From 794cc547b72397f1c75ae9a0029eb2dc371635e3 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Tue, 12 May 2020 10:43:22 -0700 Subject: [PATCH] Add specializations for cx::vector and cx::array on bool type --- include/rexy/cx/array.hpp | 97 ++++++ .../rexy/cx/detail/bool_specialize_base.hpp | 278 ++++++++++++++++++ include/rexy/cx/vector.hpp | 265 +++++++++++++++-- src/ensure.cpp | 2 + 4 files changed, 622 insertions(+), 20 deletions(-) create mode 100644 include/rexy/cx/detail/bool_specialize_base.hpp diff --git a/include/rexy/cx/array.hpp b/include/rexy/cx/array.hpp index f8662c4..1972c5a 100644 --- a/include/rexy/cx/array.hpp +++ b/include/rexy/cx/array.hpp @@ -21,6 +21,7 @@ #include //size_t #include "utility.hpp" //swap +#include "detail/bool_specialize_base.hpp" #include @@ -124,6 +125,102 @@ namespace rexy::cx{ } }; + template + class array : public detail::bool_specialize_base + { + public: + using value_type = bool; + using size_type = bool_specialize_base::size_type; + using difference_type = bool_specialize_base::difference_type; + using reference = boolean; + using const_reference = bool; + using iterator = bool_iter; + using const_iterator = const_bool_iter; + + static constexpr size_type max_elements = N; + + private: + static constexpr size_type arr_size = (N / bits_per_byte) + (N % bits_per_byte == 0 ? 0 : 1); + booleans m_elements[arr_size] = {}; + + public: + constexpr reference at(size_type pos)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr const_reference at(size_type pos)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr reference operator[](size_type pos)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr const_reference operator[](size_type pos)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr reference front(void)noexcept{ + return m_elements[0][0]; + } + constexpr const_reference front(void)const noexcept{ + return m_elements[0][0]; + } + constexpr reference back(void)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(max_elements); + return m_elements[byte_count][bits_count]; + } + constexpr const_reference back(void)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(max_elements); + return m_elements[byte_count][bits_count]; + } + + constexpr iterator begin(void)noexcept{ + return bool_iter{m_elements[0].data(), 0}; + } + constexpr const_iterator begin(void)const noexcept{ + return const_bool_iter{m_elements[0].data(), 0}; + } + constexpr const_iterator cbegin(void)const noexcept{ + return const_bool_iter{m_elements[0].data(), 0}; + } + constexpr iterator end(void)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(max_elements); + return bool_iter{m_elements[byte_count].data(), bits_count}; + } + constexpr const_iterator end(void)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(max_elements); + return const_bool_iter{m_elements[byte_count].data(), bits_count}; + } + constexpr const_iterator cend(void)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(max_elements); + return const_bool_iter{m_elements[byte_count].data(), bits_count}; + } + constexpr bool empty(void)const noexcept{ + if constexpr(max_elements == 0){ + return true; + }else{ + return false; + } + } + constexpr size_type size(void)const noexcept{ + return max_elements; + } + constexpr size_type max_size(void)const noexcept{ + return max_elements; + } + constexpr void fill(const value_type& value)noexcept{ + for(auto it = begin();it != end();++it){ + *it = value; + } + } + constexpr void swap(array& other)noexcept{ + for(size_type i = 0;i < arr_size;++i){ + cx::swap(m_elements[i], other.m_elements[i]); + } + } + }; + template array(T, Us...) -> array; diff --git a/include/rexy/cx/detail/bool_specialize_base.hpp b/include/rexy/cx/detail/bool_specialize_base.hpp new file mode 100644 index 0000000..2cdb4ef --- /dev/null +++ b/include/rexy/cx/detail/bool_specialize_base.hpp @@ -0,0 +1,278 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2020 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_BOOL_SPECIALIZE_BASE_HPP +#define REXY_BOOL_SPECIALIZE_BASE_HPP + +#include //size_t +#include //move, forward, pair +#include //CHAR_BIT +#include "../utility.hpp" //swap + + +namespace rexy::cx::detail{ + class bool_specialize_base + { + protected: + using size_type = size_t; + using difference_type = ptrdiff_t; + static constexpr size_type bits_per_byte = CHAR_BIT; + + static constexpr std::pair convert_to_byte_bit_pair(size_type s){ + return {s / bits_per_byte, s % bits_per_byte}; + } + public: + struct boolean + { + private: + using uchar = unsigned char; + uchar* m_value; + size_type m_offset; + + public: + constexpr boolean(uchar& val, size_type offset)noexcept: + m_value(&val), + m_offset(offset){} + constexpr boolean(const boolean&)noexcept = default; + constexpr boolean(boolean&&)noexcept = default; + ~boolean(void)noexcept = default; + + constexpr boolean& operator=(const boolean& b)noexcept{ + return *this = static_cast(b); + } + constexpr boolean& operator=(boolean&& b)noexcept{ + return *this = static_cast(b); + } + constexpr boolean& operator=(bool b)noexcept{ + (*m_value) = ((*m_value) & ~static_cast(uchar{1} << m_offset)) | static_cast(uchar{b} << m_offset); + return *this; + } + constexpr operator bool(void)const noexcept{ + return (*m_value) & static_cast(uchar{1} << m_offset); + } + }; + struct const_bool_iter; + struct bool_iter + { + friend class const_bool_iter; + private: + using uchar = unsigned char; + uchar* m_value; + size_type m_offset; + + public: + constexpr bool_iter(uchar& val, size_type offset)noexcept: + m_value(&val), + m_offset(offset){} + constexpr bool_iter(const bool_iter&)noexcept = default; + constexpr bool_iter(bool_iter&&)noexcept = default; + ~bool_iter(void)noexcept = default; + + constexpr bool_iter& operator=(const bool_iter&)noexcept = default; + constexpr bool_iter& operator=(bool_iter&&)noexcept = default; + + constexpr boolean operator*(void)const noexcept{ + return boolean(*m_value, m_offset); + } + constexpr bool_iter& operator++(void)noexcept{ + if(m_offset < (bits_per_byte-1)){ + ++m_offset; + }else{ + m_offset = 0; + ++m_value; + } + return *this; + } + constexpr bool_iter& operator--(void)noexcept{ + if(m_offset > 0){ + --m_offset; + }else{ + m_offset = (bits_per_byte-1); + --m_value; + } + return *this; + } + constexpr difference_type operator-(const bool_iter& other)const noexcept{ + return (m_value - other.m_value) * bits_per_byte + (m_offset - other.m_offset); + } + constexpr bool_iter operator-(difference_type d)const noexcept{ + bool_iter ret = *this; + return ret -= d; + } + constexpr bool_iter operator+(difference_type d)const noexcept{ + bool_iter ret = *this; + return ret += d; + } + constexpr bool_iter& operator+=(difference_type d)noexcept{ + if(d >= 0){ + while(d--){ + ++(*this); + } + }else{ + while(d++){ + --(*this); + } + } + return *this; + } + constexpr bool_iter& operator-=(difference_type d)noexcept{ + return (*this) += -d; + } + constexpr bool operator<(const bool_iter& other)const noexcept{ + return (m_value < other.m_value) || (m_offset < other.m_offset); + } + constexpr bool operator>(const bool_iter& other)const noexcept{ + return (m_value > other.m_value) || (m_offset > other.m_offset); + } + constexpr bool operator<=(const bool_iter& other)const noexcept{ + return (m_value <= other.m_value) || (m_offset <= other.m_offset); + } + constexpr bool operator>=(const bool_iter& other)const noexcept{ + return (m_value >= other.m_value) || (m_offset >= other.m_offset); + } + constexpr bool operator==(const bool_iter& other)const noexcept{ + return m_value == other.m_value && m_offset == other.m_offset; + } + constexpr bool operator!=(const bool_iter& other)const noexcept{ + return !(*this == other); + } + }; + struct const_bool_iter + { + friend class bool_iter; + private: + using uchar = unsigned char; + const uchar* m_value; + size_type m_offset; + + public: + constexpr const_bool_iter(const uchar& val, size_type offset)noexcept: + m_value(&val), + m_offset(offset){} + constexpr const_bool_iter(const bool_iter& b)noexcept: + m_value(b.m_value), + m_offset(b.m_offset){} + constexpr const_bool_iter(const const_bool_iter&)noexcept = default; + constexpr const_bool_iter(const_bool_iter&&)noexcept = default; + ~const_bool_iter(void)noexcept = default; + + constexpr const_bool_iter& operator=(const const_bool_iter&)noexcept = default; + constexpr const_bool_iter& operator=(const_bool_iter&&)noexcept = default; + + constexpr boolean operator*(void)const noexcept{ + return boolean(const_cast(*m_value), m_offset); + } + constexpr const_bool_iter& operator++(void)noexcept{ + if(m_offset < (bits_per_byte-1)){ + ++m_offset; + }else{ + m_offset = 0; + ++m_value; + } + return *this; + } + constexpr const_bool_iter& operator--(void)noexcept{ + if(m_offset > 0){ + --m_offset; + }else{ + m_offset = (bits_per_byte-1); + --m_value; + } + return *this; + } + constexpr difference_type operator-(const const_bool_iter& other)const noexcept{ + return (m_value - other.m_value) * bits_per_byte + (m_offset - other.m_offset); + } + constexpr const_bool_iter operator-(difference_type d)const noexcept{ + const_bool_iter ret = *this; + return ret -= d; + } + constexpr const_bool_iter operator+(difference_type d)const noexcept{ + const_bool_iter ret = *this; + return ret += d; + } + constexpr const_bool_iter& operator+=(difference_type d)noexcept{ + if(d >= 0){ + while(d--){ + ++(*this); + } + }else{ + while(d++){ + --(*this); + } + } + return *this; + } + constexpr const_bool_iter& operator-=(difference_type d)noexcept{ + return (*this) += -d; + } + constexpr bool operator<(const const_bool_iter& other)const noexcept{ + return (m_value < other.m_value) || (m_offset < other.m_offset); + } + constexpr bool operator>(const const_bool_iter& other)const noexcept{ + return (m_value > other.m_value) || (m_offset > other.m_offset); + } + constexpr bool operator<=(const const_bool_iter& other)const noexcept{ + return (m_value <= other.m_value) || (m_offset <= other.m_offset); + } + constexpr bool operator>=(const const_bool_iter& other)const noexcept{ + return (m_value >= other.m_value) || (m_offset >= other.m_offset); + } + constexpr bool operator==(const const_bool_iter& other)const noexcept{ + return m_value == other.m_value && m_offset == other.m_offset; + } + constexpr bool operator!=(const const_bool_iter& other)const noexcept{ + return !(*this == other); + } + + }; + + private: + struct booleans + { + private: + using uchar = unsigned char; + uchar m_value = 0; + + public: + constexpr booleans(void)noexcept = default; + constexpr booleans(const booleans&)noexcept = default; + constexpr booleans(booleans&&)noexcept = default; + ~booleans(void)noexcept = default; + + constexpr booleans& operator=(const booleans&)noexcept = default; + constexpr booleans& operator=(booleans&&)noexcept = default; + + constexpr boolean operator[](size_t i){ + return boolean{m_value, i}; + } + constexpr boolean operator[](size_t i)const{ + return boolean{const_cast(m_value), i}; + } + constexpr uchar& data(void){ + return m_value; + } + constexpr const uchar& data(void)const{ + return m_value; + } + }; + + }; +} + +#endif diff --git a/include/rexy/cx/vector.hpp b/include/rexy/cx/vector.hpp index 71d760e..481b020 100644 --- a/include/rexy/cx/vector.hpp +++ b/include/rexy/cx/vector.hpp @@ -22,6 +22,7 @@ #include //size_t #include //move, forward +#include "detail/bool_specialize_base.hpp" #include "utility.hpp" //swap #include @@ -45,7 +46,7 @@ namespace rexy::cx{ static constexpr size_type max_elements = N; private: - T m_elements[N] = {}; + value_type m_elements[N] = {}; size_type m_size = 0; public: @@ -59,6 +60,7 @@ namespace rexy::cx{ for(size_type i = 0;i < min(count, max_elements);++i){ m_elements[i] = value; } + m_size = cx::min(count, max_elements); } ~vector(void)noexcept = default; @@ -132,11 +134,14 @@ namespace rexy::cx{ std::is_nothrow_copy_assignable::value) { auto start = pos; - auto it = pos; - ++pos; - for(;pos != end();++it,++pos){ - *pos = std::move(*it); + if(start != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } } + ++m_size; *start = value; return start; } @@ -144,13 +149,16 @@ namespace rexy::cx{ noexcept(std::is_nothrow_move_assignable::value) { auto start = pos; - auto it = pos; - ++pos; - for(;pos != end();++it,++pos){ - *pos = std::move(*it); + if(start != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } } + ++m_size; *start = std::move(value); - return start; + return begin() + (pos - start); } template constexpr iterator emplace(const_iterator pos, Args&&... args) @@ -158,24 +166,30 @@ namespace rexy::cx{ std::is_nothrow_constructible::value) { auto start = pos; - auto it = pos; - ++pos; - for(;pos != end();++it,++pos){ - *pos = std::move(*it); + if(start != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } } + ++m_size; *start = T{std::forward(args)...}; - return start; + return begin() + (start - pos); } constexpr iterator erase(const_iterator pos) noexcept(std::is_nothrow_move_assignable::value) { auto start = pos; - auto it = pos; - ++pos; - for(;pos != end();++it,++pos){ - *it = std::move(*pos); + if(start != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *it = std::move(*pos); + } } - return start; + --m_size; + return begin() + (end() - start); } constexpr iterator push_back(const T& value) noexcept(std::is_nothrow_copy_assignable::value) @@ -227,7 +241,218 @@ namespace rexy::cx{ } cx::swap(m_size, other.m_size); } + }; + template + class vector : public detail::bool_specialize_base + { + public: + using value_type = bool; + using size_type = bool_specialize_base::size_type; + using difference_type = bool_specialize_base::difference_type; + using iterator = bool_iter; + using const_iterator = const_bool_iter; + using reference = boolean; + using const_reference = bool; + + static constexpr size_type max_elements = N; + + private: + static constexpr size_type arr_size = (N / bits_per_byte) + (N % bits_per_byte == 0 ? 0 : 1); + size_type m_size = 0; + booleans m_elements[arr_size] = {}; + + + public: + constexpr vector(void)noexcept = default; + constexpr vector(const vector&)noexcept = default; + constexpr vector(vector&&)noexcept = default; + + constexpr vector(size_type count, const value_type& value)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(count); + + size_type i = 0; + for(;i < byte_count;++i){ + for(size_type j = 0;i < bits_per_byte;++i){ + m_elements[i][j] = value; + } + } + for(size_type j = 0;j < bits_count;++j){ + m_elements[i][j] = value; + } + m_size = cx::min(count, max_elements); + } + + ~vector(void)noexcept = default; + + constexpr vector& operator=(const vector&)noexcept = default; + constexpr vector& operator=(vector&&)noexcept = default; + + constexpr reference at(size_type pos)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr const_reference at(size_type pos)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr reference operator[](size_type pos)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr const_reference operator[](size_type pos)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(pos); + return m_elements[byte_count][bits_count]; + } + constexpr reference front(void)noexcept{ + return m_elements[0][0]; + } + constexpr const_reference front(void)const noexcept{ + return m_elements[0][0]; + } + constexpr reference back(void)noexcept{ + if(!m_size) + return m_elements[0][0]; + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + if(bits_count == 0){ + bits_count = bits_per_byte-1; + byte_count -= 1; + } + return m_elements[byte_count][bits_count]; + } + constexpr const_reference back(void)const noexcept{ + if(!m_size) + return m_elements[0][0]; + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + if(bits_count == 0){ + bits_count = bits_per_byte-1; + byte_count -= 1; + } + return m_elements[byte_count][bits_count]; + } + constexpr iterator begin(void)noexcept{ + return bool_iter{m_elements[0].data(), 0}; + } + constexpr const_iterator begin(void)const noexcept{ + return const_bool_iter{m_elements[0].data(), 0}; + } + constexpr const_iterator cbegin(void)const noexcept{ + return const_bool_iter{m_elements[0].data(), 0}; + } + constexpr iterator end(void)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + return bool_iter{m_elements[byte_count].data(), bits_count}; + } + constexpr const_iterator end(void)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + return const_bool_iter{m_elements[byte_count].data(), bits_count}; + } + constexpr const_iterator cend(void)const noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + return const_bool_iter{m_elements[byte_count].data(), bits_count}; + } + + constexpr bool empty(void)const noexcept{ + return m_size == 0; + } + constexpr size_type size(void)const noexcept{ + return m_size; + } + constexpr size_type max_size(void)const noexcept{ + return max_elements; + } + constexpr size_type capacity(void)const noexcept{ + return max_elements; + } + constexpr void clear(void)noexcept{ + m_size = 0; + } + constexpr iterator insert(const_iterator pos, const value_type& value)noexcept{ + auto start = pos; + if(pos != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } + } + ++m_size; + *start = value; + return begin() + (pos - start); + } + template + constexpr iterator emplace(const_iterator pos, Args&&... args)noexcept{ + auto start = pos; + if(pos != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } + } + ++m_size; + *start = bool{std::forward(args)...}; + return begin() + (pos - start); + } + constexpr iterator erase(const_iterator pos)noexcept{ + auto start = pos; + if(pos != end()){ + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *it = std::move(*pos); + } + } + --m_size; + return begin() + (end() - start); + } + constexpr iterator push_back(const value_type& value)noexcept{ + return insert(end(), value); + } + template + constexpr iterator emplace_back(Args&&... args)noexcept{ + return emplace(end(), std::forward(args)...); + } + constexpr void pop_back(void)noexcept{ + --m_size; + } + constexpr void resize(size_type count)noexcept{ + if(count <= max_size()) + m_size = count; + } + constexpr void resize(size_type count, const value_type& value)noexcept{ + if(count > m_size){ + auto actual_count = cx::min(count, max_size()); + auto num = actual_count - m_size; + auto it = end(); + for(size_type i = 0;i < num;++i){ + *it = value; + ++it; + } + } + m_size = count; + } + constexpr void fill(const bool& value)noexcept{ + for(auto it = begin();it != end();++it){ + *it = value; + } + } + constexpr void swap(vector& other)noexcept{ + auto [byte_count,bits_count] = convert_to_byte_bit_pair(m_size); + auto [other_byte_count,other_bits_count] = convert_to_byte_bit_pair(other.m_size); + if(bits_count) + ++byte_count; + if(other_bits_count) + ++other_byte_count; + size_type i = 0; + for(;i < byte_count;++i){ + cx::swap(m_elements[i], other.m_elements[i]); + } + for(;i < other_byte_count;++i){ + cx::swap(m_elements[i], other.m_elements[i]); + } + cx::swap(m_size, other.m_size); + } }; } diff --git a/src/ensure.cpp b/src/ensure.cpp index 36dc127..fd8a394 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -22,3 +22,5 @@ #include "rexy/cx/string.hpp" #include "rexy/cx/utility.hpp" #include "rexy/cx/vector.hpp" + +#include "rexy/cx/detail/bool_specialize_base.hpp"