├── LICENSE.md ├── README.md ├── cpp ├── bit.cpp ├── bit.hpp ├── bit_algorithm.hpp ├── bit_details.hpp ├── bit_iterator.hpp ├── bit_pointer.hpp ├── bit_reference.hpp ├── bit_value.hpp └── linear_overload.hpp └── doc ├── media ├── architecture.pdf ├── architecture.svg ├── bit_log.pdf ├── bit_log.png ├── bit_log_article.pdf ├── bit_log_article.png ├── bit_nolog.pdf ├── bit_nolog.png ├── bit_nolog_article.pdf ├── bit_nolog_article.png ├── bitwise_operators.pdf ├── bitwise_operators.svg ├── fundamental_operations.pdf ├── integral_types.pdf └── integral_types.svg └── wg21 ├── 2016_02_jacksonville └── p0237r0.pdf ├── 2016_06_oulu ├── d0237r1.html ├── p0237r1.html └── p0237r2.html ├── 2016_11_issaquah ├── p0237r3.html └── p0237r4.html ├── 2017_02_kona ├── p0237r5.html └── p0237r6.html └── 2017_07_toronto ├── d0237r7.pdf ├── d0237r8.pdf ├── p0237r7.pdf └── p0237r8.pdf /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Vincent Reverdy, University of Illinois at Urbana-Champaign 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of The Bit Library nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Bit Library 2 | 3 | ## Introduction 4 | The Bit Library (TBL) is a multi-language library providing efficient bit abstractions and efficient bit manipulation algorithms. Currently, the library is focusing on the C++ version development and is aiming at standardization. 5 | 6 | ## Files 7 | * ``cpp``: C++ version of the library 8 | * ``cpp/bit_details.hpp``: Provides common implementation details and helper classes 9 | * ``cpp/bit_value.hpp``: A class representing an independent, non-referenced bit 10 | * ``cpp/bit_reference.hpp``: A class representing a reference to a bit 11 | * ``cpp/bit_pointer.hpp``: A class representing a pointer to a bit 12 | * ``cpp/bit_iterator.hpp``: A class representing an iterator on bit sequences 13 | * ``cpp/bit_algorithm.hpp``: Optimized versions of algorithms for bit manipulation 14 | * ``cpp/bit.hpp``: Includes the whole C++ bit library 15 | * ``cpp/bit.cpp``: Example use of the C++ bit library (old version, needs to be updated) 16 | * ``wg21``: ISO WG21 C++ proposal for standardization 17 | 18 | ## Documentation and resources 19 | 20 | ### CppCon 2016 presentation 21 | 22 | [![cppcon2016_presentation](https://img.youtube.com/vi/PA7oFnarcXQ/hqdefault.jpg)](https://www.youtube.com/watch?v=PA7oFnarcXQ) 23 | 24 | -------------------------------------------------------------------------------- /cpp/bit.cpp: -------------------------------------------------------------------------------- 1 | // ================================== BIT =================================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit.cpp 4 | // Description: Illustrates the use of the bit library 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | // Compilation: 10 | // g++ -std=c++14 -Wall -Wextra -pedantic -g -O3 bit.cpp -o bit -mpopcnt 11 | // Execution 12 | // ./bit 64000000 13 | // ========================================================================== // 14 | 15 | 16 | 17 | // ================================ PREAMBLE ================================ // 18 | // C++ standard library 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | // Project sources 25 | #include "bit.hpp" 26 | // Third-party libraries 27 | // Miscellaneous 28 | using namespace bit; 29 | // ========================================================================== // 30 | 31 | 32 | 33 | // ================================== BODY ================================== // 34 | // Display algorithm 35 | template 36 | void display(O&& os, bit_iterator first, bit_iterator last) 37 | { 38 | auto mem = first; 39 | for (auto it = first; it != last; ++it) { 40 | if (it.base() != mem.base()) { 41 | os << " "; 42 | } 43 | std::forward(os) << *it; 44 | mem = it; 45 | } 46 | std::forward(os) << std::endl; 47 | } 48 | 49 | // Make random vector 50 | template 51 | std::vector make_random_vector( 52 | std::size_t size, 53 | T min = std::numeric_limits::min(), 54 | T max = std::numeric_limits::max(), 55 | const T& seed = T() 56 | ) 57 | { 58 | std::vector v(size); 59 | std::random_device device; 60 | std::mt19937 engine(seed == T() ? device() : seed); 61 | std::uniform_int_distribution distribution(min, max); 62 | for (std::size_t i = 0; i < size; ++i) { 63 | v[i] = distribution(engine); 64 | } 65 | return v; 66 | } 67 | 68 | // Benchmark the function on the vector 69 | template 70 | double benchmark(std::vector v, F&& f, R&& result) 71 | { 72 | typename std::chrono::high_resolution_clock::time_point tbegin; 73 | typename std::chrono::high_resolution_clock::time_point tend; 74 | std::chrono::duration duration; 75 | volatile std::uintmax_t tmp = 0; 76 | tbegin = std::chrono::high_resolution_clock::now(); 77 | std::forward(f)(std::begin(v), std::end(v)); 78 | tend = std::chrono::high_resolution_clock::now(); 79 | result = std::accumulate(std::begin(v), std::end(v), T{}); 80 | tmp = std::forward(result) + tmp; 81 | duration = tend - tbegin; 82 | return duration.count(); 83 | } 84 | 85 | // Main function 86 | int main(int argc, char* argv[]) 87 | { 88 | // Initialization 89 | using uint_t = unsigned long long int; 90 | constexpr std::size_t byte = std::numeric_limits::digits; 91 | constexpr std::size_t digits = sizeof(uint_t) * byte; 92 | const std::size_t n = argc > 1 ? std::stoull(argv[1]) : (1 << 22); 93 | auto v = make_random_vector(n); 94 | auto vb = make_random_vector(n * digits, 0, 1); 95 | std::uintmax_t k = 0; 96 | 97 | // Functions 98 | auto f0 = [=](auto first, auto last){ 99 | auto bfirst = bit_iterator(first); 100 | auto blast = bit_iterator(last); 101 | reverse(bfirst, blast); 102 | }; 103 | auto f1 = [=](auto first, auto last){ 104 | for (auto it = first; it != last; ++it) { 105 | auto bfirst = bit_iterator(it); 106 | auto blast = bit_iterator(it + 1); 107 | reverse(bfirst, blast); 108 | } 109 | }; 110 | auto f2 = [=](auto first, auto last){ 111 | for (auto it = first; it != last; ++it) { 112 | *it = _bitswap(*it); 113 | } 114 | }; 115 | auto f3 = [=](auto first, auto last){ 116 | for (auto it = first; it != last; ++it) { 117 | auto bfirst = bit_iterator(it) + 7; 118 | auto blast = bit_iterator(it + 1); 119 | reverse(bfirst, blast); 120 | } 121 | }; 122 | auto f4 = [=](auto first, auto last){ 123 | for (auto it = first; it != last; ++it) { 124 | auto bfirst = bit_iterator(it) + 7; 125 | auto blast = bit_iterator(it + 1) - 13; 126 | reverse(bfirst, blast); 127 | } 128 | }; 129 | auto f5 = [=](auto first, auto last){ 130 | for (auto it = first; it != last; ++it) { 131 | auto bfirst = bit_iterator(it); 132 | auto blast = bit_iterator(it + 1) - 13; 133 | reverse(bfirst, blast); 134 | } 135 | }; 136 | auto f6 = [=](auto first, auto last){ 137 | std::reverse(first, last); 138 | }; 139 | 140 | // Benchmark 141 | std::cout<<"f0 = "<(k); 158 | } 159 | // ========================================================================== // 160 | -------------------------------------------------------------------------------- /cpp/bit.hpp: -------------------------------------------------------------------------------- 1 | // ================================== BIT =================================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit.hpp 4 | // Description: Includes the whole C++ bit library 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_HPP_INCLUDED 10 | #define _BIT_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_details.hpp" 19 | #include "bit_value.hpp" 20 | #include "bit_reference.hpp" 21 | #include "bit_pointer.hpp" 22 | #include "bit_iterator.hpp" 23 | #include "bit_algorithm.hpp" 24 | // Third-party libraries 25 | // Miscellaneous 26 | // ========================================================================== // 27 | 28 | 29 | 30 | // ========================================================================== // 31 | #endif // _BIT_HPP_INCLUDED 32 | // ========================================================================== // 33 | -------------------------------------------------------------------------------- /cpp/bit_algorithm.hpp: -------------------------------------------------------------------------------- 1 | // ============================= BIT ALGORITHM ============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_algorithm.hpp 4 | // Description: Optimized versions of algorithms for bit manipulation 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // Maghav Kumar [2016-2017] 8 | // License: BSD 3-Clause License 9 | // ========================================================================== // 10 | #ifndef _BIT_ALGORITHM_HPP_INCLUDED 11 | #define _BIT_ALGORITHM_HPP_INCLUDED 12 | // ========================================================================== // 13 | 14 | 15 | 16 | // ================================ PREAMBLE ================================ // 17 | // C++ standard library 18 | // Project sources 19 | #include "bit_details.hpp" 20 | #include "bit_value.hpp" 21 | #include "bit_reference.hpp" 22 | #include "bit_pointer.hpp" 23 | #include "bit_iterator.hpp" 24 | // Third-party libraries 25 | // Miscellaneous 26 | namespace bit { 27 | // ========================================================================== // 28 | 29 | 30 | 31 | /* ************************** STANDARD ALGORITHMS *************************** */ 32 | // Non-modifying sequence operations 33 | template 34 | typename bit_iterator::difference_type 35 | count( 36 | bit_iterator first, 37 | bit_iterator last, 38 | bit_value value 39 | ); 40 | 41 | // Modifying sequence operations 42 | template 43 | void reverse( 44 | bit_iterator first, 45 | bit_iterator last 46 | ); 47 | /* ************************************************************************** */ 48 | 49 | 50 | 51 | // ------------------- NON-MODIFYING SEQUENCE OPERATIONS -------------------- // 52 | // Counts the number of bits equal to the provided bit value 53 | template 54 | typename bit_iterator::difference_type 55 | count( 56 | bit_iterator first, 57 | bit_iterator last, 58 | bit_value value 59 | ) 60 | { 61 | // Assertions 62 | _assert_range_viability(first, last); 63 | 64 | // Types and constants 65 | using word_type = typename bit_iterator::word_type; 66 | using difference_type = typename bit_iterator::difference_type; 67 | constexpr difference_type digits = binary_digits::value; 68 | 69 | // Initialization 70 | difference_type result = 0; 71 | auto it = first.base(); 72 | word_type first_value = {}; 73 | word_type last_value = {}; 74 | 75 | // Computation when bits belong to several underlying words 76 | if (first.base() != last.base()) { 77 | if (first.position() != 0) { 78 | first_value = *first.base() >> first.position(); 79 | result = _popcnt(first_value); 80 | ++it; 81 | } 82 | for (; it != last.base(); ++it) { 83 | result += _popcnt(*it); 84 | } 85 | if (last.position() != 0) { 86 | last_value = *last.base() << (digits - last.position()); 87 | result += _popcnt(last_value); 88 | } 89 | // Computation when bits belong to the same underlying word 90 | } else { 91 | result = _popcnt(_bextr( 92 | *first.base(), 93 | first.position(), 94 | last.position() - first.position() 95 | )); 96 | } 97 | 98 | // Negates when the number of zero bits is requested 99 | if (!static_cast(value)) { 100 | result = std::distance(first, last) - result; 101 | } 102 | 103 | // Finalization 104 | return result; 105 | } 106 | // -------------------------------------------------------------------------- // 107 | 108 | 109 | 110 | // --------------------- MODIFYING SEQUENCE OPERATIONS ---------------------- // 111 | // Reverses the order of the bits in the provided range 112 | template 113 | void reverse( 114 | bit_iterator first, 115 | bit_iterator last 116 | ) 117 | { 118 | // Assertions 119 | _assert_range_viability(first, last); 120 | 121 | // Types and constants 122 | using word_type = typename bit_iterator::word_type; 123 | using size_type = typename bit_iterator::size_type; 124 | constexpr size_type digits = binary_digits::value; 125 | 126 | // Initialization 127 | const bool is_first_aligned = first.position() == 0; 128 | const bool is_last_aligned = last.position() == 0; 129 | size_type gap = (digits - last.position()) * !is_last_aligned; 130 | auto it = first.base(); 131 | word_type first_value = {}; 132 | word_type last_value = {}; 133 | 134 | // Reverse when bit iterators are aligned 135 | if (is_first_aligned && is_last_aligned) { 136 | std::reverse(first.base(), last.base()); 137 | for (; it != last.base(); ++it) { 138 | *it = _bitswap(*it); 139 | } 140 | // Reverse when bit iterators do not belong to the same underlying word 141 | } else if (first.base() != last.base()) { 142 | // Save first and last element 143 | first_value = *first.base(); 144 | last_value = *std::prev(last.base(), is_last_aligned); 145 | // Reverse the underlying sequence 146 | std::reverse(first.base(), std::next(last.base(), !is_last_aligned)); 147 | // Shift the underlying sequence to the left 148 | if (first.position() < gap) { 149 | it = first.base(); 150 | gap = gap - first.position(); 151 | for (; it != last.base(); ++it) { 152 | *it = _shld(*it, *std::next(it), gap); 153 | } 154 | *it <<= gap; 155 | it = first.base(); 156 | // Shift the underlying sequence to the right 157 | } else if (first.position() > gap) { 158 | it = std::prev(last.base(), is_last_aligned); 159 | gap = first.position() - gap; 160 | for (; it != first.base(); --it) { 161 | *it = _shrd(*it, *std::prev(it), gap); 162 | } 163 | *it >>= gap; 164 | it = first.base(); 165 | } 166 | // Bitswap every element of the underlying sequence 167 | for (; it != std::next(last.base(), !is_last_aligned); ++it) { 168 | *it = _bitswap(*it); 169 | } 170 | // Blend bits of the first element 171 | if (!is_first_aligned) { 172 | *first.base() = _bitblend( 173 | first_value, 174 | *first.base(), 175 | first.position(), 176 | digits - first.position() 177 | ); 178 | } 179 | // Blend bits of the last element 180 | if (!is_last_aligned) { 181 | *last.base() = _bitblend( 182 | *last.base(), 183 | last_value, 184 | last.position(), 185 | digits - last.position() 186 | ); 187 | } 188 | // Reverse when bit iterators belong to the same underlying word 189 | } else { 190 | *it = _bitblend( 191 | *it, 192 | _bitswap(*it >> first.position()) >> gap, 193 | first.position(), 194 | last.position() - first.position() 195 | ); 196 | } 197 | } 198 | // -------------------------------------------------------------------------- // 199 | 200 | 201 | 202 | // ========================================================================== // 203 | } // namespace bit 204 | #endif // _BIT_ALGORITHM_HPP_INCLUDED 205 | // ========================================================================== // 206 | -------------------------------------------------------------------------------- /cpp/bit_details.hpp: -------------------------------------------------------------------------------- 1 | // ============================== BIT DETAILS =============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_details.hpp 4 | // Description: Provides common implementation details and helper classes 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_DETAILS_HPP_INCLUDED 10 | #define _BIT_DETAILS_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | // Project sources 27 | // Third-party libraries 28 | // Miscellaneous 29 | namespace bit { 30 | class bit_value; 31 | template class bit_reference; 32 | template class bit_pointer; 33 | template class bit_iterator; 34 | // ========================================================================== // 35 | 36 | 37 | 38 | /* ***************************** BINARY DIGITS ****************************** */ 39 | // Binary digits structure definition 40 | template 41 | struct binary_digits 42 | : std::conditional< 43 | std::is_const::value || std::is_volatile::value, 44 | binary_digits::type>, 45 | std::integral_constant::digits> 46 | >::type 47 | { 48 | // Assertions 49 | static_assert(std::is_integral::value, ""); 50 | static_assert(std::is_unsigned::value, ""); 51 | static_assert(!std::is_same::value, ""); 52 | static_assert(!std::is_same::value, ""); 53 | }; 54 | 55 | // Binary digits value 56 | template 57 | constexpr std::size_t binary_digits_v = binary_digits::value; 58 | /* ************************************************************************** */ 59 | 60 | 61 | 62 | /* *************** IMPLEMENTATION DETAILS: CV ITERATOR TRAITS *************** */ 63 | // Cv iterator traits structure definition 64 | template 65 | struct _cv_iterator_traits 66 | { 67 | // Assertions 68 | private: 69 | using _traits_t = std::iterator_traits; 70 | using _difference_t = typename _traits_t::difference_type; 71 | using _value_t = typename _traits_t::value_type; 72 | using _pointer_t = typename _traits_t::pointer; 73 | using _reference_t = typename _traits_t::reference; 74 | using _category_t = typename _traits_t::iterator_category; 75 | using _no_pointer_t = typename std::remove_pointer<_pointer_t>::type; 76 | using _no_reference_t = typename std::remove_reference<_reference_t>::type; 77 | using _raw_value_t = typename std::remove_cv<_value_t>::type; 78 | using _raw_pointer_t = typename std::remove_cv<_no_pointer_t>::type; 79 | using _raw_reference_t = typename std::remove_cv<_no_reference_t>::type; 80 | using _cv_value_t = _no_reference_t; 81 | static_assert(std::is_same<_raw_pointer_t, _raw_value_t>::value, ""); 82 | static_assert(std::is_same<_raw_reference_t, _raw_value_t>::value, ""); 83 | 84 | // Types 85 | public: 86 | using difference_type = _difference_t; 87 | using value_type = _cv_value_t; 88 | using pointer = _pointer_t; 89 | using reference = _reference_t; 90 | using iterator_category = _category_t; 91 | }; 92 | /* ************************************************************************** */ 93 | 94 | 95 | 96 | /* *********** IMPLEMENTATION DETAILS: NARROWEST AND WIDEST TYPES *********** */ 97 | // Narrowest type structure declaration 98 | template 99 | struct _narrowest_type; 100 | 101 | // Narrowest type structure specialization: selects the only passed type 102 | template 103 | struct _narrowest_type 104 | : std::common_type 105 | { 106 | static_assert(binary_digits::value, ""); 107 | }; 108 | 109 | // Narrowest type structure specialization: selects the type with less bits 110 | template 111 | struct _narrowest_type 112 | : _narrowest_type< 113 | typename std::conditional< 114 | (binary_digits::value < binary_digits::value), 115 | T, 116 | typename std::conditional< 117 | (binary_digits::value > binary_digits::value), 118 | U, 119 | typename std::common_type::type 120 | >::type 121 | >::type 122 | > 123 | { 124 | }; 125 | 126 | // Narrowest type structure specialization: recursively selects the right type 127 | template 128 | struct _narrowest_type 129 | : _narrowest_type::type> 130 | { 131 | }; 132 | 133 | // Narrowest type alias 134 | template 135 | using _narrowest_type_t = typename _narrowest_type::type; 136 | 137 | // Widest type structure declaration 138 | template 139 | struct _widest_type; 140 | 141 | // Widest type structure specialization: selects the only passed type 142 | template 143 | struct _widest_type 144 | : std::common_type 145 | { 146 | static_assert(binary_digits::value, ""); 147 | }; 148 | 149 | // Widest type structure specialization: selects the type with more bits 150 | template 151 | struct _widest_type 152 | : _widest_type< 153 | typename std::conditional< 154 | (binary_digits::value > binary_digits::value), 155 | T, 156 | typename std::conditional< 157 | (binary_digits::value < binary_digits::value), 158 | U, 159 | typename std::common_type::type 160 | >::type 161 | >::type 162 | > 163 | { 164 | }; 165 | 166 | // Widest type structure specialization: recursively selects the right type 167 | template 168 | struct _widest_type 169 | : _widest_type::type> 170 | { 171 | }; 172 | 173 | // Widest type alias 174 | template 175 | using _widest_type_t = typename _widest_type::type; 176 | /* ************************************************************************** */ 177 | 178 | 179 | 180 | /* ************ IMPLEMENTATION DETAILS: NARROWER AND WIDER TYPES ************ */ 181 | // Narrower type structure definition 182 | template 183 | struct _narrower_type 184 | { 185 | using tuple = std::tuple< 186 | unsigned long long int, 187 | unsigned long int, 188 | unsigned int, 189 | unsigned short int, 190 | unsigned char 191 | >; 192 | using lhs_bits = binary_digits; 193 | using rhs_bits = binary_digits::type>; 194 | using type = typename std::conditional< 195 | (lhs_bits::value > rhs_bits::value), 196 | typename std::tuple_element::type, 197 | typename std::conditional< 198 | (I + 1 < std::tuple_size::value), 199 | typename _narrower_type< 200 | T, 201 | (I + 1 < std::tuple_size::value ? I + 1 : -1) 202 | >::type, 203 | typename std::tuple_element::type 204 | >::type 205 | >::type; 206 | }; 207 | 208 | // Narrower type structure specialization: not found 209 | template 210 | struct _narrower_type 211 | { 212 | using type = T; 213 | }; 214 | 215 | // Narrower type alias 216 | template 217 | using _narrower_type_t = typename _narrower_type::type; 218 | 219 | // Wider type structure definition 220 | template 221 | struct _wider_type 222 | { 223 | using tuple = std::tuple< 224 | unsigned char, 225 | unsigned short int, 226 | unsigned int, 227 | unsigned long int, 228 | unsigned long long int 229 | >; 230 | using lhs_bits = binary_digits; 231 | using rhs_bits = binary_digits::type>; 232 | using type = typename std::conditional< 233 | (lhs_bits::value < rhs_bits::value), 234 | typename std::tuple_element::type, 235 | typename std::conditional< 236 | (I + 1 < std::tuple_size::value), 237 | typename _narrower_type< 238 | T, 239 | (I + 1 < std::tuple_size::value ? I + 1 : -1) 240 | >::type, 241 | typename std::tuple_element::type 242 | >::type 243 | >::type; 244 | }; 245 | 246 | // Wider type structure specialization: not found 247 | template 248 | struct _wider_type 249 | { 250 | using type = T; 251 | }; 252 | 253 | // Wider type alias 254 | template 255 | using _wider_type_t = typename _wider_type::type; 256 | /* ************************************************************************** */ 257 | 258 | 259 | 260 | /* ******************* IMPLEMENTATION DETAILS: UTILITIES ******************** */ 261 | // Assertions 262 | template 263 | constexpr bool _assert_range_viability(Iterator first, Iterator last); 264 | /* ************************************************************************** */ 265 | 266 | 267 | 268 | /* ****************** IMPLEMENTATION DETAILS: INSTRUCTIONS ****************** */ 269 | // Population count 270 | template 271 | constexpr T _popcnt(T src) noexcept; 272 | template 273 | constexpr T _popcnt(T src, X...) noexcept; 274 | 275 | // Leading zeros count 276 | template 277 | constexpr T _lzcnt(T src) noexcept; 278 | template 279 | constexpr T _lzcnt(T src, X...) noexcept; 280 | 281 | // Trailing zeros count 282 | template 283 | constexpr T _tzcnt(T src) noexcept; 284 | template 285 | constexpr T _tzcnt(T src, X...) noexcept; 286 | 287 | // Bit field extraction 288 | template 289 | constexpr T _bextr(T src, T start, T len) noexcept; 290 | template 291 | constexpr T _bextr(T src, T start, T len, X...) noexcept; 292 | 293 | // Parallel bits deposit 294 | template 295 | constexpr T _pdep(T src, T msk) noexcept; 296 | template 297 | constexpr T _pdep(T src, T msk, X...) noexcept; 298 | 299 | // Parallel bits extract 300 | template 301 | constexpr T _pext(T src, T msk) noexcept; 302 | template 303 | constexpr T _pext(T src, T msk, X...) noexcept; 304 | 305 | // Byte swap 306 | template 307 | constexpr T _byteswap(T src) noexcept; 308 | template 309 | constexpr T _byteswap(T src, X...) noexcept; 310 | 311 | // Bit swap 312 | template 313 | constexpr T _bitswap(T src) noexcept; 314 | template 315 | constexpr T _bitswap(T src) noexcept; 316 | template 317 | constexpr T _bitswap() noexcept; 318 | 319 | // Bit blend 320 | template 321 | constexpr T _bitblend(T src0, T src1, T msk) noexcept; 322 | template 323 | constexpr T _bitblend(T src0, T src1, T start, T len) noexcept; 324 | 325 | // Bit compare 326 | template 327 | constexpr T _bitcmp(T src0, T src1, T start0, T start1, T len) noexcept; 328 | 329 | // Double precision shift left 330 | template 331 | constexpr T _shld(T dst, T src, T cnt) noexcept; 332 | 333 | // Double precision shift right 334 | template 335 | constexpr T _shrd(T dst, T src, T cnt) noexcept; 336 | 337 | // Add carry 338 | template 339 | using _supports_adc = decltype(__builtin_ia32_addcarryx_u64(T()...)); 340 | template > 341 | constexpr C _addcarry(C carry, T src0, T src1, T* dst) noexcept; 342 | template 343 | constexpr C _addcarry(C carry, T src0, T src1, T* dst, X...) noexcept; 344 | 345 | // Sub borrow 346 | template 347 | using _supports_sbb = decltype(__builtin_ia32_sbb_u64(T()...)); 348 | template 349 | using _supports_sbb_alt = decltype(__builtin_ia32_subborrow_u64(T()...)); 350 | template > 351 | constexpr B _subborrow(B borrow, T src0, T src1, T* dst) noexcept; 352 | template > 353 | constexpr B _subborrow(const B& borrow, T src0, T src1, T* dst) noexcept; 354 | template 355 | constexpr B _subborrow(B borrow, T src0, T src1, T* dst, X...) noexcept; 356 | 357 | // Multiword multiply 358 | template 359 | constexpr T _mulx(T src0, T src1, T* hi) noexcept; 360 | template 361 | constexpr T _mulx(T src0, T src1, T* hi, X...) noexcept; 362 | /* ************************************************************************** */ 363 | 364 | 365 | 366 | // ------------- IMPLEMENTATION DETAILS: UTILITIES: ASSERTIONS -------------- // 367 | // If the range allows multipass iteration, checks if last - first >= 0 368 | template 369 | constexpr bool _assert_range_viability(Iterator first, Iterator last) 370 | { 371 | using traits_t = std::iterator_traits; 372 | using category_t = typename traits_t::iterator_category; 373 | using multi_t = std::forward_iterator_tag; 374 | constexpr bool is_multipass = std::is_base_of::value; 375 | const bool is_viable = !is_multipass || std::distance(first, last) >= 0; 376 | assert(is_viable); 377 | return is_viable; 378 | } 379 | // -------------------------------------------------------------------------- // 380 | 381 | 382 | 383 | // --------- IMPLEMENTATION DETAILS: INSTRUCTIONS: POPULATION COUNT --------- // 384 | // Counts the number of bits set to 1 with compiler intrinsics 385 | template 386 | constexpr T _popcnt(T src) noexcept 387 | { 388 | static_assert(binary_digits::value, ""); 389 | constexpr T digits = binary_digits::value; 390 | if (digits <= std::numeric_limits::digits) { 391 | src = __builtin_popcount(src); 392 | } else if (digits <= std::numeric_limits::digits) { 393 | src = __builtin_popcountl(src); 394 | } else if (digits <= std::numeric_limits::digits) { 395 | src = __builtin_popcountll(src); 396 | } else { 397 | src = _popcnt(src, std::ignore); 398 | } 399 | return src; 400 | } 401 | 402 | // Counts the number of bits set to 1 without compiler intrinsics 403 | template 404 | constexpr T _popcnt(T src, X...) noexcept 405 | { 406 | static_assert(binary_digits::value, ""); 407 | T dst = T(); 408 | for (dst = T(); src; src >>= 1) { 409 | dst += src & 1; 410 | } 411 | return dst; 412 | } 413 | // -------------------------------------------------------------------------- // 414 | 415 | 416 | 417 | // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: LEADING ZEROS COUNT -------- // 418 | // Counts the number of leading zeros with compiler intrinsics 419 | template 420 | constexpr T _lzcnt(T src) noexcept 421 | { 422 | static_assert(binary_digits::value, ""); 423 | constexpr T digits = binary_digits::value; 424 | T dst = T(); 425 | if (digits < std::numeric_limits::digits) { 426 | dst = src ? __builtin_clz(src) 427 | - (std::numeric_limits::digits 428 | - digits) 429 | : digits; 430 | } else if (digits == std::numeric_limits::digits) { 431 | dst = src ? __builtin_clz(src) : digits; 432 | } else if (digits < std::numeric_limits::digits) { 433 | dst = src ? __builtin_clzl(src) 434 | - (std::numeric_limits::digits 435 | - digits) 436 | : digits; 437 | } else if (digits == std::numeric_limits::digits) { 438 | dst = src ? __builtin_clzl(src) : digits; 439 | } else if (digits < std::numeric_limits::digits) { 440 | dst = src ? __builtin_clzll(src) 441 | - (std::numeric_limits::digits 442 | - digits) 443 | : digits; 444 | } else if (digits == std::numeric_limits::digits) { 445 | dst = src ? __builtin_clzll(src) : digits; 446 | } else { 447 | dst = _lzcnt(src, std::ignore); 448 | } 449 | return dst; 450 | } 451 | 452 | // Counts the number of leading zeros without compiler intrinsics 453 | template 454 | constexpr T _lzcnt(T src, X...) noexcept 455 | { 456 | static_assert(binary_digits::value, ""); 457 | constexpr T digits = binary_digits::value; 458 | T dst = src != T(); 459 | while (src >>= 1) { 460 | ++dst; 461 | } 462 | return digits - dst; 463 | } 464 | // -------------------------------------------------------------------------- // 465 | 466 | 467 | 468 | // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: TRAILING ZEROS COUNT ------- // 469 | // Counts the number of trailing zeros with compiler intrinsics 470 | template 471 | constexpr T _tzcnt(T src) noexcept 472 | { 473 | static_assert(binary_digits::value, ""); 474 | constexpr T digits = binary_digits::value; 475 | T dst = T(); 476 | if (digits <= std::numeric_limits::digits) { 477 | dst = src ? __builtin_ctz(src) : digits; 478 | } else if (digits <= std::numeric_limits::digits) { 479 | dst = src ? __builtin_ctzl(src) : digits; 480 | } else if (digits <= std::numeric_limits::digits) { 481 | dst = src ? __builtin_ctzll(src) : digits; 482 | } else { 483 | dst = _tzcnt(src, std::ignore); 484 | } 485 | return dst; 486 | } 487 | 488 | // Counts the number of trailing zeros without compiler intrinsics 489 | template 490 | constexpr T _tzcnt(T src, X...) noexcept 491 | { 492 | static_assert(binary_digits::value, ""); 493 | constexpr T digits = binary_digits::value; 494 | T dst = digits; 495 | if (src) { 496 | src = (src ^ (src - 1)) >> 1; 497 | for (dst = T(); src; dst++) { 498 | src >>= 1; 499 | } 500 | } 501 | return dst; 502 | } 503 | // -------------------------------------------------------------------------- // 504 | 505 | 506 | 507 | // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT FIELD EXTRACTION ------- // 508 | // Extacts to lsbs a field of contiguous bits with compiler intrinsics 509 | template 510 | constexpr T _bextr(T src, T start, T len) noexcept 511 | { 512 | static_assert(binary_digits::value, ""); 513 | constexpr T digits = binary_digits::value; 514 | T dst = T(); 515 | if (digits <= std::numeric_limits::digits) { 516 | dst = __builtin_ia32_bextr_u32(src, start, len); 517 | } else if (digits <= std::numeric_limits::digits) { 518 | dst = __builtin_ia32_bextr_u64(src, start, len); 519 | } else { 520 | dst = _bextr(src, start, len, std::ignore); 521 | } 522 | return dst; 523 | } 524 | 525 | // Extacts to lsbs a field of contiguous bits without compiler intrinsics 526 | template 527 | constexpr T _bextr(T src, T start, T len, X...) noexcept 528 | { 529 | static_assert(binary_digits::value, ""); 530 | constexpr T digits = binary_digits::value; 531 | constexpr T one = 1; 532 | const T msk = (one << len) * (len < digits) - one; 533 | return (src >> start) & msk * (start < digits); 534 | } 535 | // -------------------------------------------------------------------------- // 536 | 537 | 538 | 539 | // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: PARALLEL BIT DEPOSIT ------- // 540 | // Deposits bits according to a mask with compiler instrinsics 541 | template 542 | constexpr T _pdep(T src, T msk) noexcept 543 | { 544 | static_assert(binary_digits::value, ""); 545 | constexpr T digits = binary_digits::value; 546 | T dst = T(); 547 | if (digits <= std::numeric_limits::digits) { 548 | dst = _pdep_u32(src, msk); 549 | } else if (digits <= std::numeric_limits::digits) { 550 | dst = _pdep_u64(src, msk); 551 | } else { 552 | dst = _pdep(src, msk, std::ignore); 553 | } 554 | return dst; 555 | } 556 | 557 | // Deposits bits according to a mask without compiler instrinsics 558 | template 559 | constexpr T _pdep(T src, T msk, X...) noexcept 560 | { 561 | static_assert(binary_digits::value, ""); 562 | constexpr T digits = binary_digits::value; 563 | T dst = T(); 564 | T cnt = T(); 565 | while (msk) { 566 | dst >>= 1; 567 | if (msk & 1) { 568 | dst |= src << (digits - 1); 569 | src >>= 1; 570 | } 571 | msk >>= 1; 572 | ++cnt; 573 | } 574 | dst >>= (digits - cnt) * (cnt > 0); 575 | return dst; 576 | } 577 | // -------------------------------------------------------------------------- // 578 | 579 | 580 | 581 | // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: PARALLEL BIT EXTRACT ------- // 582 | // Extracts bits according to a mask with compiler instrinsics 583 | template 584 | constexpr T _pext(T src, T msk) noexcept 585 | { 586 | static_assert(binary_digits::value, ""); 587 | constexpr T digits = binary_digits::value; 588 | T dst = T(); 589 | if (digits <= std::numeric_limits::digits) { 590 | dst = _pext_u32(src, msk); 591 | } else if (digits <= std::numeric_limits::digits) { 592 | dst = _pext_u64(src, msk); 593 | } else { 594 | dst = _pext(src, msk, std::ignore); 595 | } 596 | return dst; 597 | } 598 | 599 | // Extracts bits according to a mask without compiler instrinsics 600 | template 601 | constexpr T _pext(T src, T msk, X...) noexcept 602 | { 603 | static_assert(binary_digits::value, ""); 604 | constexpr T digits = binary_digits::value; 605 | T dst = T(); 606 | T cnt = T(); 607 | while (msk) { 608 | if (msk & 1) { 609 | dst >>= 1; 610 | dst |= src << (digits - 1); 611 | ++cnt; 612 | } 613 | src >>= 1; 614 | msk >>= 1; 615 | } 616 | dst >>= (digits - cnt) * (cnt > 0); 617 | return dst; 618 | } 619 | // -------------------------------------------------------------------------- // 620 | 621 | 622 | 623 | // ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: BYTE SWAP ------------- // 624 | // Reverses the order of the underlying bytes with compiler intrinsics 625 | template 626 | constexpr T _byteswap(T src) noexcept 627 | { 628 | static_assert(binary_digits::value, ""); 629 | using byte_t = unsigned char; 630 | constexpr T digits = sizeof(T) * std::numeric_limits::digits; 631 | std::uint64_t tmp64 = 0; 632 | std::uint64_t* ptr64 = nullptr; 633 | if (std::is_same::value) { 634 | ptr64 = reinterpret_cast(&src); 635 | tmp64 = __builtin_bswap64(*ptr64); 636 | *ptr64 = __builtin_bswap64(*(ptr64 + 1)); 637 | *(ptr64 + 1) = tmp64; 638 | } else if (digits == std::numeric_limits::digits) { 639 | src = __builtin_bswap16(src); 640 | } else if (digits == std::numeric_limits::digits) { 641 | src = __builtin_bswap32(src); 642 | } else if (digits == std::numeric_limits::digits) { 643 | src = __builtin_bswap64(src); 644 | } else if (digits > std::numeric_limits::digits) { 645 | src = _byteswap(src, std::ignore); 646 | } 647 | return src; 648 | } 649 | 650 | // Reverses the order of the underlying bytes without compiler intrinsics 651 | template 652 | constexpr T _byteswap(T src, X...) noexcept 653 | { 654 | static_assert(binary_digits::value, ""); 655 | using byte_t = unsigned char; 656 | constexpr T half = sizeof(T) / 2; 657 | constexpr T end = sizeof(T) - 1; 658 | unsigned char* bytes = reinterpret_cast(&src); 659 | unsigned char byte = 0; 660 | for (T i = T(); i < half; ++i) { 661 | byte = bytes[i]; 662 | bytes[i] = bytes[end - i]; 663 | bytes[end - i] = byte; 664 | } 665 | return src; 666 | } 667 | // -------------------------------------------------------------------------- // 668 | 669 | 670 | 671 | // ------------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT SWAP ------------- // 672 | // Reverses the order of the bits with or without of compiler intrinsics 673 | template 674 | constexpr T _bitswap(T src) noexcept 675 | { 676 | static_assert(binary_digits::value, ""); 677 | using byte_t = unsigned char; 678 | constexpr auto ignore = nullptr; 679 | constexpr T digits = binary_digits::value; 680 | constexpr unsigned long long int first = 0x80200802ULL; 681 | constexpr unsigned long long int second = 0x0884422110ULL; 682 | constexpr unsigned long long int third = 0x0101010101ULL; 683 | constexpr unsigned long long int fourth = 32; 684 | constexpr bool is_size1 = sizeof(T) == 1; 685 | constexpr bool is_byte = digits == std::numeric_limits::digits; 686 | constexpr bool is_octet = std::numeric_limits::digits == 8; 687 | constexpr bool is_pow2 = _popcnt(digits, ignore) == 1; 688 | T dst = src; 689 | T i = digits - 1; 690 | if (is_size1 && is_byte && is_octet) { 691 | dst = ((src * first) & second) * third >> fourth; 692 | } else if (is_pow2) { 693 | dst = _bitswap(src); 694 | } else { 695 | for (src >>= 1; src; src >>= 1) { 696 | dst <<= 1; 697 | dst |= src & 1; 698 | i--; 699 | } 700 | dst <<= i; 701 | } 702 | return dst; 703 | } 704 | 705 | // Reverses the order of the bits: recursive metafunction 706 | template 707 | constexpr T _bitswap(T src) noexcept 708 | { 709 | static_assert(binary_digits::value, ""); 710 | constexpr T cnt = N >> 1; 711 | constexpr T msk = _bitswap(); 712 | src = ((src >> cnt) & msk) | ((src << cnt) & ~msk); 713 | return cnt > 1 ? _bitswap(src) : src; 714 | } 715 | 716 | // Reverses the order of the bits: mask for the recursive metafunction 717 | template 718 | constexpr T _bitswap() noexcept 719 | { 720 | static_assert(binary_digits::value, ""); 721 | constexpr T digits = binary_digits::value; 722 | T cnt = digits; 723 | T msk = ~T(); 724 | while (cnt != N) { 725 | cnt >>= 1; 726 | msk ^= (msk << cnt); 727 | } 728 | return msk; 729 | } 730 | // -------------------------------------------------------------------------- // 731 | 732 | 733 | 734 | // ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT BLEND ------------- // 735 | // Replaces len bits of src0 by the ones of src1 where the mask is true 736 | template 737 | constexpr T _bitblend(T src0, T src1, T msk) noexcept 738 | { 739 | static_assert(binary_digits::value, ""); 740 | return src0 ^ ((src0 ^ src1) & msk); 741 | } 742 | 743 | // Replaces len bits of src0 by the ones of src1 starting at start 744 | template 745 | constexpr T _bitblend(T src0, T src1, T start, T len) noexcept 746 | { 747 | static_assert(binary_digits::value, ""); 748 | constexpr T digits = binary_digits::value; 749 | constexpr T one = 1; 750 | const T msk = ((one << len) * (len < digits) - one) << start; 751 | return src0 ^ ((src0 ^ src1) & msk * (start < digits)); 752 | } 753 | // -------------------------------------------------------------------------- // 754 | 755 | 756 | 757 | // ----------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT COMPARE ------------ // 758 | // Compares a subsequence of bits within src0 and src1 and returns 0 if equal 759 | template 760 | constexpr T _bitcmp(T src0, T src1, T start0, T start1, T len) noexcept 761 | { 762 | static_assert(binary_digits::value, ""); 763 | return _bextr(src0, start0, len) == _bextr(src1, start1, len); 764 | } 765 | // -------------------------------------------------------------------------- // 766 | 767 | 768 | 769 | // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT LEFT ---- // 770 | // Left shifts dst by cnt bits, filling the lsbs of dst by the msbs of src 771 | template 772 | constexpr T _shld(T dst, T src, T cnt) noexcept 773 | { 774 | static_assert(binary_digits::value, ""); 775 | constexpr T digits = binary_digits::value; 776 | if (cnt < digits) { 777 | dst = (dst << cnt) | (src >> (digits - cnt)); 778 | } else { 779 | dst = (src << (cnt - digits)) * (cnt < digits + digits); 780 | } 781 | return dst; 782 | } 783 | // -------------------------------------------------------------------------- // 784 | 785 | 786 | 787 | // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT RIGHT --- // 788 | // Right shifts dst by cnt bits, filling the msbs of dst by the lsbs of src 789 | template 790 | constexpr T _shrd(T dst, T src, T cnt) noexcept 791 | { 792 | static_assert(binary_digits::value, ""); 793 | constexpr T digits = binary_digits::value; 794 | if (cnt < digits) { 795 | dst = (dst >> cnt) | (src << (digits - cnt)); 796 | } else { 797 | dst = (src >> (cnt - digits)) * (cnt < digits + digits); 798 | } 799 | return dst; 800 | } 801 | // -------------------------------------------------------------------------- // 802 | 803 | 804 | 805 | // ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: ADD CARRY ------------- // 806 | // Adds src0 and src1 and returns the new carry bit with intrinsics 807 | template 808 | constexpr C _addcarry(C carry, T src0, T src1, T* dst) noexcept 809 | { 810 | static_assert(binary_digits::value, ""); 811 | using wider_t = typename _wider_type::type; 812 | constexpr T digits = binary_digits::value; 813 | wider_t tmp = 0; 814 | unsigned int udst = 0; 815 | unsigned long long int ulldst = 0; 816 | if (digits == std::numeric_limits::digits) { 817 | carry = __builtin_ia32_addcarryx_u32(carry, src0, src1, &udst); 818 | *dst = udst; 819 | } else if (digits == std::numeric_limits::digits) { 820 | carry = __builtin_ia32_addcarryx_u64(carry, src0, src1, &ulldst); 821 | *dst = ulldst; 822 | } else if (digits < binary_digits::value) { 823 | tmp = static_cast(src0) + static_cast(src1); 824 | tmp += static_cast(static_cast(carry)); 825 | *dst = tmp; 826 | carry = static_cast(tmp >> digits); 827 | } else { 828 | carry = _addcarry(carry, src0, src1, dst, std::ignore); 829 | } 830 | return carry; 831 | } 832 | 833 | // Adds src0 and src1 and returns the new carry bit without intrinsics 834 | template 835 | constexpr C _addcarry(C carry, T src0, T src1, T* dst, X...) noexcept 836 | { 837 | static_assert(binary_digits::value, ""); 838 | *dst = src0 + src1 + static_cast(static_cast(carry)); 839 | return carry ? *dst <= src0 || *dst <= src1 : *dst < src0 || *dst < src1; 840 | } 841 | // -------------------------------------------------------------------------- // 842 | 843 | 844 | 845 | // ------------ IMPLEMENTATION DETAILS: INSTRUCTIONS: SUB BORROW ------------ // 846 | // Subtracts src1 to src0 and returns the new borrow bit with intrinsics 847 | template 848 | constexpr B _subborrow(B borrow, T src0, T src1, T* dst) noexcept 849 | { 850 | static_assert(binary_digits::value, ""); 851 | using wider_t = typename _wider_type::type; 852 | constexpr T digits = binary_digits::value; 853 | wider_t tmp = 0; 854 | unsigned int udst = 0; 855 | unsigned long long int ulldst = 0; 856 | if (digits == std::numeric_limits::digits) { 857 | borrow = __builtin_ia32_sbb_u32(borrow, src0, src1, &udst); 858 | *dst = udst; 859 | } else if (digits == std::numeric_limits::digits) { 860 | borrow = __builtin_ia32_sbb_u64(borrow, src0, src1, &ulldst); 861 | *dst = ulldst; 862 | } else if (digits < binary_digits::value) { 863 | tmp = static_cast(src1); 864 | tmp += static_cast(static_cast(borrow)); 865 | borrow = tmp > static_cast(src0); 866 | *dst = static_cast(src0) - tmp; 867 | } else { 868 | borrow = _subborrow(borrow, src0, src1, dst, std::ignore); 869 | } 870 | return borrow; 871 | } 872 | 873 | // Subtracts src1 to src0 and returns the new borrow bit with other intrinsics 874 | template 875 | constexpr B _subborrow(const B& borrow, T src0, T src1, T* dst) noexcept 876 | { 877 | static_assert(binary_digits::value, ""); 878 | using wider_t = typename _wider_type::type; 879 | constexpr T digits = binary_digits::value; 880 | wider_t tmp = 0; 881 | unsigned int udst = 0; 882 | unsigned long long int ulldst = 0; 883 | B flag = borrow; 884 | if (digits == std::numeric_limits::digits) { 885 | flag = __builtin_ia32_subborrow_u32(borrow, src0, src1, &udst); 886 | *dst = udst; 887 | } else if (digits == std::numeric_limits::digits) { 888 | flag = __builtin_ia32_subborrow_u64(borrow, src0, src1, &ulldst); 889 | *dst = ulldst; 890 | } else if (digits < binary_digits::value) { 891 | tmp = static_cast(src1); 892 | tmp += static_cast(static_cast(borrow)); 893 | flag = tmp > static_cast(src0); 894 | *dst = static_cast(src0) - tmp; 895 | } else { 896 | flag = _subborrow(borrow, src0, src1, dst, std::ignore); 897 | } 898 | return flag; 899 | } 900 | 901 | // Subtracts src1 to src0 and returns the new borrow bit without intrinsics 902 | template 903 | constexpr B _subborrow(B borrow, T src0, T src1, T* dst, X...) noexcept 904 | { 905 | static_assert(binary_digits::value, ""); 906 | *dst = src0 - (src1 + static_cast(static_cast(borrow))); 907 | return borrow ? src1 >= src0 : src1 > src0; 908 | } 909 | // -------------------------------------------------------------------------- // 910 | 911 | 912 | 913 | // -------- IMPLEMENTATION DETAILS: INSTRUCTIONS: MULTIWORD MULTIPLY -------- // 914 | // Multiplies src0 and src1 and gets the full result with compiler intrinsics 915 | template 916 | constexpr T _mulx(T src0, T src1, T* hi) noexcept 917 | { 918 | static_assert(binary_digits::value, ""); 919 | using wider_t = typename _wider_type::type; 920 | constexpr T digits = binary_digits::value; 921 | wider_t tmp = 0; 922 | T128 tmp128 = 0; 923 | T lo = 0; 924 | if (digits == std::numeric_limits::digits) { 925 | tmp128 = static_cast(src0) * static_cast(src1); 926 | *hi = tmp128 >> digits; 927 | lo = tmp128; 928 | } else if (digits + digits == binary_digits::value) { 929 | tmp = static_cast(src0) * static_cast(src1); 930 | *hi = tmp >> digits; 931 | lo = tmp; 932 | } else { 933 | lo = _mulx(src0, src1, hi, std::ignore); 934 | } 935 | return lo; 936 | } 937 | 938 | // Multiplies src0 and src1 and gets the full result without compiler intrinsics 939 | template 940 | constexpr T _mulx(T src0, T src1, T* hi, X...) noexcept 941 | { 942 | static_assert(binary_digits::value, ""); 943 | constexpr T digits = binary_digits::value; 944 | constexpr T offset = digits / 2; 945 | constexpr T ones = ~static_cast(0); 946 | const T lsbs0 = src0 & static_cast(ones >> (digits - offset)); 947 | const T msbs0 = src0 >> offset; 948 | const T lsbs1 = src1 & static_cast(ones >> (digits - offset)); 949 | const T msbs1 = src1 >> offset; 950 | const T llsbs = lsbs0 * lsbs1; 951 | const T mlsbs = msbs0 * lsbs1; 952 | const T lmsbs = lsbs0 * msbs1; 953 | const T mi = mlsbs + lmsbs; 954 | const T lo = llsbs + static_cast(mi << offset); 955 | const T lcarry = lo < llsbs || lo < static_cast(mi << offset); 956 | const T mcarry = static_cast(mi < mlsbs || mi < lmsbs) << offset; 957 | *hi = static_cast(mi >> offset) + msbs0 * msbs1 + mcarry + lcarry; 958 | return lo; 959 | } 960 | // -------------------------------------------------------------------------- // 961 | 962 | 963 | 964 | // ========================================================================== // 965 | } // namespace bit 966 | #endif // _BIT_DETAILS_HPP_INCLUDED 967 | // ========================================================================== // 968 | -------------------------------------------------------------------------------- /cpp/bit_iterator.hpp: -------------------------------------------------------------------------------- 1 | // ============================== BIT ITERATOR ============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_iterator.hpp 4 | // Description: A class representing an iterator on bit sequences 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_ITERATOR_HPP_INCLUDED 10 | #define _BIT_ITERATOR_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_details.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | 25 | 26 | /* ****************************** BIT ITERATOR ****************************** */ 27 | // Bit iterator class definition 28 | template 29 | class bit_iterator 30 | { 31 | // Assertions 32 | private: 33 | using _traits_t = _cv_iterator_traits; 34 | static_assert(binary_digits::value, ""); 35 | 36 | // Types 37 | public: 38 | using iterator_type = Iterator; 39 | using word_type = typename _traits_t::value_type; 40 | using iterator_category = typename _traits_t::iterator_category; 41 | using value_type = bit_value; 42 | using difference_type = std::ptrdiff_t; 43 | using pointer = bit_pointer; 44 | using reference = bit_reference; 45 | using size_type = std::size_t; 46 | 47 | // Lifecycle 48 | public: 49 | constexpr bit_iterator(); 50 | template 51 | constexpr bit_iterator(const bit_iterator& other); 52 | explicit constexpr bit_iterator(iterator_type i); 53 | constexpr bit_iterator(iterator_type i, size_type pos); 54 | 55 | // Assignment 56 | public: 57 | template 58 | constexpr bit_iterator& operator=(const bit_iterator& other); 59 | 60 | // Access 61 | public: 62 | constexpr reference operator*() const noexcept; 63 | constexpr pointer operator->() const noexcept; 64 | constexpr reference operator[](difference_type n) const; 65 | 66 | // Increment and decrement operators 67 | public: 68 | constexpr bit_iterator& operator++(); 69 | constexpr bit_iterator& operator--(); 70 | constexpr bit_iterator operator++(int); 71 | constexpr bit_iterator operator--(int); 72 | constexpr bit_iterator operator+(difference_type n) const; 73 | constexpr bit_iterator operator-(difference_type n) const; 74 | constexpr bit_iterator& operator+=(difference_type n); 75 | constexpr bit_iterator& operator-=(difference_type n); 76 | 77 | // Underlying details 78 | public: 79 | constexpr iterator_type base() const; 80 | constexpr size_type position() const noexcept; 81 | constexpr typename std::remove_cv::type mask() const noexcept; 82 | 83 | // Implementation details: data members 84 | private: 85 | iterator_type _current; 86 | size_type _position; 87 | 88 | // Non-member arithmetic operators 89 | template 90 | friend constexpr bit_iterator operator+( 91 | typename bit_iterator::difference_type n, 92 | const bit_iterator& i 93 | ); 94 | template 95 | friend constexpr typename std::common_type< 96 | typename bit_iterator::difference_type, 97 | typename bit_iterator::difference_type 98 | >::type operator-( 99 | const bit_iterator& lhs, 100 | const bit_iterator& rhs 101 | ); 102 | 103 | // Comparison operators 104 | public: 105 | template 106 | friend constexpr bool operator==( 107 | const bit_iterator& lhs, 108 | const bit_iterator& rhs 109 | ); 110 | template 111 | friend constexpr bool operator!=( 112 | const bit_iterator& lhs, 113 | const bit_iterator& rhs 114 | ); 115 | template 116 | friend constexpr bool operator<( 117 | const bit_iterator& lhs, 118 | const bit_iterator& rhs 119 | ); 120 | template 121 | friend constexpr bool operator<=( 122 | const bit_iterator& lhs, 123 | const bit_iterator& rhs 124 | ); 125 | template 126 | friend constexpr bool operator>( 127 | const bit_iterator& lhs, 128 | const bit_iterator& rhs 129 | ); 130 | template 131 | friend constexpr bool operator>=( 132 | const bit_iterator& lhs, 133 | const bit_iterator& rhs 134 | ); 135 | }; 136 | /* ************************************************************************** */ 137 | 138 | 139 | 140 | // ------------------------ BIT ITERATOR: LIFECYCLE ------------------------- // 141 | // Implicitly default constructs a bit iterator 142 | template 143 | constexpr bit_iterator::bit_iterator( 144 | ) 145 | : _current() 146 | , _position() 147 | { 148 | } 149 | 150 | // Implicitly constructs a bit iterator from another bit iterator 151 | template 152 | template 153 | constexpr bit_iterator::bit_iterator( 154 | const bit_iterator& other 155 | ) 156 | : _current(other._current) 157 | , _position(other._position) 158 | { 159 | } 160 | 161 | // Explicitly constructs an aligned bit iterator from an iterator 162 | template 163 | constexpr bit_iterator::bit_iterator( 164 | iterator_type i 165 | ) 166 | : _current(i) 167 | , _position(0) 168 | { 169 | } 170 | 171 | // Explicitly constructs an unaligned bit iterator from an iterator 172 | template 173 | constexpr bit_iterator::bit_iterator( 174 | iterator_type i, 175 | size_type pos 176 | ) 177 | : _current(i) 178 | , _position((assert(pos < binary_digits::value), pos)) 179 | { 180 | } 181 | // -------------------------------------------------------------------------- // 182 | 183 | 184 | 185 | // ------------------------ BIT ITERATOR: ASSIGNMENT ------------------------ // 186 | // Assigns a bit iterator to the bit iterator 187 | template 188 | template 189 | constexpr bit_iterator& bit_iterator::operator=( 190 | const bit_iterator& other 191 | ) 192 | { 193 | _current = other._current; 194 | _position = other._position; 195 | return *this; 196 | } 197 | // -------------------------------------------------------------------------- // 198 | 199 | 200 | 201 | // -------------------------- BIT ITERATOR: ACCESS -------------------------- // 202 | // Gets a bit reference from the bit iterator 203 | template 204 | constexpr typename bit_iterator::reference 205 | bit_iterator::operator*( 206 | ) const noexcept 207 | { 208 | return reference(*_current, _position); 209 | } 210 | 211 | // Gets a pointer to a bit 212 | template 213 | constexpr typename bit_iterator::pointer 214 | bit_iterator::operator->( 215 | ) const noexcept 216 | { 217 | return pointer(&*_current, _position); 218 | } 219 | 220 | // Gets a bit reference, decrementing or incrementing the iterator 221 | template 222 | constexpr typename bit_iterator::reference 223 | bit_iterator::operator[]( 224 | difference_type n 225 | ) const 226 | { 227 | constexpr difference_type digits = binary_digits::value; 228 | const difference_type sum = _position + n; 229 | difference_type diff = sum / digits; 230 | if (sum < 0 && diff * digits != sum) { 231 | --diff; 232 | } 233 | return reference(*std::next(_current, diff), sum - diff * digits); 234 | } 235 | // -------------------------------------------------------------------------- // 236 | 237 | 238 | 239 | // ------------- BIT ITERATOR: INCREMENT AND DECREMENT OPERATORS ------------ // 240 | // Increments the bit iterator and returns it 241 | template 242 | constexpr bit_iterator& bit_iterator::operator++( 243 | ) 244 | { 245 | constexpr size_type digits = binary_digits::value; 246 | if (_position + 1 < digits) { 247 | ++_position; 248 | } else { 249 | ++_current; 250 | _position = 0; 251 | } 252 | return *this; 253 | } 254 | 255 | // Decrements the bit iterator and returns it 256 | template 257 | constexpr bit_iterator& bit_iterator::operator--( 258 | ) 259 | { 260 | constexpr size_type digits = binary_digits::value; 261 | if (_position) { 262 | --_position; 263 | } else { 264 | --_current; 265 | _position = digits - 1; 266 | } 267 | return *this; 268 | } 269 | 270 | // Increments the bit iterator and returns the old one 271 | template 272 | constexpr bit_iterator bit_iterator::operator++( 273 | int 274 | ) 275 | { 276 | bit_iterator old = *this; 277 | ++(*this); 278 | return old; 279 | } 280 | 281 | // Decrements the bit iterator and returns the old one 282 | template 283 | constexpr bit_iterator bit_iterator::operator--( 284 | int 285 | ) 286 | { 287 | bit_iterator old = *this; 288 | --(*this); 289 | return old; 290 | } 291 | 292 | // Looks forward several bits and gets an iterator at this position 293 | template 294 | constexpr bit_iterator bit_iterator::operator+( 295 | difference_type n 296 | ) const 297 | { 298 | constexpr difference_type digits = binary_digits::value; 299 | const difference_type sum = _position + n; 300 | difference_type diff = sum / digits; 301 | if (sum < 0 && diff * digits != sum) { 302 | --diff; 303 | } 304 | return bit_iterator(std::next(_current, diff), sum - diff * digits); 305 | } 306 | 307 | // Looks backward several bits and gets an iterator at this position 308 | template 309 | constexpr bit_iterator bit_iterator::operator-( 310 | difference_type n 311 | ) const 312 | { 313 | constexpr difference_type digits = binary_digits::value; 314 | const difference_type sum = _position - n; 315 | difference_type diff = sum / digits; 316 | if (sum < 0 && diff * digits != sum) { 317 | --diff; 318 | } 319 | return bit_iterator(std::next(_current, diff), sum - diff * digits); 320 | } 321 | 322 | // Increments the iterator by several bits and returns it 323 | template 324 | constexpr bit_iterator& bit_iterator::operator+=( 325 | difference_type n 326 | ) 327 | { 328 | *this = *this + n; 329 | return *this; 330 | } 331 | 332 | // Decrements the iterator by several bits and returns it 333 | template 334 | constexpr bit_iterator& bit_iterator::operator-=( 335 | difference_type n 336 | ) 337 | { 338 | *this = *this - n; 339 | return *this; 340 | } 341 | // -------------------------------------------------------------------------- // 342 | 343 | 344 | 345 | // -------------------- BIT ITERATOR: UNDERLYING DETAILS -------------------- // 346 | // Returns a copy of the underlying iterator 347 | template 348 | constexpr typename bit_iterator::iterator_type 349 | bit_iterator::base( 350 | ) const 351 | { 352 | return _current; 353 | } 354 | 355 | // Returns the position of the bit within the underlying word 356 | template 357 | constexpr typename bit_iterator::size_type 358 | bit_iterator::position( 359 | ) const noexcept 360 | { 361 | return _position; 362 | } 363 | 364 | // Returns a mask corresponding to the bit associated with the iterator 365 | template 366 | constexpr typename std::remove_cv< 367 | typename bit_iterator::word_type 368 | >::type bit_iterator::mask( 369 | ) const noexcept 370 | { 371 | return static_cast(1) << _position; 372 | } 373 | // -------------------------------------------------------------------------- // 374 | 375 | 376 | 377 | // -------------- BIT ITERATOR: NON-MEMBER ARITHMETIC OPERATORS ------------- // 378 | // Advances the bit iterator several times 379 | template 380 | constexpr bit_iterator operator+( 381 | typename bit_iterator::difference_type n, 382 | const bit_iterator& i 383 | ) 384 | { 385 | return i + n; 386 | } 387 | 388 | // Computes the distance in bits separating two bit iterators 389 | template 390 | constexpr typename std::common_type< 391 | typename bit_iterator::difference_type, 392 | typename bit_iterator::difference_type 393 | >::type operator-( 394 | const bit_iterator& lhs, 395 | const bit_iterator& rhs 396 | ) 397 | { 398 | using lhs_utype = typename bit_iterator::word_type; 399 | using rhs_utype = typename bit_iterator::word_type; 400 | using lhs_type = typename bit_iterator::difference_type; 401 | using rhs_type = typename bit_iterator::difference_type; 402 | using difference_type = typename std::common_type::type; 403 | constexpr difference_type lhs_digits = binary_digits::value; 404 | constexpr difference_type rhs_digits = binary_digits::value; 405 | constexpr difference_type digits = rhs_digits; 406 | static_assert(lhs_digits == rhs_digits, ""); 407 | const difference_type main = lhs._current - rhs._current; 408 | return main * digits + (lhs._position - rhs._position); 409 | } 410 | // -------------------------------------------------------------------------- // 411 | 412 | 413 | 414 | // ------------------- BIT ITERATOR: COMPARISON OPERATORS ------------------- // 415 | // Checks if the left hand side is equal to the right hand side 416 | template 417 | constexpr bool operator==( 418 | const bit_iterator& lhs, 419 | const bit_iterator& rhs 420 | ) 421 | { 422 | return lhs._current == rhs._current && lhs._position == rhs._position; 423 | } 424 | 425 | // Checks if the left hand side is non equal to the right hand side 426 | template 427 | constexpr bool operator!=( 428 | const bit_iterator& lhs, 429 | const bit_iterator& rhs 430 | ) 431 | { 432 | return lhs._current != rhs._current || lhs._position != rhs._position; 433 | } 434 | 435 | // Checks if the left hand side is less than the right hand side 436 | template 437 | constexpr bool operator<( 438 | const bit_iterator& lhs, 439 | const bit_iterator& rhs 440 | ) 441 | { 442 | return lhs._current < rhs._current 443 | || (lhs._current == rhs._current && lhs._position < rhs._position); 444 | } 445 | 446 | // Checks if the left hand side is less than or equal to the right hand side 447 | template 448 | constexpr bool operator<=( 449 | const bit_iterator& lhs, 450 | const bit_iterator& rhs 451 | ) 452 | { 453 | return lhs._current < rhs._current 454 | || (lhs._current == rhs._current && lhs._position <= rhs._position); 455 | } 456 | 457 | // Checks if the left hand side is greater than the right hand side 458 | template 459 | constexpr bool operator>( 460 | const bit_iterator& lhs, 461 | const bit_iterator& rhs 462 | ) 463 | { 464 | return lhs._current > rhs._current 465 | || (lhs._current == rhs._current && lhs._position > rhs._position); 466 | } 467 | 468 | // Checks if the left hand side is greater than or equal to the right hand side 469 | template 470 | constexpr bool operator>=( 471 | const bit_iterator& lhs, 472 | const bit_iterator& rhs 473 | ) 474 | { 475 | return lhs._current > rhs._current 476 | || (lhs._current == rhs._current && lhs._position >= rhs._position); 477 | } 478 | // -------------------------------------------------------------------------- // 479 | 480 | 481 | 482 | // ========================================================================== // 483 | } // namespace bit 484 | #endif // _BIT_ITERATOR_HPP_INCLUDED 485 | // ========================================================================== // 486 | -------------------------------------------------------------------------------- /cpp/bit_pointer.hpp: -------------------------------------------------------------------------------- 1 | // ============================== BIT POINTER =============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_pointer.hpp 4 | // Description: A class representing a pointer to a bit 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_POINTER_HPP_INCLUDED 10 | #define _BIT_POINTER_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_details.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | 25 | 26 | /* ****************************** BIT POINTER ******************************* */ 27 | // Bit pointer class definition 28 | template 29 | class bit_pointer 30 | { 31 | // Assertions 32 | static_assert(binary_digits::value, ""); 33 | 34 | // Friendship 35 | template friend class bit_pointer; 36 | 37 | // Types 38 | public: 39 | using word_type = WordType; 40 | using size_type = std::size_t; 41 | using difference_type = std::ptrdiff_t; 42 | 43 | // Lifecycle 44 | public: 45 | constexpr bit_pointer() noexcept; 46 | template 47 | constexpr bit_pointer(const bit_pointer& other) noexcept; 48 | constexpr bit_pointer(std::nullptr_t) noexcept; 49 | explicit constexpr bit_pointer(word_type* ptr) noexcept; 50 | constexpr bit_pointer(word_type* ptr, size_type pos); 51 | 52 | // Assignment 53 | public: 54 | constexpr bit_pointer& operator=(std::nullptr_t) noexcept; 55 | constexpr bit_pointer& operator=(const bit_pointer& other) noexcept; 56 | template 57 | constexpr bit_pointer& operator=(const bit_pointer& other) noexcept; 58 | 59 | // Conversion 60 | public: 61 | explicit constexpr operator bool() const noexcept; 62 | 63 | // Access 64 | public: 65 | constexpr bit_reference operator*() const noexcept; 66 | constexpr bit_reference* operator->() const noexcept; 67 | constexpr bit_reference operator[](difference_type n) const; 68 | 69 | // Increment and decrement operators 70 | public: 71 | constexpr bit_pointer& operator++(); 72 | constexpr bit_pointer& operator--(); 73 | constexpr bit_pointer operator++(int); 74 | constexpr bit_pointer operator--(int); 75 | constexpr bit_pointer operator+(difference_type n) const; 76 | constexpr bit_pointer operator-(difference_type n) const; 77 | constexpr bit_pointer& operator+=(difference_type n); 78 | constexpr bit_pointer& operator-=(difference_type n); 79 | 80 | // Implementation details: data members 81 | private: 82 | bit_reference _ref; 83 | 84 | // Non-member arithmetic operators 85 | template 86 | friend constexpr bit_pointer operator+( 87 | typename bit_pointer::difference_type n, 88 | bit_pointer x 89 | ); 90 | template 91 | friend constexpr typename std::common_type< 92 | typename bit_pointer::difference_type, 93 | typename bit_pointer::difference_type 94 | >::type operator-( 95 | bit_pointer lhs, 96 | bit_pointer rhs 97 | ); 98 | 99 | // Comparison operators 100 | template 101 | friend constexpr bool operator==( 102 | bit_pointer lhs, 103 | bit_pointer rhs 104 | ) noexcept; 105 | template 106 | friend constexpr bool operator!=( 107 | bit_pointer lhs, 108 | bit_pointer rhs 109 | ) noexcept; 110 | template 111 | friend constexpr bool operator<( 112 | bit_pointer lhs, 113 | bit_pointer rhs 114 | ) noexcept; 115 | template 116 | friend constexpr bool operator<=( 117 | bit_pointer lhs, 118 | bit_pointer rhs 119 | ) noexcept; 120 | template 121 | friend constexpr bool operator>( 122 | bit_pointer lhs, 123 | bit_pointer rhs 124 | ) noexcept; 125 | template 126 | friend constexpr bool operator>=( 127 | bit_pointer lhs, 128 | bit_pointer rhs 129 | ) noexcept; 130 | }; 131 | /* ************************************************************************** */ 132 | 133 | 134 | 135 | // ------------------------- BIT POINTER: LIFECYCLE ------------------------- // 136 | // Implicitly default constructs a null bit pointer 137 | template 138 | constexpr bit_pointer::bit_pointer( 139 | ) noexcept 140 | : _ref(nullptr) 141 | { 142 | } 143 | 144 | // Implicitly constructs a bit pointer from another bit pointer 145 | template 146 | template 147 | constexpr bit_pointer::bit_pointer( 148 | const bit_pointer& other 149 | ) noexcept 150 | : _ref(other._ref) 151 | { 152 | } 153 | 154 | // Explicitly constructs a bit pointer from a null pointer 155 | template 156 | constexpr bit_pointer::bit_pointer( 157 | std::nullptr_t 158 | ) noexcept 159 | : _ref(nullptr) 160 | { 161 | } 162 | 163 | // Explicitly constructs an aligned bit pointer from a pointer 164 | template 165 | constexpr bit_pointer::bit_pointer( 166 | word_type* ptr 167 | ) noexcept 168 | : _ref(ptr) 169 | { 170 | } 171 | 172 | // Explicitly constructs an unaligned bit pointer from a pointer 173 | template 174 | constexpr bit_pointer::bit_pointer( 175 | word_type* ptr, 176 | size_type pos 177 | ) 178 | : _ref(ptr, pos) 179 | { 180 | } 181 | // -------------------------------------------------------------------------- // 182 | 183 | 184 | 185 | // ------------------------ BIT POINTER: ASSIGNMENT ------------------------- // 186 | // Assigns a null pointer to the bit pointer 187 | template 188 | constexpr bit_pointer& bit_pointer::operator=( 189 | std::nullptr_t 190 | ) noexcept 191 | { 192 | _ref._ptr = nullptr; 193 | _ref._mask = 0; 194 | return *this; 195 | } 196 | 197 | // Copies a bit pointer to the bit pointer 198 | template 199 | constexpr bit_pointer& bit_pointer::operator=( 200 | const bit_pointer& other 201 | ) noexcept 202 | { 203 | _ref._ptr = other._ref._ptr; 204 | _ref._mask = other._ref._mask; 205 | return *this; 206 | } 207 | 208 | // Assigns a bit pointer to the bit pointer 209 | template 210 | template 211 | constexpr bit_pointer& bit_pointer::operator=( 212 | const bit_pointer& other 213 | ) noexcept 214 | { 215 | _ref._ptr = other._ref._ptr; 216 | _ref._mask = other._ref._mask; 217 | return *this; 218 | } 219 | // -------------------------------------------------------------------------- // 220 | 221 | 222 | 223 | // ------------------------ BIT POINTER: CONVERSION ------------------------- // 224 | // Returns true if the bit pointer is null, false otherwise 225 | template 226 | constexpr bit_pointer::operator bool( 227 | ) const noexcept 228 | { 229 | return _ref._ptr; 230 | } 231 | // -------------------------------------------------------------------------- // 232 | 233 | 234 | 235 | // -------------------------- BIT POINTER: ACCESS --------------------------- // 236 | // Gets a bit reference from the bit pointer 237 | template 238 | constexpr bit_reference bit_pointer::operator*( 239 | ) const noexcept 240 | { 241 | return _ref; 242 | } 243 | 244 | // Gets a pointer to a bit reference 245 | template 246 | constexpr bit_reference* bit_pointer::operator->( 247 | ) const noexcept 248 | { 249 | return std::addressof(const_cast&>(_ref)); 250 | } 251 | 252 | // Gets a bit reference, decrementing or incrementing the pointer 253 | template 254 | constexpr bit_reference bit_pointer::operator[]( 255 | difference_type n 256 | ) const 257 | { 258 | constexpr difference_type digits = binary_digits::value; 259 | const difference_type sum = _ref.position() + n; 260 | difference_type diff = sum / digits; 261 | if (sum < 0 && diff * digits != sum) { 262 | --diff; 263 | } 264 | return bit_reference(_ref._ptr + diff, sum - diff * digits); 265 | } 266 | // -------------------------------------------------------------------------- // 267 | 268 | 269 | 270 | // ------------- BIT POINTER: INCREMENT AND DECREMENT OPERATORS ------------- // 271 | // Increments the bit pointer and returns it 272 | template 273 | constexpr bit_pointer& bit_pointer::operator++( 274 | ) 275 | { 276 | using type = typename std::remove_cv::type; 277 | constexpr size_type digits = binary_digits::value; 278 | constexpr type one = 1; 279 | constexpr type mask = one; 280 | const size_type pos = _ref.position(); 281 | if (pos + 1 < digits) { 282 | _ref._mask <<= 1; 283 | } else { 284 | ++_ref._ptr; 285 | _ref._mask = mask; 286 | } 287 | return *this; 288 | } 289 | 290 | // Decrements the bit pointer and returns it 291 | template 292 | constexpr bit_pointer& bit_pointer::operator--( 293 | ) 294 | { 295 | using type = typename std::remove_cv::type; 296 | constexpr size_type digits = binary_digits::value; 297 | constexpr type one = 1; 298 | constexpr type mask = static_cast(one << (digits - 1)); 299 | const size_type pos = _ref.position(); 300 | if (pos) { 301 | _ref._mask >>= 1; 302 | } else { 303 | --_ref._ptr; 304 | _ref._mask = mask; 305 | } 306 | return *this; 307 | } 308 | 309 | // Increments the bit pointer and returns the old one 310 | template 311 | constexpr bit_pointer bit_pointer::operator++( 312 | int 313 | ) 314 | { 315 | bit_pointer old = *this; 316 | ++(*this); 317 | return old; 318 | } 319 | 320 | // Decrements the bit pointer and returns the old one 321 | template 322 | constexpr bit_pointer bit_pointer::operator--( 323 | int 324 | ) 325 | { 326 | bit_pointer old = *this; 327 | --(*this); 328 | return old; 329 | } 330 | 331 | // Looks forward several bits and gets a pointer at this position 332 | template 333 | constexpr bit_pointer bit_pointer::operator+( 334 | difference_type n 335 | ) const 336 | { 337 | constexpr difference_type digits = binary_digits::value; 338 | const difference_type sum = _ref.position() + n; 339 | difference_type diff = sum / digits; 340 | if (sum < 0 && diff * digits != sum) { 341 | --diff; 342 | } 343 | return bit_pointer(_ref._ptr + diff, sum - diff * digits); 344 | } 345 | 346 | // Looks backward several bits and gets a pointer at this position 347 | template 348 | constexpr bit_pointer bit_pointer::operator-( 349 | difference_type n 350 | ) const 351 | { 352 | constexpr difference_type digits = binary_digits::value; 353 | const difference_type sum = _ref.position() - n; 354 | difference_type diff = sum / digits; 355 | if (sum < 0 && diff * digits != sum) { 356 | --diff; 357 | } 358 | return bit_pointer(_ref._ptr + diff, sum - diff * digits); 359 | } 360 | 361 | // Increments the pointer by several bits and returns it 362 | template 363 | constexpr bit_pointer& bit_pointer::operator+=( 364 | difference_type n 365 | ) 366 | { 367 | *this = *this + n; 368 | return *this; 369 | } 370 | 371 | // Decrements the pointer by several bits and returns it 372 | template 373 | constexpr bit_pointer& bit_pointer::operator-=( 374 | difference_type n 375 | ) 376 | { 377 | *this = *this - n; 378 | return *this; 379 | } 380 | // -------------------------------------------------------------------------- // 381 | 382 | 383 | 384 | // -------------- BIT POINTER: NON-MEMBER ARITHMETIC OPERATORS -------------- // 385 | // Advances the bit pointer several times 386 | template 387 | constexpr bit_pointer operator+( 388 | typename bit_pointer::difference_type n, 389 | bit_pointer x 390 | ) 391 | { 392 | return x + n; 393 | } 394 | 395 | // Computes the distance in bits separating two bit pointers 396 | template 397 | constexpr typename std::common_type< 398 | typename bit_pointer::difference_type, 399 | typename bit_pointer::difference_type 400 | >::type operator-( 401 | bit_pointer lhs, 402 | bit_pointer rhs 403 | ) 404 | { 405 | using lhs_type = typename bit_pointer::difference_type; 406 | using rhs_type = typename bit_pointer::difference_type; 407 | using difference_type = typename std::common_type::type; 408 | constexpr difference_type lhs_digits = binary_digits::value; 409 | constexpr difference_type rhs_digits = binary_digits::value; 410 | constexpr difference_type digits = rhs_digits; 411 | static_assert(lhs_digits == rhs_digits, ""); 412 | const difference_type main = lhs._ref.address() - rhs._ref.address(); 413 | return main * digits + (lhs._ref.position() - rhs._ref.position()); 414 | } 415 | // -------------------------------------------------------------------------- // 416 | 417 | 418 | 419 | // ------------------- BIT POINTER: COMPARISON OPERATORS -------------------- // 420 | // Checks if the left hand side is equal to the right hand side 421 | template 422 | constexpr bool operator==( 423 | bit_pointer lhs, 424 | bit_pointer rhs 425 | ) noexcept 426 | { 427 | return lhs._ref.address() == rhs._ref.address() 428 | && lhs._ref.position() == rhs._ref.position(); 429 | } 430 | 431 | // Checks if the left hand side is non equal to the right hand side 432 | template 433 | constexpr bool operator!=( 434 | bit_pointer lhs, 435 | bit_pointer rhs 436 | ) noexcept 437 | { 438 | return lhs._ref.address() != rhs._ref.address() 439 | || lhs._ref.position() != rhs._ref.position(); 440 | } 441 | 442 | // Checks if the left hand side is less than the right hand side 443 | template 444 | constexpr bool operator<( 445 | bit_pointer lhs, 446 | bit_pointer rhs 447 | ) noexcept 448 | { 449 | return lhs._ref.address() < rhs._ref.address() 450 | || (lhs._ref.address() == rhs._ref.address() 451 | && lhs._ref.position() < rhs._ref.position()); 452 | } 453 | 454 | // Checks if the left hand side is less than or equal to the right hand side 455 | template 456 | constexpr bool operator<=( 457 | bit_pointer lhs, 458 | bit_pointer rhs 459 | ) noexcept 460 | { 461 | return lhs._ref.address() < rhs._ref.address() 462 | || (lhs._ref.address() == rhs._ref.address() 463 | && lhs._ref.position() <= rhs._ref.position()); 464 | } 465 | 466 | // Checks if the left hand side is greater than the right hand side 467 | template 468 | constexpr bool operator>( 469 | bit_pointer lhs, 470 | bit_pointer rhs 471 | ) noexcept 472 | { 473 | return lhs._ref.address() > rhs._ref.address() 474 | || (lhs._ref.address() == rhs._ref.address() 475 | && lhs._ref.position() > rhs._ref.position()); 476 | } 477 | 478 | // Checks if the left hand side is greater than or equal to the right hand side 479 | template 480 | constexpr bool operator>=( 481 | bit_pointer lhs, 482 | bit_pointer rhs 483 | ) noexcept 484 | { 485 | return lhs._ref.address() > rhs._ref.address() 486 | || (lhs._ref.address() == rhs._ref.address() 487 | && lhs._ref.position() >= rhs._ref.position()); 488 | } 489 | // -------------------------------------------------------------------------- // 490 | 491 | 492 | 493 | // ========================================================================== // 494 | } // namespace bit 495 | #endif // _BIT_POINTER_HPP_INCLUDED 496 | // ========================================================================== // 497 | -------------------------------------------------------------------------------- /cpp/bit_reference.hpp: -------------------------------------------------------------------------------- 1 | // ============================= BIT REFERENCE ============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_reference.hpp 4 | // Description: A class representing a reference to a bit 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_REFERENCE_HPP_INCLUDED 10 | #define _BIT_REFERENCE_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_details.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | 25 | 26 | /* ***************************** BIT REFERENCE ****************************** */ 27 | // Bit reference class definition 28 | template 29 | class bit_reference 30 | { 31 | // Assertions 32 | static_assert(binary_digits::value, ""); 33 | 34 | // Friendship 35 | template friend class bit_reference; 36 | friend class bit_pointer; 37 | 38 | // Types 39 | public: 40 | using word_type = WordType; 41 | using size_type = std::size_t; 42 | 43 | // Lifecycle 44 | public: 45 | template 46 | constexpr bit_reference(const bit_reference& other) noexcept; 47 | explicit constexpr bit_reference(word_type& ref) noexcept; 48 | constexpr bit_reference(word_type& ref, size_type pos); 49 | 50 | // Assignment 51 | public: 52 | constexpr bit_reference& operator=(const bit_reference& other) noexcept; 53 | template 54 | constexpr bit_reference& operator=(const bit_reference& other) noexcept; 55 | constexpr bit_reference& operator=(bit_value val) noexcept; 56 | constexpr bit_reference& assign(word_type val) noexcept; 57 | constexpr bit_reference& assign(word_type val, size_type pos); 58 | 59 | // Bitwise assignment operators 60 | public: 61 | constexpr bit_reference& operator&=(bit_value other) noexcept; 62 | constexpr bit_reference& operator|=(bit_value other) noexcept; 63 | constexpr bit_reference& operator^=(bit_value other) noexcept; 64 | 65 | // Conversion 66 | public: 67 | explicit constexpr operator bool() const noexcept; 68 | 69 | // Access 70 | public: 71 | constexpr bit_pointer operator&() const noexcept; 72 | 73 | // Swap members 74 | public: 75 | template 76 | void swap(bit_reference other); 77 | void swap(bit_value& other); 78 | 79 | // Bit manipulation 80 | public: 81 | constexpr bit_reference& set(bool b) noexcept; 82 | constexpr bit_reference& set() noexcept; 83 | constexpr bit_reference& reset() noexcept; 84 | constexpr bit_reference& flip() noexcept; 85 | 86 | // Underlying details 87 | public: 88 | constexpr word_type* address() const noexcept; 89 | constexpr size_type position() const noexcept; 90 | constexpr typename std::remove_cv::type mask() const noexcept; 91 | 92 | // Implementation details: function members 93 | private: 94 | bit_reference() noexcept = default; 95 | explicit constexpr bit_reference(std::nullptr_t) noexcept; 96 | explicit constexpr bit_reference(word_type* ptr) noexcept; 97 | constexpr bit_reference(word_type* ptr, size_type pos); 98 | 99 | // Implementation details: data members 100 | private: 101 | word_type* _ptr; 102 | typename std::remove_cv::type _mask; 103 | }; 104 | 105 | // Swap 106 | template 107 | void swap( 108 | bit_reference lhs, 109 | bit_reference rhs 110 | ) noexcept; 111 | template 112 | void swap( 113 | bit_reference lhs, 114 | bit_value& rhs 115 | ) noexcept; 116 | template 117 | void swap( 118 | bit_value& lhs, 119 | bit_reference rhs 120 | ) noexcept; 121 | 122 | // Stream functions 123 | template 124 | std::basic_istream& operator>>( 125 | std::basic_istream& is, 126 | bit_reference& x 127 | ); 128 | template 129 | std::basic_ostream& operator<<( 130 | std::basic_ostream& os, 131 | bit_reference x 132 | ); 133 | /* ************************************************************************** */ 134 | 135 | 136 | 137 | // ------------------------ BIT REFERENCE: LIFECYCLE ------------------------ // 138 | // Implicitly constructs a bit reference from another bit reference 139 | template 140 | template 141 | constexpr bit_reference::bit_reference( 142 | const bit_reference& other 143 | ) noexcept 144 | : _ptr(other._ptr) 145 | , _mask(other._mask) 146 | { 147 | } 148 | 149 | // Explicitly constructs an aligned bit reference 150 | template 151 | constexpr bit_reference::bit_reference( 152 | word_type& ref 153 | ) noexcept 154 | : _ptr(&ref) 155 | , _mask(1) 156 | { 157 | } 158 | 159 | // Explicitly constructs an unaligned bit reference 160 | template 161 | constexpr bit_reference::bit_reference( 162 | word_type& ref, 163 | size_type pos 164 | ) 165 | : _ptr((assert(pos < binary_digits::value), &ref)) 166 | , _mask(static_cast(1) << pos) 167 | { 168 | } 169 | // -------------------------------------------------------------------------- // 170 | 171 | 172 | 173 | // ----------------------- BIT REFERENCE: ASSIGNMENT ------------------------ // 174 | // Copies a bit reference to the bit reference 175 | template 176 | constexpr bit_reference& bit_reference::operator=( 177 | const bit_reference& other 178 | ) noexcept 179 | { 180 | other ? set() : reset(); 181 | return *this; 182 | } 183 | 184 | // Assigns a bit reference to the bit reference 185 | template 186 | template 187 | constexpr bit_reference& bit_reference::operator=( 188 | const bit_reference& other 189 | ) noexcept 190 | { 191 | other ? set() : reset(); 192 | return *this; 193 | } 194 | 195 | // Assigns a bit value to the bit reference 196 | template 197 | constexpr bit_reference& bit_reference::operator=( 198 | bit_value val 199 | ) noexcept 200 | { 201 | val ? set() : reset(); 202 | return *this; 203 | } 204 | 205 | // Assigns the aligned bit of a value to the bit reference 206 | template 207 | constexpr bit_reference& bit_reference::assign( 208 | word_type val 209 | ) noexcept 210 | { 211 | val & 1 ? set() : reset(); 212 | return *this; 213 | } 214 | 215 | // Assigns an unaligned bit of a value to the bit reference 216 | template 217 | constexpr bit_reference& bit_reference::assign( 218 | word_type val, 219 | size_type pos 220 | ) 221 | { 222 | assert(pos < binary_digits::value); 223 | val >> pos & 1 ? set() : reset(); 224 | return *this; 225 | } 226 | // -------------------------------------------------------------------------- // 227 | 228 | 229 | 230 | // -------------- BIT REFERENCE: BITWISE ASSIGNMENT OPERATORS --------------- // 231 | // Assigns the value of the referenced bit through a bitwise and operation 232 | template 233 | constexpr bit_reference& bit_reference::operator&=( 234 | bit_value other 235 | ) noexcept 236 | { 237 | *_ptr &= ~(_mask * static_cast(!other._value)); 238 | return *this; 239 | } 240 | 241 | // Assigns the value of the referenced bit through a bitwise or operation 242 | template 243 | constexpr bit_reference& bit_reference::operator|=( 244 | bit_value other 245 | ) noexcept 246 | { 247 | *_ptr |= _mask * static_cast(other._value); 248 | return *this; 249 | } 250 | 251 | // Assigns the value of the referenced bit through a bitwise xor operation 252 | template 253 | constexpr bit_reference& bit_reference::operator^=( 254 | bit_value other 255 | ) noexcept 256 | { 257 | *_ptr ^= _mask * static_cast(other._value); 258 | return *this; 259 | } 260 | // -------------------------------------------------------------------------- // 261 | 262 | 263 | 264 | // ----------------------- BIT REFERENCE: CONVERSION ------------------------ // 265 | // Explicitly converts the bit reference to a boolean value 266 | template 267 | constexpr bit_reference::operator bool( 268 | ) const noexcept 269 | { 270 | return *_ptr & _mask; 271 | } 272 | // -------------------------------------------------------------------------- // 273 | 274 | 275 | 276 | // ------------------------- BIT REFERENCE: ACCESS -------------------------- // 277 | // Gets a bit pointer from the bit reference 278 | template 279 | constexpr bit_pointer bit_reference::operator&( 280 | ) const noexcept 281 | { 282 | return bit_pointer(_ptr, position()); 283 | } 284 | // -------------------------------------------------------------------------- // 285 | 286 | 287 | 288 | // ---------------------- BIT REFERENCE: SWAP MEMBERS ----------------------- // 289 | // Swaps the value of the referenced bit with another bit reference 290 | template 291 | template 292 | void bit_reference::swap( 293 | bit_reference other 294 | ) 295 | { 296 | if (other != *this) { 297 | flip(); 298 | other.flip(); 299 | } 300 | } 301 | 302 | // Swaps the value of the referenced bit with a bit value 303 | template 304 | void bit_reference::swap( 305 | bit_value& other 306 | ) 307 | { 308 | if (other != *this) { 309 | flip(); 310 | other.flip(); 311 | } 312 | } 313 | // -------------------------------------------------------------------------- // 314 | 315 | 316 | 317 | // -------------------- BIT REFERENCE: BIT MANIPULATION --------------------- // 318 | // Sets the value of the referenced bit to the provided boolean value 319 | template 320 | constexpr bit_reference& bit_reference::set( 321 | bool b 322 | ) noexcept 323 | { 324 | b ? set() : reset(); 325 | return *this; 326 | } 327 | 328 | // Sets the value of the referenced bit to 1 329 | template 330 | constexpr bit_reference& bit_reference::set( 331 | ) noexcept 332 | { 333 | *_ptr |= _mask; 334 | return *this; 335 | } 336 | 337 | // Resets the value of the referenced bit to 0 338 | template 339 | constexpr bit_reference& bit_reference::reset( 340 | ) noexcept 341 | { 342 | *_ptr &= ~_mask; 343 | return *this; 344 | } 345 | 346 | // Flips the value of the referenced bit 347 | template 348 | constexpr bit_reference& bit_reference::flip( 349 | ) noexcept 350 | { 351 | *_ptr ^= _mask; 352 | return *this; 353 | } 354 | // -------------------------------------------------------------------------- // 355 | 356 | 357 | 358 | // ------------------- BIT REFERENCE: UNDERLYING DETAILS -------------------- // 359 | // Returns a pointer to the underlying word 360 | template 361 | constexpr typename bit_reference::word_type* 362 | bit_reference::address( 363 | ) const noexcept 364 | { 365 | return _ptr; 366 | } 367 | 368 | // Returns the position of the referenced bit within the underlying word 369 | template 370 | constexpr typename bit_reference::size_type 371 | bit_reference::position( 372 | ) const noexcept 373 | { 374 | return _tzcnt(_mask); 375 | } 376 | 377 | // Returns a mask corresponding to the referenced bit 378 | template 379 | constexpr typename std::remove_cv< 380 | typename bit_reference::word_type 381 | >::type bit_reference::mask( 382 | ) const noexcept 383 | { 384 | return _mask; 385 | } 386 | // -------------------------------------------------------------------------- // 387 | 388 | 389 | 390 | // -------------------------- BIT REFERENCE: SWAP --------------------------- // 391 | // Swaps two bit references 392 | template 393 | void swap( 394 | bit_reference lhs, 395 | bit_reference rhs 396 | ) noexcept 397 | { 398 | if (lhs != rhs) { 399 | lhs.flip(); 400 | rhs.flip(); 401 | } 402 | } 403 | 404 | // Swaps a bit reference and a bit value 405 | template 406 | void swap( 407 | bit_reference lhs, 408 | bit_value& rhs 409 | ) noexcept 410 | { 411 | if (lhs != rhs) { 412 | lhs.flip(); 413 | rhs.flip(); 414 | } 415 | } 416 | 417 | // Swaps a bit value and a bit reference 418 | template 419 | void swap( 420 | bit_value& lhs, 421 | bit_reference rhs 422 | ) noexcept 423 | { 424 | if (lhs != rhs) { 425 | lhs.flip(); 426 | rhs.flip(); 427 | } 428 | } 429 | // -------------------------------------------------------------------------- // 430 | 431 | 432 | 433 | // -------------------- BIT REFERENCE: STREAM FUNCTIONS --------------------- // 434 | // Extracts a bit reference from an input stream 435 | template 436 | std::basic_istream& operator>>( 437 | std::basic_istream& is, 438 | bit_reference& x 439 | ) 440 | { 441 | using stream_type = std::basic_istream; 442 | using traits_type = typename stream_type::traits_type; 443 | using ios_base = typename stream_type::ios_base; 444 | constexpr char zero = '0'; 445 | constexpr char one = '1'; 446 | constexpr typename stream_type::int_type eof = traits_type::eof(); 447 | typename ios_base::iostate state = ios_base::goodbit; 448 | typename stream_type::char_type char_value = 0; 449 | typename stream_type::int_type int_value = 0; 450 | typename stream_type::sentry sentry(is); 451 | bool ok = false; 452 | bit_value tmp = x; 453 | if (sentry) { 454 | try { 455 | int_value = is.rdbuf()->sbumpc(); 456 | if (traits_type::eq_int_type(int_value, eof)) { 457 | state |= ios_base::eofbit; 458 | } else { 459 | char_value = traits_type::to_char_type(int_value); 460 | if (traits_type::eq(char_value, is.widen(zero))) { 461 | tmp.reset(); 462 | ok = true; 463 | } else if (traits_type::eq(char_value, is.widen(one))) { 464 | tmp.set(); 465 | ok = true; 466 | } else { 467 | int_value = is.rdbuf()->sputbackc(char_value); 468 | if (traits_type::eq_int_type(int_value, eof)) { 469 | state |= ios_base::failbit; 470 | } 471 | } 472 | } 473 | } catch(...) { 474 | is.setstate(ios_base::badbit); 475 | } 476 | } 477 | if (ok) { 478 | x = tmp; 479 | } else { 480 | state |= ios_base::failbit; 481 | } 482 | state ? is.setstate(state) : void(); 483 | return is; 484 | } 485 | 486 | // Inserts a bit reference in an output stream 487 | template 488 | std::basic_ostream& operator<<( 489 | std::basic_ostream& os, 490 | bit_reference x 491 | ) 492 | { 493 | constexpr char zero = '0'; 494 | constexpr char one = '1'; 495 | return os << os.widen(x ? one : zero); 496 | } 497 | // -------------------------------------------------------------------------- // 498 | 499 | 500 | 501 | // -------- BIT REFERENCE: IMPLEMENTATION DETAILS: FUNCTION MEMBERS --------- // 502 | // Privately explicitly constructs a bit reference from a nullptr 503 | template 504 | constexpr bit_reference::bit_reference( 505 | std::nullptr_t 506 | ) noexcept 507 | : _ptr(nullptr) 508 | , _mask() 509 | { 510 | } 511 | 512 | // Privately explicitly constructs an aligned bit reference from a pointer 513 | template 514 | constexpr bit_reference::bit_reference( 515 | word_type* ptr 516 | ) noexcept 517 | : _ptr(ptr) 518 | , _mask(1) 519 | { 520 | } 521 | 522 | // Privately explicitly constructs an unaligned bit reference from a pointer 523 | template 524 | constexpr bit_reference::bit_reference( 525 | word_type* ptr, 526 | size_type pos 527 | ) 528 | : _ptr((assert(pos < binary_digits::value), ptr)) 529 | , _mask(static_cast(1) << pos) 530 | { 531 | } 532 | // -------------------------------------------------------------------------- // 533 | 534 | 535 | 536 | // ========================================================================== // 537 | } // namespace bit 538 | #endif // _BIT_REFERENCE_HPP_INCLUDED 539 | // ========================================================================== // 540 | -------------------------------------------------------------------------------- /cpp/bit_value.hpp: -------------------------------------------------------------------------------- 1 | // =============================== BIT VALUE ================================ // 2 | // Project: The C++ Bit Library 3 | // Name: bit_value.hpp 4 | // Description: A class representing an independent, non-referenced bit 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _BIT_VALUE_HPP_INCLUDED 10 | #define _BIT_VALUE_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_details.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | 25 | 26 | /* ******************************* BIT VALUE ******************************** */ 27 | // Bit value class definition 28 | class bit_value 29 | { 30 | // Friendship 31 | template friend class bit_reference; 32 | 33 | // Types 34 | public: 35 | using size_type = std::size_t; 36 | 37 | // Lifecycle 38 | public: 39 | constexpr bit_value() noexcept; 40 | template 41 | constexpr bit_value(bit_reference ref) noexcept; 42 | template 43 | explicit constexpr bit_value(WordType val) noexcept; 44 | template 45 | constexpr bit_value(WordType val, size_type pos); 46 | 47 | // Assignment 48 | public: 49 | template 50 | constexpr bit_value& operator=(bit_reference ref) noexcept; 51 | template 52 | constexpr bit_value& assign(WordType val) noexcept; 53 | template 54 | constexpr bit_value& assign(WordType val, size_type pos); 55 | 56 | // Bitwise assignment operators 57 | public: 58 | constexpr bit_value& operator&=(bit_value other) noexcept; 59 | constexpr bit_value& operator|=(bit_value other) noexcept; 60 | constexpr bit_value& operator^=(bit_value other) noexcept; 61 | 62 | // Conversion 63 | public: 64 | explicit constexpr operator bool() const noexcept; 65 | 66 | // Swap members 67 | public: 68 | void swap(bit_value& other) noexcept; 69 | template 70 | void swap(bit_reference other) noexcept; 71 | 72 | // Bit manipulation 73 | public: 74 | constexpr bit_value& set(bool b) noexcept; 75 | constexpr bit_value& set() noexcept; 76 | constexpr bit_value& reset() noexcept; 77 | constexpr bit_value& flip() noexcept; 78 | 79 | // Implementation details: data members 80 | private: 81 | bool _value; 82 | 83 | // Bitwise operators 84 | public: 85 | friend constexpr bit_value operator~( 86 | bit_value rhs 87 | ) noexcept; 88 | friend constexpr bit_value operator&( 89 | bit_value lhs, 90 | bit_value rhs 91 | ) noexcept; 92 | friend constexpr bit_value operator|( 93 | bit_value lhs, 94 | bit_value rhs 95 | ) noexcept; 96 | friend constexpr bit_value operator^( 97 | bit_value lhs, 98 | bit_value rhs 99 | ) noexcept; 100 | 101 | // Comparison operators 102 | public: 103 | friend constexpr bool operator==( 104 | bit_value lhs, 105 | bit_value rhs 106 | ) noexcept; 107 | friend constexpr bool operator!=( 108 | bit_value lhs, 109 | bit_value rhs 110 | ) noexcept; 111 | friend constexpr bool operator<( 112 | bit_value lhs, 113 | bit_value rhs 114 | ) noexcept; 115 | friend constexpr bool operator<=( 116 | bit_value lhs, 117 | bit_value rhs 118 | ) noexcept; 119 | friend constexpr bool operator>( 120 | bit_value lhs, 121 | bit_value rhs 122 | ) noexcept; 123 | friend constexpr bool operator>=( 124 | bit_value lhs, 125 | bit_value rhs 126 | ) noexcept; 127 | }; 128 | 129 | // Stream functions 130 | template 131 | std::basic_istream& operator>>( 132 | std::basic_istream& is, 133 | bit_value& x 134 | ); 135 | template 136 | std::basic_ostream& operator<<( 137 | std::basic_ostream& os, 138 | bit_value x 139 | ); 140 | 141 | // Constants 142 | /* ************************************************************************** */ 143 | 144 | 145 | 146 | // -------------------------- BIT VALUE: LIFECYCLE -------------------------- // 147 | // Implicitly default constructs a bit value initialized to zero 148 | constexpr bit_value::bit_value( 149 | ) noexcept 150 | : _value(false) 151 | { 152 | } 153 | 154 | // Implicitly constructs a bit value from a bit reference 155 | template 156 | constexpr bit_value::bit_value( 157 | bit_reference ref 158 | ) noexcept 159 | : _value(static_cast(ref)) 160 | { 161 | } 162 | 163 | // Explicitly constructs an aligned bit value 164 | template 165 | constexpr bit_value::bit_value( 166 | WordType val 167 | ) noexcept 168 | : _value(val & 1) 169 | { 170 | static_assert(binary_digits::value, ""); 171 | } 172 | 173 | // Explicitly constructs an unaligned bit value 174 | template 175 | constexpr bit_value::bit_value( 176 | WordType val, 177 | size_type pos 178 | ) 179 | : _value((assert(pos < binary_digits::value), val >> pos & 1)) 180 | { 181 | static_assert(binary_digits::value, ""); 182 | } 183 | // -------------------------------------------------------------------------- // 184 | 185 | 186 | 187 | // ------------------------- BIT VALUE: ASSIGNMENT -------------------------- // 188 | // Assigns a bit reference to the bit value 189 | template 190 | constexpr bit_value& bit_value::operator=( 191 | bit_reference ref 192 | ) noexcept 193 | { 194 | _value = static_cast(ref); 195 | return *this; 196 | } 197 | 198 | // Assigns the aligned bit of a value to the bit value 199 | template 200 | constexpr bit_value& bit_value::assign( 201 | WordType val 202 | ) noexcept 203 | { 204 | static_assert(binary_digits::value, ""); 205 | _value = val & 1; 206 | return *this; 207 | } 208 | 209 | // Assigns an unaligned bit of a value to the bit value 210 | template 211 | constexpr bit_value& bit_value::assign( 212 | WordType val, 213 | size_type pos 214 | ) 215 | { 216 | assert(pos < binary_digits::value); 217 | _value = val >> pos & 1; 218 | return *this; 219 | } 220 | // -------------------------------------------------------------------------- // 221 | 222 | 223 | 224 | // ---------------- BIT VALUE: BITWISE ASSIGNMENT OPERATORS ----------------- // 225 | // Assigns the value of the bit through a bitwise and operation 226 | constexpr bit_value& bit_value::operator&=( 227 | bit_value other 228 | ) noexcept 229 | { 230 | _value &= other._value; 231 | return *this; 232 | } 233 | 234 | // Assigns the value of the bit through a bitwise or operation 235 | constexpr bit_value& bit_value::operator|=( 236 | bit_value other 237 | ) noexcept 238 | { 239 | _value |= other._value; 240 | return *this; 241 | } 242 | 243 | // Assigns the value of the bit through a bitwise xor operation 244 | constexpr bit_value& bit_value::operator^=( 245 | bit_value other 246 | ) noexcept 247 | { 248 | _value ^= other._value; 249 | return *this; 250 | } 251 | // -------------------------------------------------------------------------- // 252 | 253 | 254 | 255 | // ------------------------- BIT VALUE: CONVERSION -------------------------- // 256 | // Explicitly converts the bit value to a boolean value 257 | constexpr bit_value::operator bool( 258 | ) const noexcept 259 | { 260 | return _value; 261 | } 262 | // -------------------------------------------------------------------------- // 263 | 264 | 265 | 266 | // ------------------------ BIT VALUE: SWAP MEMBERS ------------------------- // 267 | // Swaps the bit value with another bit value 268 | void bit_value::swap( 269 | bit_value& other 270 | ) noexcept 271 | { 272 | std::swap(*this, other); 273 | } 274 | 275 | // Swaps the bit value with the value of a bit reference 276 | template 277 | void bit_value::swap( 278 | bit_reference other 279 | ) noexcept 280 | { 281 | if (other != _value) { 282 | flip(); 283 | other.flip(); 284 | } 285 | } 286 | // -------------------------------------------------------------------------- // 287 | 288 | 289 | 290 | // ---------------------- BIT VALUE: BIT MANIPULATION ----------------------- // 291 | // Sets the value of the bit to the provided boolean value 292 | constexpr bit_value& bit_value::set( 293 | bool b 294 | ) noexcept 295 | { 296 | _value = b; 297 | return *this; 298 | } 299 | 300 | // Sets the value of the bit to 1 301 | constexpr bit_value& bit_value::set( 302 | ) noexcept 303 | { 304 | _value = true; 305 | return *this; 306 | } 307 | 308 | // Resets the value of the bit to 0 309 | constexpr bit_value& bit_value::reset( 310 | ) noexcept 311 | { 312 | _value = false; 313 | return *this; 314 | } 315 | 316 | // Flips the value of the bit 317 | constexpr bit_value& bit_value::flip( 318 | ) noexcept 319 | { 320 | _value = !_value; 321 | return *this; 322 | } 323 | // -------------------------------------------------------------------------- // 324 | 325 | 326 | 327 | // ---------------------- BIT VALUE: BITWISE OPERATORS ---------------------- // 328 | // Returns the result of a bitwise not on the right hand side 329 | constexpr bit_value operator~( 330 | bit_value rhs 331 | ) noexcept 332 | { 333 | using type = unsigned int; 334 | return bit_value(static_cast(!rhs._value)); 335 | } 336 | 337 | // Returns the result of a bitwise and between the left and right hand sides 338 | constexpr bit_value operator&( 339 | bit_value lhs, 340 | bit_value rhs 341 | ) noexcept 342 | { 343 | using type = unsigned int; 344 | return bit_value(static_cast(lhs._value & rhs._value)); 345 | } 346 | 347 | // Returns the result of a bitwise or between the left and right hand sides 348 | constexpr bit_value operator|( 349 | bit_value lhs, 350 | bit_value rhs 351 | ) noexcept 352 | { 353 | using type = unsigned int; 354 | return bit_value(static_cast(lhs._value | rhs._value)); 355 | } 356 | 357 | // Returns the result of a bitwise xor between the left and right hand sides 358 | constexpr bit_value operator^( 359 | bit_value lhs, 360 | bit_value rhs 361 | ) noexcept 362 | { 363 | using type = unsigned int; 364 | return bit_value(static_cast(lhs._value ^ rhs._value)); 365 | } 366 | // -------------------------------------------------------------------------- // 367 | 368 | 369 | 370 | // -------------------- BIT VALUE: COMPARISON OPERATORS --------------------- // 371 | // Checks if the left hand side is equal to the right hand side 372 | constexpr bool operator==( 373 | bit_value lhs, 374 | bit_value rhs 375 | ) noexcept 376 | { 377 | return lhs._value == rhs._value; 378 | } 379 | 380 | // Checks if the left hand side is non equal to the right hand side 381 | constexpr bool operator!=( 382 | bit_value lhs, 383 | bit_value rhs 384 | ) noexcept 385 | { 386 | return lhs._value != rhs._value; 387 | } 388 | 389 | // Checks if the left hand side is less than the right hand side 390 | constexpr bool operator<( 391 | bit_value lhs, 392 | bit_value rhs 393 | ) noexcept 394 | { 395 | return lhs._value < rhs._value; 396 | } 397 | 398 | // Checks if the left hand side is less than or equal to the right hand side 399 | constexpr bool operator<=( 400 | bit_value lhs, 401 | bit_value rhs 402 | ) noexcept 403 | { 404 | return lhs._value <= rhs._value; 405 | } 406 | 407 | // Checks if the left hand side is greater than the right hand side 408 | constexpr bool operator>( 409 | bit_value lhs, 410 | bit_value rhs 411 | ) noexcept 412 | { 413 | return lhs._value > rhs._value; 414 | } 415 | 416 | // Checks if the left hand side is greater than or equal to the right hand side 417 | constexpr bool operator>=( 418 | bit_value lhs, 419 | bit_value rhs 420 | ) noexcept 421 | { 422 | return lhs._value >= rhs._value; 423 | } 424 | // -------------------------------------------------------------------------- // 425 | 426 | 427 | 428 | // ---------------------- BIT VALUE: STREAM FUNCTIONS ----------------------- // 429 | // Extracts a bit value from an input stream 430 | template 431 | std::basic_istream& operator>>( 432 | std::basic_istream& is, 433 | bit_value& x 434 | ) 435 | { 436 | using stream_type = std::basic_istream; 437 | using traits_type = typename stream_type::traits_type; 438 | using ios_base = typename stream_type::ios_base; 439 | constexpr char zero = '0'; 440 | constexpr char one = '1'; 441 | constexpr typename stream_type::int_type eof = traits_type::eof(); 442 | typename ios_base::iostate state = ios_base::goodbit; 443 | typename stream_type::char_type char_value = 0; 444 | typename stream_type::int_type int_value = 0; 445 | typename stream_type::sentry sentry(is); 446 | bool ok = false; 447 | bit_value tmp = x; 448 | if (sentry) { 449 | try { 450 | int_value = is.rdbuf()->sbumpc(); 451 | if (traits_type::eq_int_type(int_value, eof)) { 452 | state |= ios_base::eofbit; 453 | } else { 454 | char_value = traits_type::to_char_type(int_value); 455 | if (traits_type::eq(char_value, is.widen(zero))) { 456 | tmp.reset(); 457 | ok = true; 458 | } else if (traits_type::eq(char_value, is.widen(one))) { 459 | tmp.set(); 460 | ok = true; 461 | } else { 462 | int_value = is.rdbuf()->sputbackc(char_value); 463 | if (traits_type::eq_int_type(int_value, eof)) { 464 | state |= ios_base::failbit; 465 | } 466 | } 467 | } 468 | } catch(...) { 469 | is.setstate(ios_base::badbit); 470 | } 471 | } 472 | if (ok) { 473 | x = tmp; 474 | } else { 475 | state |= ios_base::failbit; 476 | } 477 | state ? is.setstate(state) : void(); 478 | return is; 479 | } 480 | 481 | // Inserts a bit value in an output stream 482 | template 483 | std::basic_ostream& operator<<( 484 | std::basic_ostream& os, 485 | bit_value x 486 | ) 487 | { 488 | constexpr char zero = '0'; 489 | constexpr char one = '1'; 490 | return os << os.widen(x ? one : zero); 491 | } 492 | // -------------------------------------------------------------------------- // 493 | 494 | 495 | 496 | // -------------------------- BIT VALUE: CONSTANTS -------------------------- // 497 | // Constant bit values 498 | constexpr bit_value bit_off(0U); 499 | constexpr bit_value bit_on(1U); 500 | constexpr bit_value bit0(0U); 501 | constexpr bit_value bit1(1U); 502 | // -------------------------------------------------------------------------- // 503 | 504 | 505 | 506 | // ========================================================================== // 507 | } // namespace bit 508 | #endif // _BIT_VALUE_HPP_INCLUDED 509 | // ========================================================================== // 510 | -------------------------------------------------------------------------------- /cpp/linear_overload.hpp: -------------------------------------------------------------------------------- 1 | // ============================ LINEAR OVERLOAD ============================= // 2 | // Project: The C++ Bit Library 3 | // Name: linear_overload.hpp 4 | // Description: Utilities to invoke the first valid call of an overload set 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _LINEAR_OVERLOAD_HPP_INCLUDED 10 | #define _LINEAR_OVERLOAD_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | #include 18 | #include 19 | #include 20 | // Project sources 21 | // Third-party libraries 22 | // Miscellaneous 23 | namespace bit { 24 | // ========================================================================== // 25 | 26 | 27 | 28 | /* **************************** LINEAR OVERLOAD ***************************** */ 29 | // Linear overload class definition 30 | template 31 | class linear_overload 32 | { 33 | // Types 34 | public: 35 | using tuple = std::tuple; 36 | 37 | // Lifecycle 38 | public: 39 | template 40 | explicit constexpr linear_overload(G&&... g); 41 | 42 | // Access 43 | public: 44 | template 45 | decltype(auto) get() noexcept; 46 | template 47 | constexpr decltype(auto) get() const noexcept; 48 | template 49 | decltype(auto) get() noexcept; 50 | template 51 | constexpr decltype(auto) get() const noexcept; 52 | 53 | // Capacity 54 | public: 55 | static constexpr bool empty() noexcept; 56 | static constexpr std::size_t size() noexcept; 57 | static constexpr std::size_t max_size() noexcept; 58 | 59 | // Call 60 | public: 61 | template < 62 | std::size_t N = 0, 63 | class... Args, 64 | class = typename std::enable_if= size()>::type 65 | > 66 | void operator()(Args&&...); 67 | template < 68 | std::size_t N = 0, 69 | class = typename std::enable_if::type, 70 | class = decltype(std::get(std::declval())()) 71 | > 72 | decltype(auto) operator()(); 73 | template < 74 | std::size_t N = 0, 75 | class Arg, 76 | class... Args, 77 | class = typename std::enable_if::type, 78 | class = decltype(std::get(std::declval())( 79 | std::declval(), 80 | std::declval()... 81 | )) 82 | > 83 | decltype(auto) operator()(Arg&& arg, Args&&... args); 84 | template < 85 | std::size_t N = 0, 86 | class... Args, 87 | class = typename std::enable_if::type 88 | > 89 | decltype(auto) operator()(Args&&... args); 90 | 91 | // Implementation details: data members 92 | private: 93 | tuple _f; 94 | 95 | // Maker 96 | public: 97 | template 98 | friend constexpr linear_overload overload_linearly(G&&... g); 99 | }; 100 | /* ************************************************************************** */ 101 | 102 | 103 | 104 | // ----------------------- LINEAR OVERLOAD: LIFECYCLE ----------------------- // 105 | // Explicitly constructs a linear overload from a list of functions 106 | template 107 | template 108 | constexpr linear_overload::linear_overload( 109 | G&&... g 110 | ) 111 | : _f{std::forward(g)...} 112 | { 113 | } 114 | // -------------------------------------------------------------------------- // 115 | 116 | 117 | 118 | // ------------------------ LINEAR OVERLOAD: ACCESS ------------------------- // 119 | // Gets the i-th function of the linear overload 120 | template 121 | template 122 | decltype(auto) linear_overload::get( 123 | ) noexcept 124 | { 125 | return std::get(_f); 126 | } 127 | 128 | // Gets the i-th function of the immutable linear overload 129 | template 130 | template 131 | constexpr decltype(auto) linear_overload::get( 132 | ) const noexcept 133 | { 134 | return std::get(_f); 135 | } 136 | 137 | // Gets the function of the given type from the linear overload 138 | template 139 | template 140 | decltype(auto) linear_overload::get() noexcept 141 | { 142 | return std::get(_f); 143 | } 144 | 145 | // Gets the function of the given type from the immutable linear overload 146 | template 147 | template 148 | constexpr decltype(auto) linear_overload::get( 149 | ) const noexcept 150 | { 151 | return std::get(_f); 152 | } 153 | // -------------------------------------------------------------------------- // 154 | 155 | 156 | 157 | // ----------------------- LINEAR OVERLOAD: CAPACITY ------------------------ // 158 | // Checks whether the linear overload is empty 159 | template 160 | constexpr bool linear_overload::empty( 161 | ) noexcept 162 | { 163 | return std::tuple_size::value == 0; 164 | } 165 | 166 | // Returns the number of functions in the linear overload 167 | template 168 | constexpr std::size_t linear_overload::size( 169 | ) noexcept 170 | { 171 | return std::tuple_size::value; 172 | } 173 | 174 | // Returns the maximum possible number of functions in the linear overload 175 | template 176 | constexpr std::size_t linear_overload::max_size( 177 | ) noexcept 178 | { 179 | return std::tuple_size::value; 180 | } 181 | // -------------------------------------------------------------------------- // 182 | 183 | 184 | 185 | // ------------------------- LINEAR OVERLOAD: CALL -------------------------- // 186 | // Calls the linear overload with the provided arguments: no valid overload 187 | template 188 | template 189 | void linear_overload::operator()( 190 | Args&&... 191 | ) 192 | { 193 | } 194 | 195 | // Calls the linear overload with the provided arguments: no argument 196 | template 197 | template 198 | decltype(auto) linear_overload::operator()( 199 | ) 200 | { 201 | return std::get(_f)(); 202 | } 203 | 204 | // Calls the linear overload with the provided arguments: valid call 205 | template 206 | template 207 | decltype(auto) linear_overload::operator()( 208 | Arg&& arg, 209 | Args&&... args 210 | ) 211 | { 212 | return std::get(_f)(std::forward(arg), std::forward(args)...); 213 | } 214 | 215 | // Calls the linear overload with the provided arguments: invalid call 216 | template 217 | template 218 | decltype(auto) linear_overload::operator()( 219 | Args&&... args 220 | ) 221 | { 222 | return operator()(std::forward(args)...); 223 | } 224 | // -------------------------------------------------------------------------- // 225 | 226 | 227 | 228 | // ------------------------- LINEAR OVERLOAD: MAKER ------------------------- // 229 | // Builds a linear overload from a list of functions 230 | template 231 | constexpr linear_overload overload_linearly(G&&... g) 232 | { 233 | return linear_overload(std::forward(g)...); 234 | } 235 | // -------------------------------------------------------------------------- // 236 | 237 | 238 | 239 | // ========================================================================== // 240 | } // namespace bit 241 | #endif // _LINEAR_OVERLOAD_HPP_INCLUDED 242 | // ========================================================================== // 243 | -------------------------------------------------------------------------------- /doc/media/architecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/architecture.pdf -------------------------------------------------------------------------------- /doc/media/bit_log.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_log.pdf -------------------------------------------------------------------------------- /doc/media/bit_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_log.png -------------------------------------------------------------------------------- /doc/media/bit_log_article.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_log_article.pdf -------------------------------------------------------------------------------- /doc/media/bit_log_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_log_article.png -------------------------------------------------------------------------------- /doc/media/bit_nolog.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_nolog.pdf -------------------------------------------------------------------------------- /doc/media/bit_nolog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_nolog.png -------------------------------------------------------------------------------- /doc/media/bit_nolog_article.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_nolog_article.pdf -------------------------------------------------------------------------------- /doc/media/bit_nolog_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bit_nolog_article.png -------------------------------------------------------------------------------- /doc/media/bitwise_operators.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/bitwise_operators.pdf -------------------------------------------------------------------------------- /doc/media/fundamental_operations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/fundamental_operations.pdf -------------------------------------------------------------------------------- /doc/media/integral_types.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/media/integral_types.pdf -------------------------------------------------------------------------------- /doc/wg21/2016_02_jacksonville/p0237r0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/wg21/2016_02_jacksonville/p0237r0.pdf -------------------------------------------------------------------------------- /doc/wg21/2016_06_oulu/d0237r1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Wording for fundamental bit manipulation utilities 5 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
Document number:P0237R1
Date:2016-05-30
Project:ISO JTC1/SC22/WG21: Programming Language C++
Audience:LEWG, SG14, SG6
Reply to:Vincent Reverdy <vince.rev@gmail.com>
Robert J. Brunner
48 | 49 |

Wording for fundamental bit manipulation utilities

50 | 51 |

Table of Contents

52 | 59 | 60 |

History and feedback

61 |

The idea of bit manipulation utilities has been originally proposed in the 2016 pre-Jacksonville mailing and has been discussed in both SG6 and LEWG in Jacksonville. The original document, P0237R0 fully describes and discusses the idea of fundamental bit manipulation utilities for the C++ language. Another proposal, P0161R0 had the same motivations but was focusing on bitsets. As P0237R0 seemed more generic and not restrained to the scope of std::bitset, we decided to push forward P0237R0, while still keeping in mind the functionalities and performances allowed by P0161R0. The genericity and abstraction offered by P0237R0 should not introduce a performance overhead (at least with the -O2 optimization level on most compilers) when compared to P0161R0 and N3864.

62 | 63 |

The feedback from the Jacksonville meeting was positive: in top of their intrinsics functionalities, bit manipulation utilities have the potential to serve as a common basis for a std::dynamic_bitset replacement of std::vector<bool> and for bounded and unbounded precision arithmetic as discussed in N4038.

64 | 65 |

In terms of design, the following guidance was given by LEWG: 66 |

    67 |
  • Restrain std::bit_reference to unsigned fundamental integer types? 68 | [SF: 6, F: 3, N: 0, A: 0, SA :0]
  • 69 |
  • std::bit_reference provides no arithmetic except what the paper provides explicitly? [Unanimous consent]
  • 70 |
  • In small discussion groups, introducing std::bit_value was considered to be good idea
  • 71 |
72 |

73 | 74 |

In Jacksonville, the following questions were raised:

75 |
    76 |
  • How to deal with word endianness?
  • 77 |
  • How to provide the possibility to get a mask from the bit position?
  • 78 |
  • How to deal with infinite ranges of bits, particularly for unbounded precision arithmetic?
  • 79 |
  • What bitwise logic operators should bits provide?
  • 80 |
  • How to make std::bit_iterator compatible with proxy iterators presented in P0022R1?
  • 81 |
82 |

83 | 84 | If bit utilities make it to the standard, they will be used, at least, as the basis for an implementation of a dynamic bitset, and are likely to be used as an interface to the underlying containers of words for unbounded and bounded precision arithmetic. 85 | 86 |

Introduction

87 |

88 | This paper proposes a wording for fundamental bit utilities: std::bit_value, std::bit_reference, std::bit_pointer and std::bit_iterator. An in-depth discussion of the motivations and an in-depth exploration of the design space can be found in P0237R0. In short, this paper proposes a set of 4 main utility classes to serve as bit abstractions in order to offer a common and standardized interface for libraries and programs that require bit manipulations. These bit utilities both emulate bits that are easy to use for users, and provide an interface to access the underlying words to implement efficient low-level algorithms. 89 |

90 | 91 |

Examples

92 |

An implementation of the fundamental bit utilities is available at https://github.com/vreverdy/bit. Before presenting a wording, we illustrate some of the functionalities of the library.

93 | 94 |

First, std::bit_value and std::bit_reference:

95 |
 96 |   // First, we create an integer
 97 |   using uint_t = unsigned long long int;
 98 |   uint_t intval = 42;                                        // 101010
 99 |   
100 |   // Then we create aligned bit values and a bit references on this integer
101 |   std::bit_value bval0(intval);                              // Creates a bit value from the bit at position 0 of intval
102 |   std::bit_reference<uint_t> bref0(intval);                  // Creates a bit reference from the bit at position 0 of intval
103 | 
104 |   // And unaligned bit values and a bit references on this integer
105 |   std::bit_value bval5(intval, 5);                           // Creates a bit value from the bit at position 5 of intval 
106 |   std::bit_reference<uint_t> bref5(intval, 5);               // Creates a bit reference from the bit at position 5 of intval
107 | 
108 |   // Display them
109 |   std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          // Prints 0011
110 |   
111 |   // Change their values conditionnally
112 |   if (static_cast<bool>(bval5)) {
113 |     bval0.flip();  // Flips the bit without affecting the integer
114 |     bref5.reset(); // Resets the bit to zero and affects the integer
115 |   }
116 |   std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          //  Prints 1010
117 |   
118 |   // Prints the location and the corresponding mask of bit references
119 |   std::cout<<bref0.position()<<" "<<bref0.mask()<<std::endl; // Prints 0 and 1
120 |   std::cout<<bref5.position()<<" "<<bref5.mask()<<std::endl; // Prints 5 and 32
121 | 
122 | 123 |

Then, with std::bit_pointer:

124 |
125 |   // First, we create an array of integers
126 |   using uint_t = unsigned long long int;
127 |   std::array<uint_t, 2> intarr = {42, 314};
128 |   
129 |   // Then we create a bit reference and a bit pointer
130 |   std::bit_reference<uint_t> bref5(intarr[0], 5);            // Creates a bit reference from the bit at position 5 of the first element of the array
131 |   std::bit_pointer<uint_t> bptr(intarr.data());              // Creates a bit pointer from the bit at position 0 of the first element of the array
132 | 
133 |   // We flip the first bit, and sets the second one to 1 with two methods
134 |   bptr->flip();                                              // Flips the bit
135 |   ++bptr;                                                    // Goes to the next bit
136 |   *bptr.set();                                               // Sets the bit
137 |   
138 |   // Then we advance the bit pointer by more than 64 bits and display its position
139 |   bptr += 71;
140 |   std::cout<<bptr->position()<<std::endl;                    // Prints 7 as the bit is now in the second element of the array
141 |   
142 |   // And finally we set the bit pointer to the position of the bit reference
143 |   bptr = &bref5;
144 | 
145 | 146 |

And finally std::bit_iterator, which can serve as a basis of bit algorithm:

147 |
148 |   // First, we create a list of integers
149 |   using uint_t = unsigned short int;
150 |   std::list<uint_t> intlst = {40, 41, 42, 43, 44};
151 |   
152 |   // Then we create a pair of aligned bit iterators
153 |   auto bfirst = std::make_bit_iterator(std::begin(intlst));
154 |   auto bend = std::make_bit_iterator(std::end(intlst));
155 | 
156 |   // Then we count the number of bits set to 1
157 |   auto result = std::count(bfirst, bend, std::bit(1));
158 |   
159 |   // We take a subset of the list
160 |   auto bfirst2 = std::make_bit_iterator(std::begin(intlst), 5);
161 |   auto bend2 = std::make_bit_iterator(std::end(intlst) - 1, 2);
162 |   
163 |   // And we reverse the subset
164 |   std::reverse(bfirst2, bend2);
165 | 
166 | 167 |

The count algorithm can be implemented as:

168 |
169 | // Counts the number of bits equal to the provided bit value
170 | template <class InputIt, class T> 
171 | typename bit_iterator<InputIt>::difference_type
172 | count(
173 |   bit_iterator<InputIt> first, 
174 |   bit_iterator<InputIt> last, 
175 |   const T& value
176 | )
177 | {
178 |   // Initialization
179 |   using underlying_type = typename bit_iterator<InputIt>::underlying_type;
180 |   using difference_type = typename bit_iterator<InputIt>::difference_type;
181 |   constexpr difference_type digits = binary_digits<underlying_type>::value;
182 |   const bit_value input = value;
183 |   difference_type result = 0;
184 |   auto it = first.base();
185 |     
186 |   // Computation when bits belong to several underlying values
187 |   if (first.base() != last.base()) {
188 |     if (first.position() != 0) {
189 |       result = _popcnt(*first.base() >> first.position());
190 |       ++it;
191 |     }
192 |     for (; it != last.base(); ++it) {
193 |       result += _popcnt(*it);
194 |     }
195 |     if (last.position() != 0) {
196 |       result += _popcnt(*last.base() << (digits - last.position()));
197 |     }
198 |   // Computation when bits belong to the same underlying value
199 |   } else {
200 |     result = _popcnt(_bextr(
201 |       *first.base(), 
202 |       static_cast<underlying_type>(first.position()), 
203 |       static_cast<underlying_type>(last.position() - first.position())
204 |     ));
205 |   }
206 |     
207 |   // Negates when the number of zero bits is requested
208 |   if (!static_cast<bool>(input)) {
209 |     result = (last - first) - result;
210 |   }
211 |     
212 |   // Finalization
213 |   return result;
214 | }
215 | 
216 | 217 | As illustrated in these examples, bit utilities act as a convenient interface between high level code that can use bit manipulation through bit iterators, and low level algorithms that can call dedicated instruction sets and compiler intrinsics. 218 | 219 |

Proposed Wording

220 | 221 |

Header <bit>

222 |

223 | Add the following header to the standard: 224 |

225 |
226 | <bit>
227 | 
228 | 229 |

Class std::bit_value

230 | 231 |

232 | Add to the <bit> synopsis: 233 |

234 | 235 |
236 | // Bit value class definition
237 | class bit_value 
238 | {public:
239 |     
240 |   // Types
241 |   using size_type = std::size_t;
242 |     
243 |   // Lifecycle
244 |   bit_value() noexcept = default;
245 |   template <class T> 
246 |   constexpr bit_value(bit_reference<T> val) noexcept;
247 |   template <class UIntType> 
248 |   explicit constexpr bit_value(UIntType val) noexcept;
249 |   template <class UIntType> 
250 |   constexpr bit_value(UIntType val, size_type pos);
251 |     
252 |   // Assignment
253 |   template <class T> 
254 |   bit_value& operator=(bit_reference<T> val) noexcept;
255 |   template <class UIntType> 
256 |   bit_value& operator=(UIntType val) noexcept;
257 | 
258 |   // Conversion
259 |   explicit constexpr operator bool() const noexcept;
260 | 
261 |   // Bit manipulation
262 |   void set(bool b) noexcept;
263 |   void set() noexcept;
264 |   void reset() noexcept;
265 |   void flip() noexcept;
266 | };
267 | 
268 | // Comparison operators
269 | constexpr bool operator==(bit_value lhs, bit_value rhs) noexcept;
270 | constexpr bool operator!=(bit_value lhs, bit_value rhs) noexcept;
271 | constexpr bool operator<(bit_value lhs, bit_value rhs) noexcept;
272 | constexpr bool operator<=(bit_value lhs, bit_value rhs) noexcept;
273 | constexpr bool operator>(bit_value lhs, bit_value rhs) noexcept;
274 | constexpr bool operator>=(bit_value lhs, bit_value rhs) noexcept;
275 | 
276 | // Stream functions
277 | template <class CharT, class Traits>
278 | std::basic_ostream<CharT, Traits>& operator<<(
279 |   std::basic_ostream<CharT, Traits>& os,
280 |   bit_value x
281 | );
282 | template <class CharT, class Traits>
283 | std::basic_istream<CharT, Traits>& operator>>(
284 |   std::basic_istream<CharT, Traits>& is,
285 |   bit_value& x
286 | );
287 |     
288 | // Make functions
289 | template <class T>
290 | constexpr bit_value make_bit_value(T val) noexcept;
291 | template <class T>
292 | constexpr bit_value make_bit_value(
293 |   T val, 
294 |   typename bit_value::size_type pos
295 | );
296 | 
297 | 298 |

Class template std::bit_reference

299 | 300 |

301 | Add to the <bit> synopsis: 302 |

303 | 304 |
305 | // Bit reference class definition
306 | template <class UIntType>
307 | class bit_reference
308 | {public:
309 |     
310 |   // Types
311 |   using underlying_type = UIntType;
312 |   using size_type = std::size_t;
313 | 
314 |   // Lifecycle
315 |   template <class T> 
316 |   constexpr bit_reference(const bit_reference<T>& other) noexcept;
317 |   explicit constexpr bit_reference(underlying_type& ref) noexcept;
318 |   constexpr bit_reference(underlying_type& ref, size_type pos);
319 | 
320 |   // Assignment
321 |   bit_reference& operator=(const bit_reference& other) noexcept;
322 |   template <class T> 
323 |   bit_reference& operator=(const bit_reference<T>& other) noexcept;
324 |   bit_reference& operator=(bit_value val) noexcept;
325 |   bit_reference& operator=(underlying_type val) noexcept;
326 |     
327 |   // Conversion
328 |   explicit constexpr operator bool() const noexcept;
329 | 
330 |   // Access
331 |   constexpr bit_pointer<UIntType> operator&() const noexcept;
332 |     
333 |   // Swap members
334 |   template <class T> 
335 |   void swap(bit_reference<T> other);
336 |   void swap(bit_value& other);
337 | 
338 |   // Bit manipulation
339 |   void set(bool b) noexcept;
340 |   void set() noexcept;
341 |   void reset() noexcept;
342 |   void flip() noexcept;
343 | 
344 |   // Underlying details
345 |   constexpr underlying_type* address() const noexcept;
346 |   constexpr size_type position() const noexcept;
347 |   constexpr underlying_type mask() const noexcept;
348 | };
349 | 
350 | // Swap and exchange
351 | template <class T, class U>
352 | void swap(bit_reference<T> lhs, bit_reference<U> rhs) noexcept;
353 | template <class T>
354 | void swap(bit_reference<T> lhs, bit_value& rhs) noexcept;
355 | template <class U>
356 | void swap(bit_value& lhs, bit_reference<U> rhs) noexcept;
357 | template <class T, class U = bit_value>
358 | bit_value exchange(bit_reference<T> x, U&& val);
359 | 
360 | // Stream functions
361 | template <class CharT, class Traits, class T>
362 | std::basic_ostream<CharT, Traits>& operator<<(
363 |   std::basic_ostream<CharT, Traits>& os,
364 |   bit_reference<T> x
365 | );
366 | template <class CharT, class Traits, class T>
367 | std::basic_istream<CharT, Traits>& operator>>(
368 |   std::basic_istream<CharT, Traits>& is,
369 |   bit_reference<T>& x
370 | );
371 | 
372 | // Make functions
373 | template <class T>
374 | constexpr bit_reference<T> make_bit_reference(T& ref) noexcept;
375 | template <class T>
376 | constexpr bit_reference<T> make_bit_reference(
377 |   T& ref, 
378 |   typename bit_reference<T>::size_type pos
379 | );
380 | 
381 | 382 |

Class template std::bit_pointer

383 | 384 |

385 | Add to the <bit> synopsis: 386 |

387 | 388 |
389 | // Bit pointer class definition
390 | template <class UIntType>
391 | class bit_pointer
392 | {public:
393 |     
394 |   // Types
395 |   using underlying_type = UIntType;
396 |   using size_type = std::size_t;
397 |   using difference_type = std::intmax_t;
398 | 
399 |   // Lifecycle
400 |   bit_pointer() noexcept = default;
401 |   template <class T> 
402 |   constexpr bit_pointer(const bit_pointer<T>& other) noexcept;
403 |   explicit constexpr bit_pointer(std::nullptr_t) noexcept;
404 |   constexpr bit_pointer(std::nullptr_t, size_type);
405 |   explicit constexpr bit_pointer(underlying_type* ptr) noexcept;
406 |   constexpr bit_pointer(underlying_type* ptr, size_type pos);
407 |     
408 |   // Assignment
409 |   bit_pointer& operator=(std::nullptr_t) noexcept;
410 |   bit_pointer& operator=(const bit_pointer& other) noexcept;
411 |   template <class T> 
412 |   bit_pointer& operator=(const bit_pointer<T>& other) noexcept;
413 |   bit_pointer& operator=(underlying_type* ptr) noexcept;
414 |     
415 |   // Conversion
416 |   explicit constexpr operator bool() const noexcept;
417 | 
418 |   // Access
419 |   constexpr bit_reference<UIntType> operator*() const noexcept;
420 |   constexpr bit_reference<UIntType>* operator->() const noexcept;
421 |   constexpr bit_reference<UIntType> operator[](difference_type n) const;
422 |     
423 |   // Increment and decrement operators
424 |   bit_pointer& operator++();
425 |   bit_pointer& operator--();
426 |   bit_pointer operator++(int);
427 |   bit_pointer operator--(int);
428 |   constexpr bit_pointer operator+(difference_type n) const;
429 |   constexpr bit_pointer operator-(difference_type n) const;
430 |   bit_pointer& operator+=(difference_type n);
431 |   bit_pointer& operator-=(difference_type n);
432 | };
433 | 
434 | // Non-member arithmetic operators
435 | template <class T>
436 | constexpr bit_pointer<T> operator+(
437 |   typename bit_pointer<T>::difference_type n,
438 |   bit_pointer<T> x
439 | );
440 | template <class T, class U>
441 | constexpr typename std::common_type<
442 |   typename bit_pointer<T>::difference_type,
443 |   typename bit_pointer<U>::difference_type
444 | >::type operator-(
445 |   bit_pointer<T> lhs,
446 |   bit_pointer<U> rhs
447 | );
448 | 
449 | // Comparison operators
450 | template <class T, class U>
451 | constexpr bool operator==(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
452 | template <class T, class U>
453 | constexpr bool operator!=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
454 | template <class T, class U>
455 | constexpr bool operator<(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
456 | template <class T, class U>
457 | constexpr bool operator<=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
458 | template <class T, class U>
459 | constexpr bool operator>(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
460 | template <class T, class U>
461 | constexpr bool operator>=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
462 | 
463 | // Make functions
464 | template <class T>
465 | constexpr bit_pointer<T> make_bit_pointer(T* ptr) noexcept;
466 | template <class T>
467 | constexpr bit_pointer<T> make_bit_pointer(
468 |   T* ptr, 
469 |   typename bit_pointer<T>::size_type pos
470 | );
471 | 
472 | 473 |

Class template std::bit_iterator

474 | 475 |

476 | Add to the <bit> synopsis: 477 |

478 | 479 |
480 | // Bit iterator class definition
481 | template <class Iterator>
482 | class bit_iterator
483 | {public:
484 |   
485 |   // Types
486 |   using iterator_type = Iterator;
487 |   using underlying_type = typename _cv_iterator_traits<Iterator>::value_type;
488 |   using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
489 |   using value_type = bit_value;
490 |   using difference_type = std::intmax_t;
491 |   using pointer = bit_pointer<underlying_type>;
492 |   using reference = bit_reference<underlying_type>;
493 |   using size_type = std::size_t;
494 | 
495 |   // Lifecycle
496 |   constexpr bit_iterator();
497 |   template <class T> 
498 |   constexpr bit_iterator(const bit_iterator<T>& other);
499 |   explicit constexpr bit_iterator(iterator_type i);
500 |   constexpr bit_iterator(iterator_type i, size_type pos);
501 | 
502 |   // Assignment
503 |   template <class T>
504 |   bit_iterator& operator=(const bit_iterator<T>& other);
505 |   bit_iterator& operator=(iterator_type i);
506 | 
507 |   // Access
508 |   constexpr reference operator*() const noexcept;
509 |   constexpr pointer operator->() const noexcept;
510 |   constexpr reference operator[](difference_type n) const;
511 | 
512 |   // Increment and decrement operators
513 |   bit_iterator& operator++();
514 |   bit_iterator& operator--();
515 |   bit_iterator operator++(int);
516 |   bit_iterator operator--(int);
517 |   constexpr bit_iterator operator+(difference_type n) const;
518 |   constexpr bit_iterator operator-(difference_type n) const;
519 |   bit_iterator& operator+=(difference_type n);
520 |   bit_iterator& operator-=(difference_type n);
521 | 
522 |   // Underlying details
523 |   constexpr iterator_type base() const;
524 |   constexpr size_type position() const noexcept;
525 |   constexpr underlying_type mask() const noexcept;
526 | };
527 | 
528 | // Non-member arithmetic operators
529 | template <class T>
530 | constexpr bit_iterator<T> operator+(
531 |   typename bit_iterator<T>::difference_type n,
532 |   const bit_iterator<T>& i
533 | );
534 | template <class T, class U>
535 | constexpr typename std::common_type<
536 |   typename bit_iterator<T>::difference_type,
537 |   typename bit_iterator<U>::difference_type
538 | >::type operator-(
539 |   const bit_iterator<T>& lhs,
540 |   const bit_iterator<U>& rhs
541 | );
542 | 
543 | // Comparison operators
544 | template <class T, class U>
545 | constexpr bool operator==(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
546 | template <class T, class U>
547 | constexpr bool operator!=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
548 | template <class T, class U>
549 | constexpr bool operator<(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
550 | template <class T, class U>
551 | constexpr bool operator<=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
552 | template <class T, class U>
553 | constexpr bool operator>(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
554 | template <class T, class U>
555 | constexpr bool operator>=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
556 | 
557 | // Make functions
558 | template <class T>
559 | constexpr bit_iterator<T> make_bit_iterator(T i);
560 | template <class T>
561 | constexpr bit_iterator<T> make_bit_iterator(
562 |   T i,
563 |   typename bit_iterator<T>::size_type pos
564 | );
565 | 
566 | 567 |

Helper struct std::binary_digits

568 | 569 |

570 | Add to the <bit> synopsis: 571 |

572 | 573 |
574 | // Binary digits structure definition
575 | template <class UIntType>
576 | struct binary_digits 
577 | : std::integral_constant<std::size_t, std::numeric_limits<UIntType>::digits> 
578 | {};
579 | 
580 | 581 |

Acknowledgements

582 | The authors would like to thank Howard Hinnant, Jens Maurer, Tony Van Eerd, Klemens Morgenstern, Vicente Botet Escriba, Tomasz Kaminski, Odin Holmes and the other contributors of the ISO C++ Standard - Discussion and of the ISO C++ Standard - Future Proposals groups for their initial reviews and comments. 583 | 584 | Vincent Reverdy and Robert J. Brunner have been supported by the National Science Foundation Grant AST-1313415. Robert J. Brunner has been supported in part by the Center for Advanced Studies at the University of Illinois. 585 | 586 | 587 | 588 | -------------------------------------------------------------------------------- /doc/wg21/2016_06_oulu/p0237r1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Wording for fundamental bit manipulation utilities 5 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
Document number:D0237R1
Date:2016-06-23
Project:ISO JTC1/SC22/WG21: Programming Language C++
Audience:LEWG, SG14, SG6
Reply to:Vincent Reverdy <vince.rev@gmail.com>
Robert J. Brunner
Nathan Myers
55 | 56 |
57 | 58 |

Wording for fundamental bit manipulation utilities

59 | 60 |
61 | 62 |

Table of Contents

63 | 71 | 72 |
73 | 74 |

History and feedback

75 |

The idea of bit manipulation utilities has been originally proposed in the 2016 pre-Jacksonville mailing and has been discussed in both SG6 and LEWG in Jacksonville. The original document, P0237R0 fully describes and discusses the idea of fundamental bit manipulation utilities for the C++ language. Another proposal, P0161R0 had the same motivations but was focusing on bitsets. As P0237R0 seemed more generic and not restrained to the scope of std::bitset, we decided to push forward P0237R0, while still keeping in mind the functionalities and performances allowed by P0161R0. The genericity and abstraction offered by P0237R0 should not introduce a performance overhead (at least with the -O2 optimization level on most compilers) when compared to P0161R0 and N3864.

76 | 77 |

The feedback from the Jacksonville meeting was positive: in top of their intrinsics functionalities, bit manipulation utilities have the potential to serve as a common basis for a std::dynamic_bitset replacement of std::vector<bool> and for bounded and unbounded precision arithmetic as discussed in N4038.

78 | 79 |

In terms of design, the following guidance was given by LEWG: 80 |

    81 |
  • Restrain std::bit_reference to unsigned fundamental integer types? 82 | [SF: 6, F: 3, N: 0, A: 0, SA :0]
  • 83 |
  • std::bit_reference provides no arithmetic except what the paper provides explicitly? [Unanimous consent]
  • 84 |
  • In small discussion groups, introducing std::bit_value was considered to be good idea
  • 85 |
86 |

87 | 88 |

In Jacksonville, the following questions were raised:

89 |
    90 |
  • How to deal with word endianness?
  • 91 |
  • How to provide the possibility to get a mask from the bit position?
  • 92 |
  • How to deal with infinite ranges of bits, particularly for unbounded precision arithmetic?
  • 93 |
  • What bitwise logic operators should bits provide?
  • 94 |
  • How to make std::bit_iterator compatible with proxy iterators presented in P0022R1?
  • 95 |
96 |

97 | 98 | If bit utilities make it to the standard, they will be used, at least, as the basis for an implementation of a dynamic bitset, and are likely to be used as an interface to the underlying containers of words for unbounded and bounded precision arithmetic. 99 | 100 |
101 | 102 |

Introduction

103 |

104 | This paper proposes a wording for fundamental bit utilities: std::bit_value, std::bit_reference, std::bit_pointer and std::bit_iterator. An in-depth discussion of the motivations and an in-depth exploration of the design space can be found in P0237R0. In short, this paper proposes a set of 4 main utility classes to serve as bit abstractions in order to offer a common and standardized interface for libraries and programs that require bit manipulations. These bit utilities both emulate bits that are easy to use for users, and provide an interface to access the underlying words to implement efficient low-level algorithms. 105 |

106 | 107 |

Examples

108 |

An implementation of the fundamental bit utilities is available at https://github.com/vreverdy/bit. Before presenting a wording, we illustrate some of the functionalities of the library.

109 | 110 |

First, std::bit_value and std::bit_reference:

111 |
 112 |   // First, we create an integer
 113 |   using uint_t = unsigned long long int;
 114 |   uint_t intval = 42;                                        // 101010
 115 |   
 116 |   // Then we create aligned bit values and a bit references on this integer
 117 |   std::bit_value bval0(intval);                              // Creates a bit value from the bit at position 0 of intval
 118 |   std::bit_reference<uint_t> bref0(intval);                  // Creates a bit reference from the bit at position 0 of intval
 119 | 
 120 |   // And unaligned bit values and a bit references on this integer
 121 |   std::bit_value bval5(intval, 5);                           // Creates a bit value from the bit at position 5 of intval 
 122 |   std::bit_reference<uint_t> bref5(intval, 5);               // Creates a bit reference from the bit at position 5 of intval
 123 | 
 124 |   // Display them
 125 |   std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          // Prints 0011
 126 |   
 127 |   // Change their values conditionnally
 128 |   if (static_cast<bool>(bval5)) {
 129 |     bval0.flip();  // Flips the bit without affecting the integer
 130 |     bref5.reset(); // Resets the bit to zero and affects the integer
 131 |   }
 132 |   std::cout<<bval0<<bref0<<bval5<<bref5<<std::endl;          //  Prints 1010
 133 |   
 134 |   // Prints the location and the corresponding mask of bit references
 135 |   std::cout<<bref0.position()<<" "<<bref0.mask()<<std::endl; // Prints 0 and 1
 136 |   std::cout<<bref5.position()<<" "<<bref5.mask()<<std::endl; // Prints 5 and 32
 137 | 
138 | 139 |

Then, with std::bit_pointer:

140 |
 141 |   // First, we create an array of integers
 142 |   using uint_t = unsigned long long int;
 143 |   std::array<uint_t, 2> intarr = {42, 314};
 144 |   
 145 |   // Then we create a bit reference and a bit pointer
 146 |   std::bit_reference<uint_t> bref5(intarr[0], 5);            // Creates a bit reference from the bit at position 5 of the first element of the array
 147 |   std::bit_pointer<uint_t> bptr(intarr.data());              // Creates a bit pointer from the bit at position 0 of the first element of the array
 148 | 
 149 |   // We flip the first bit, and sets the second one to 1 with two methods
 150 |   bptr->flip();                                              // Flips the bit
 151 |   ++bptr;                                                    // Goes to the next bit
 152 |   *bptr.set();                                               // Sets the bit
 153 |   
 154 |   // Then we advance the bit pointer by more than 64 bits and display its position
 155 |   bptr += 71;
 156 |   std::cout<<bptr->position()<<std::endl;                    // Prints 7 as the bit is now in the second element of the array
 157 |   
 158 |   // And finally we set the bit pointer to the position of the bit reference
 159 |   bptr = &bref5;
 160 | 
161 | 162 |

And finally std::bit_iterator, which can serve as a basis of bit algorithm:

163 |
 164 |   // First, we create a list of integers
 165 |   using uint_t = unsigned short int;
 166 |   std::list<uint_t> intlst = {40, 41, 42, 43, 44};
 167 |   
 168 |   // Then we create a pair of aligned bit iterators
 169 |   auto bfirst = std::make_bit_iterator(std::begin(intlst));
 170 |   auto bend = std::make_bit_iterator(std::end(intlst));
 171 | 
 172 |   // Then we count the number of bits set to 1
 173 |   auto result = std::count(bfirst, bend, std::bit(1));
 174 |   
 175 |   // We take a subset of the list
 176 |   auto bfirst2 = std::make_bit_iterator(std::begin(intlst), 5);
 177 |   auto bend2 = std::make_bit_iterator(std::end(intlst) - 1, 2);
 178 |   
 179 |   // And we reverse the subset
 180 |   std::reverse(bfirst2, bend2);
 181 | 
182 | 183 |

The count algorithm can be implemented as:

184 |
 185 | // Counts the number of bits equal to the provided bit value
 186 | template <class InputIt, class T> 
 187 | typename bit_iterator<InputIt>::difference_type
 188 | count(
 189 |   bit_iterator<InputIt> first, 
 190 |   bit_iterator<InputIt> last, 
 191 |   const T& value
 192 | )
 193 | {
 194 |   // Initialization
 195 |   using underlying_type = typename bit_iterator<InputIt>::underlying_type;
 196 |   using difference_type = typename bit_iterator<InputIt>::difference_type;
 197 |   constexpr difference_type digits = binary_digits<underlying_type>::value;
 198 |   const bit_value input = value;
 199 |   difference_type result = 0;
 200 |   auto it = first.base();
 201 |     
 202 |   // Computation when bits belong to several underlying values
 203 |   if (first.base() != last.base()) {
 204 |     if (first.position() != 0) {
 205 |       result = _popcnt(*first.base() >> first.position());
 206 |       ++it;
 207 |     }
 208 |     for (; it != last.base(); ++it) {
 209 |       result += _popcnt(*it);
 210 |     }
 211 |     if (last.position() != 0) {
 212 |       result += _popcnt(*last.base() << (digits - last.position()));
 213 |     }
 214 |   // Computation when bits belong to the same underlying value
 215 |   } else {
 216 |     result = _popcnt(_bextr(
 217 |       *first.base(), 
 218 |       static_cast<underlying_type>(first.position()), 
 219 |       static_cast<underlying_type>(last.position() - first.position())
 220 |     ));
 221 |   }
 222 |     
 223 |   // Negates when the number of zero bits is requested
 224 |   if (!static_cast<bool>(input)) {
 225 |     result = (last - first) - result;
 226 |   }
 227 |     
 228 |   // Finalization
 229 |   return result;
 230 | }
 231 | 
232 | 233 | As illustrated in these examples, bit utilities act as a convenient interface between high level code that can use bit manipulation through bit iterators, and low level algorithms that can call dedicated instruction sets and compiler intrinsics. 234 | 235 |
236 | 237 |

Proposed Wording

238 | 239 |
240 | 241 |

Header <bit>

242 |

243 | Add the following header to the standard: 244 |

245 |
 246 | <bit>
 247 | 
248 | 249 |
250 | 251 |

Class std::bit_value

252 | 253 |

254 | Add to the <bit> synopsis: 255 |

256 | 257 |
 258 | // Bit value class definition
 259 | class bit_value
 260 | {public:
 261 |     
 262 |   // Types
 263 |   using size_type = std::size_t;
 264 |     
 265 |   // Lifecycle
 266 |   bit_value() noexcept = default;
 267 |   template <class T> 
 268 |   constexpr bit_value(bit_reference<T> val) noexcept;
 269 |   template <class UIntType>
 270 |   explicit constexpr bit_value(UIntType val) noexcept;
 271 |   template <class UIntType> 
 272 |   constexpr bit_value(UIntType val, size_type pos);
 273 |     
 274 |   // Assignment
 275 |   template <class T> 
 276 |   bit_value& operator=(bit_reference<T> val) noexcept;
 277 |   template <class UIntType> 
 278 |   bit_value& operator=(UIntType val) noexcept;
 279 | 
 280 |   // Conversion
 281 |   explicit constexpr operator bool() const noexcept;
 282 | 
 283 |   // Bit manipulation
 284 |   void set(bool b) noexcept;
 285 |   void set() noexcept;
 286 |   void reset() noexcept;
 287 |   void flip() noexcept;
 288 | };
 289 | 
 290 | // Comparison operators
 291 | constexpr bool operator==(bit_value lhs, bit_value rhs) noexcept;
 292 | constexpr bool operator!=(bit_value lhs, bit_value rhs) noexcept;
 293 | constexpr bool operator<(bit_value lhs, bit_value rhs) noexcept;
 294 | constexpr bool operator<=(bit_value lhs, bit_value rhs) noexcept;
 295 | constexpr bool operator>(bit_value lhs, bit_value rhs) noexcept;
 296 | constexpr bool operator>=(bit_value lhs, bit_value rhs) noexcept;
 297 | 
 298 | // Stream functions
 299 | template <class CharT, class Traits>
 300 | std::basic_ostream<CharT, Traits>& operator<<(
 301 |   std::basic_ostream<CharT, Traits>& os,
 302 |   bit_value x
 303 | );
 304 | template <class CharT, class Traits>
 305 | std::basic_istream<CharT, Traits>& operator>>(
 306 |   std::basic_istream<CharT, Traits>& is,
 307 |   bit_value& x
 308 | );
 309 |     
 310 | // Make functions
 311 | template <class T>
 312 | constexpr bit_value make_bit_value(T val) noexcept;
 313 | template <class T>
 314 | constexpr bit_value make_bit_value(
 315 |   T val, 
 316 |   typename bit_value::size_type pos
 317 | );
 318 | 
319 | 320 |

Lifecycle

321 |

322 | bit_value() noexcept = default;
323 | Effects: Constructs the bit value without initializing its value. 324 |

325 |

326 | template <class T> constexpr bit_value(bit_reference<T> val) noexcept;
327 | Effects: Constructs the bit value from the value of a bit reference. 328 |

329 |

330 | template <class UIntType> explicit constexpr bit_value(UIntType val) noexcept;
331 | Requires: std::binary_digits<UIntType>::value should exist and be strictly positive.
332 | Effects: Constructs the bit value from the bit at position 0 of val as in static_cast<bool>(val & static_cast<UIntType>(1)). 333 |

334 |

335 | template <class UIntType> constexpr bit_value(UIntType val, size_type pos);
336 | Requires: std::binary_digits<UIntType>::value should exist, be strictly positive and pos should verify pos < std::binary_digits<UIntType>::value.
337 | Effects: Constructs the bit value from the bit at position pos of val as in static_cast<bool>((val >> pos) & static_cast<UIntType>(1)).
338 | Remarks: For unsigned integral types, static_cast<bool>((val >> pos) & static_cast<UIntType>(1)) is equivalent to static_cast<bool>(val & (static_cast<UIntType>(1) << pos)) for pos < std::binary_digits<UIntType>::value. 339 |

340 | 341 |

Assignment

342 |

343 | template <class T> bit_value& operator=(bit_reference<T> val) noexcept;
344 | Effects: Assigns a bit reference to the bit value.
345 | Returns: *this. 346 |

347 |

348 | template <class UIntType> bit_value& operator=(UIntType val) noexcept;
349 | Requires: std::binary_digits<UIntType>::value should exist and be strictly positive.
350 | Effects: Assigns the bit at position 0 of val as in static_cast<bool>(val & static_cast<UIntType>(1)) to the bit value.
351 | Returns: *this. 352 |

353 | 354 |

Conversion

355 |

356 | explicit constexpr operator bool() const noexcept;
357 | Effects: Explicitly converts the bit value to a boolean value. 358 |

359 | 360 |

Bit manipulation

361 |

362 | void set(bool b) noexcept;
363 | Effects: Assigns b to the bit value. 364 |

365 |

366 | void set() noexcept;
367 | Effects: Unconditionally sets the bit value to 1. 368 |

369 |

370 | void reset() noexcept;
371 | Effects: Unconditionally resets the bit value to 0. 372 |

373 |

374 | void flip() noexcept;
375 | Effects: Flips the bit value, 0 becoming 1 and 1 becoming 0. 376 |

377 | 378 |

Comparison operators

379 |

380 | constexpr bool operator==(bit_value lhs, bit_value rhs) noexcept;
381 | constexpr bool operator!=(bit_value lhs, bit_value rhs) noexcept;
382 | constexpr bool operator<(bit_value lhs, bit_value rhs) noexcept;
383 | constexpr bool operator<=(bit_value lhs, bit_value rhs) noexcept;
384 | constexpr bool operator>(bit_value lhs, bit_value rhs) noexcept;
385 | constexpr bool operator>=(bit_value lhs, bit_value rhs) noexcept;
386 | Effects: Compares two bit values.
387 | Returns: The boolean value of the comparison.
388 | Remarks: Bit references get compared through these operators using implicit conversions to bit values. 389 |

390 | 391 |

Stream functions

392 |

393 | template <class CharT, class Traits> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, bit_value x);
394 | Effects: Outputs the bit value to the stream in a form equivalent to os << static_cast<int>(static_cast<bool>(x)).
395 | Returns: The updated stream. 396 |

397 |

398 | template <class CharT, class Traits> std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, bit_value& x);
399 | Effects: Reads the next character from the input stream and sets the bit value accordingly if this caracter is 0 or 1. The behaviour is undefined otherwise.
400 | Returns: The updated stream. 401 |

402 | 403 |

Make functions

404 |

405 | template <class T> constexpr bit_value make_bit_value(T val) noexcept;
406 | Requires: std::binary_digits<T>::value should exist and be strictly positive.
407 | Effects: Constructs a bit value from the bit at position 0 of val as in static_cast<bool>(val & static_cast<T>(1)).
408 | Returns: The resulting bit value. 409 |

410 |

411 | template <class T> constexpr bit_value make_bit_value(T val, typename bit_value::size_type pos);
412 | Requires: std::binary_digits<T>::value should exist, be strictly positive and pos should verify pos < std::binary_digits<T>::value.
413 | Effects: Constructs a bit value from the bit at position pos of val as in static_cast<bool>((val >> pos) & static_cast<T>(1)).
414 | Returns: The resulting bit value.
415 | Remarks: For unsigned integral types, static_cast<bool>((val >> pos) & static_cast<T>(1)) is equivalent to static_cast<bool>(val & (static_cast<T>(1) << pos)) for pos < std::binary_digits<T>::value. 416 |

417 | 418 |
419 | 420 |

Class template std::bit_reference

421 | 422 |

423 | Add to the <bit> synopsis: 424 |

425 | 426 |
 427 | // Bit reference class definition
 428 | template <class UIntType>
 429 | class bit_reference
 430 | {public:
 431 |     
 432 |   // Types
 433 |   using underlying_type = UIntType;
 434 |   using size_type = std::size_t;
 435 | 
 436 |   // Lifecycle
 437 |   template <class T> 
 438 |   constexpr bit_reference(const bit_reference<T>& other) noexcept;
 439 |   explicit constexpr bit_reference(underlying_type& ref) noexcept;
 440 |   constexpr bit_reference(underlying_type& ref, size_type pos);
 441 | 
 442 |   // Assignment
 443 |   bit_reference& operator=(const bit_reference& other) noexcept;
 444 |   template <class T> 
 445 |   bit_reference& operator=(const bit_reference<T>& other) noexcept;
 446 |   bit_reference& operator=(bit_value val) noexcept;
 447 |   bit_reference& operator=(underlying_type val) noexcept;
 448 |     
 449 |   // Conversion
 450 |   explicit constexpr operator bool() const noexcept;
 451 | 
 452 |   // Access
 453 |   constexpr bit_pointer<UIntType> operator&() const noexcept;
 454 |     
 455 |   // Swap members
 456 |   template <class T> 
 457 |   void swap(bit_reference<T> other);
 458 |   void swap(bit_value& other);
 459 | 
 460 |   // Bit manipulation
 461 |   void set(bool b) noexcept;
 462 |   void set() noexcept;
 463 |   void reset() noexcept;
 464 |   void flip() noexcept;
 465 | 
 466 |   // Underlying details
 467 |   constexpr underlying_type* address() const noexcept;
 468 |   constexpr size_type position() const noexcept;
 469 |   constexpr underlying_type mask() const noexcept;
 470 | };
 471 | 
 472 | // Swap and exchange
 473 | template <class T, class U>
 474 | void swap(bit_reference<T> lhs, bit_reference<U> rhs) noexcept;
 475 | template <class T>
 476 | void swap(bit_reference<T> lhs, bit_value& rhs) noexcept;
 477 | template <class U>
 478 | void swap(bit_value& lhs, bit_reference<U> rhs) noexcept;
 479 | template <class T, class U = bit_value>
 480 | bit_value exchange(bit_reference<T> x, U&& val);
 481 | 
 482 | // Stream functions
 483 | template <class CharT, class Traits, class T>
 484 | std::basic_ostream<CharT, Traits>& operator<<(
 485 |   std::basic_ostream<CharT, Traits>& os,
 486 |   bit_reference<T> x
 487 | );
 488 | template <class CharT, class Traits, class T>
 489 | std::basic_istream<CharT, Traits>& operator>>(
 490 |   std::basic_istream<CharT, Traits>& is,
 491 |   bit_reference<T>& x
 492 | );
 493 | 
 494 | // Make functions
 495 | template <class T>
 496 | constexpr bit_reference<T> make_bit_reference(T& ref) noexcept;
 497 | template <class T>
 498 | constexpr bit_reference<T> make_bit_reference(
 499 |   T& ref, 
 500 |   typename bit_reference<T>::size_type pos
 501 | );
 502 | 
503 | 504 | Requires: std::binary_digits<UIntType>::value should exist and be strictly positive.
505 | 506 |

Lifecycle

507 |

508 | template <class T> constexpr bit_reference(const bit_reference<T>& other) noexcept;
509 | Effects: Constructs the bit reference from a bit reference on another type T.
510 | Remarks: The main usage of this constructor is when T is the same as UIntType, but differently cv-qualified. 511 |

512 |

513 | explicit constexpr bit_reference(underlying_type& ref) noexcept;
514 | Effects: Constructs the bit reference by referencing the bit at position 0 of ref as in static_cast<bool>(ref & static_cast<UIntType>(1)). 515 |

516 |

517 | constexpr bit_reference(underlying_type& ref, size_type pos);
518 | Requires: pos should verify pos < std::binary_digits<UIntType>::value.
519 | Effects: Constructs the bit reference by referencing the bit at position pos of ref as in static_cast<bool>((ref >> pos) & static_cast<UIntType>(1)).
520 | Remarks: For unsigned integral types, static_cast<bool>((ref >> pos) & static_cast<UIntType>(1)) is equivalent to static_cast<bool>(ref & (static_cast<UIntType>(1) << pos)) for pos < std::binary_digits<UIntType>::value. 521 |

522 | 523 |

Assignment

524 |

525 | bit_reference& operator=(const bit_reference& other) noexcept;
526 | Effects: Copy assigns from the value of the bit referenced in other.
527 | Returns: *this.
528 | Remarks: The behaviour is different than what a default copy assignment would be: the value of the other bit is copied, not the reference itself. 529 |

530 |

531 | template <class T> bit_reference& operator=(const bit_reference<T>& other) noexcept;
532 | Effects: Copy assigns from the value of the bit referenced in other.
533 | Returns: *this. 534 | Remarks: The main usage of this assignment operator is when T is the same as UIntType, but differently cv-qualified. 535 |

536 |

537 | bit_reference& operator=(bit_value val) noexcept;
538 | Effects: Assigns the value of the bit val to the referenced bit.
539 | Returns: *this. 540 |

541 |

542 | bit_reference& operator=(underlying_type val) noexcept;
543 | Effects: Assigns the bit at position 0 of val as in static_cast<bool>(val & static_cast<UIntType>(1)) to the referenced bit.
544 | Returns: *this. 545 |

546 | 547 |

Conversion

548 |

549 | explicit constexpr operator bool() const noexcept;
550 | Effects: Explicitly converts the bit value to a boolean value. 551 |

552 | 553 |

Access

554 |

555 | constexpr bit_pointer<UIntType> operator&() const noexcept;
556 | Returns: A bit pointer pointing to the referenced bit. 557 |

558 | 559 |

Swap members

560 |

561 | template <class T> void swap(bit_reference<T> other);
562 | void swap(bit_value& other);
563 | Effects: Swaps the value of the referenced bit with the value of the other bit. 564 |

565 | 566 |

Bit manipulation

567 |

568 | void set(bool b) noexcept;
569 | Effects: Assigns b to the referenced bit. 570 |

571 |

572 | void set() noexcept;
573 | Effects: Unconditionally sets the referenced bit to 1. 574 |

575 |

576 | void reset() noexcept;
577 | Effects: Unconditionally resets the referenced bit to 0. 578 |

579 |

580 | void flip() noexcept;
581 | Effects: Flips the referenced bit, 0 becoming 1 and 1 becoming 0. 582 |

583 | 584 |

Underlying details

585 |

586 | constexpr underlying_type* address() const noexcept;
587 | Returns: A pointer to the object in which the referenced bit is. 588 |

589 |

590 | constexpr size_type position() const noexcept;
591 | Returns: The position of the referenced bit in the underlying object.
592 | Remarks: The position verifies pos >= 0 and pos < std::binary_digits<UIntType>::value. 593 |

594 |

595 | constexpr underlying_type mask() const noexcept;
596 | Returns: A mask of underlying_type in which the bit at position pos is set to 1. The mask is equivalent to static_cast<UIntType>(1) << pos. 597 |

598 | 599 |

Swap and exchange

600 |

601 | template <class T, class U> void swap(bit_reference<T> lhs, bit_reference<U> rhs) noexcept;
602 | template <class T> void swap(bit_reference<T> lhs, bit_value& rhs) noexcept;
603 | template <class U> void swap(bit_value& lhs, bit_reference<U> rhs) noexcept;
604 | Effects: Swaps the value of the passed bits. 605 |

606 |

607 | template <class T, class U = bit_value> bit_value exchange(bit_reference<T> x, U&& val);
608 | Effects: Replaces the value of x with val and returns the old value of x.
609 | Remarks: This function is an overload of std::exchange so that it performs the correct operation when operating on bits.
610 |

611 | 612 |

Stream functions

613 |

614 | template <class CharT, class Traits, class T> std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, bit_reference<T> x);
615 | Effects: Outputs the referenced bit to the stream in a form equivalent to os << static_cast<int>(static_cast<bool>(x)).
616 | Returns: The updated stream. 617 |

618 |

619 | template <class CharT, class Traits, class T> std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, bit_reference<T>& x);
620 | Effects: Reads the next character from the input stream and sets the referenced bit accordingly if this caracter is 0 or 1. The behaviour is undefined otherwise.
621 | Returns: The updated stream. 622 |

623 | 624 |

Make functions

625 |

626 | template <class T> constexpr bit_reference<T> make_bit_reference(T& ref) noexcept;
627 | Requires: std::binary_digits<T>::value should exist and be strictly positive.
628 | Effects: Constructs a bit reference ce from the bit at position 0 of ref as in static_cast<bool>(ref & static_cast<T>(1)).
629 | Returns: The resulting bit reference. 630 |

631 |

632 | template <class T> constexpr bit_reference<T> make_bit_reference(T& ref, typename bit_reference<T>::size_type pos);
633 | Requires: std::binary_digits<T>::value should exist, be strictly positive and pos should verify pos < std::binary_digits<T>::value.
634 | Effects: Constructs a bit reference from the bit at position pos of ref as in static_cast<bool>((ref >> pos) & static_cast<T>(1)).
635 | Returns: The resulting bit reference.
636 | Remarks: For unsigned integral types, static_cast<bool>((ref >> pos) & static_cast<T>(1)) is equivalent to static_cast<bool>(ref & (static_cast<T>(1) << pos)) for pos < std::binary_digits<T>::value. 637 |

638 | 639 |
640 | 641 |

Class template std::bit_pointer

642 | 643 |

644 | Add to the <bit> synopsis: 645 |

646 | 647 |
 648 | // Bit pointer class definition
 649 | template <class UIntType>
 650 | class bit_pointer
 651 | {public:
 652 |     
 653 |   // Types
 654 |   using underlying_type = UIntType;
 655 |   using size_type = std::size_t;
 656 |   using difference_type = std::intmax_t;
 657 | 
 658 |   // Lifecycle
 659 |   bit_pointer() noexcept = default;
 660 |   template <class T> 
 661 |   constexpr bit_pointer(const bit_pointer<T>& other) noexcept;
 662 |   explicit constexpr bit_pointer(std::nullptr_t) noexcept;
 663 |   constexpr bit_pointer(std::nullptr_t, size_type);
 664 |   explicit constexpr bit_pointer(underlying_type* ptr) noexcept;
 665 |   constexpr bit_pointer(underlying_type* ptr, size_type pos);
 666 |     
 667 |   // Assignment
 668 |   bit_pointer& operator=(std::nullptr_t) noexcept;
 669 |   bit_pointer& operator=(const bit_pointer& other) noexcept;
 670 |   template <class T> 
 671 |   bit_pointer& operator=(const bit_pointer<T>& other) noexcept;
 672 |   bit_pointer& operator=(underlying_type* ptr) noexcept;
 673 |     
 674 |   // Conversion
 675 |   explicit constexpr operator bool() const noexcept;
 676 | 
 677 |   // Access
 678 |   constexpr bit_reference<UIntType> operator*() const noexcept;
 679 |   constexpr bit_reference<UIntType>* operator->() const noexcept;
 680 |   constexpr bit_reference<UIntType> operator[](difference_type n) const;
 681 |     
 682 |   // Increment and decrement operators
 683 |   bit_pointer& operator++();
 684 |   bit_pointer& operator--();
 685 |   bit_pointer operator++(int);
 686 |   bit_pointer operator--(int);
 687 |   constexpr bit_pointer operator+(difference_type n) const;
 688 |   constexpr bit_pointer operator-(difference_type n) const;
 689 |   bit_pointer& operator+=(difference_type n);
 690 |   bit_pointer& operator-=(difference_type n);
 691 | };
 692 | 
 693 | // Non-member arithmetic operators
 694 | template <class T>
 695 | constexpr bit_pointer<T> operator+(
 696 |   typename bit_pointer<T>::difference_type n,
 697 |   bit_pointer<T> x
 698 | );
 699 | template <class T, class U>
 700 | constexpr typename std::common_type<
 701 |   typename bit_pointer<T>::difference_type,
 702 |   typename bit_pointer<U>::difference_type
 703 | >::type operator-(
 704 |   bit_pointer<T> lhs,
 705 |   bit_pointer<U> rhs
 706 | );
 707 | 
 708 | // Comparison operators
 709 | template <class T, class U>
 710 | constexpr bool operator==(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 711 | template <class T, class U>
 712 | constexpr bool operator!=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 713 | template <class T, class U>
 714 | constexpr bool operator<(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 715 | template <class T, class U>
 716 | constexpr bool operator<=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 717 | template <class T, class U>
 718 | constexpr bool operator>(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 719 | template <class T, class U>
 720 | constexpr bool operator>=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
 721 | 
 722 | // Make functions
 723 | template <class T>
 724 | constexpr bit_pointer<T> make_bit_pointer(T* ptr) noexcept;
 725 | template <class T>
 726 | constexpr bit_pointer<T> make_bit_pointer(
 727 |   T* ptr, 
 728 |   typename bit_pointer<T>::size_type pos
 729 | );
 730 | 
731 | 732 | Requires: std::binary_digits<UIntType>::value should exist and be strictly positive.
733 | 734 |

Lifecycle

735 |

736 | bit_pointer() noexcept = default;
737 | Effects: Constructs the bit pointer leaving it uninitialized. 738 |

739 |

740 | template <class T> constexpr bit_pointer(const bit_pointer<T>& other) noexcept;
741 | Effects: Constructs the bit pointer from a bit pointer on another type T.
742 | Remarks: The main usage of this constructor is when T is the same as UIntType, but differently cv-qualified. 743 |

744 |

745 | explicit constexpr bit_pointer(std::nullptr_t) noexcept;
746 | Effects: Constructs a null bit pointer with position 0. 747 |

748 |

749 | constexpr bit_pointer(std::nullptr_t, size_type);
750 | Effects: Constructs a null bit pointer with a non-zero position 0. 751 |

752 |

753 | explicit constexpr bit_pointer(underlying_type* ptr) noexcept;
754 | Effects: Constructs the bit pointer by pointing to the bit at position 0 of ptr as in static_cast<bool>(*ptr & static_cast<UIntType>(1)). 755 |

756 |

757 | constexpr bit_pointer(underlying_type* ptr, size_type pos);
758 | Requires: pos should verify pos < std::binary_digits<UIntType>::value.
759 | Effects: Constructs the bit pointer by pointing to the bit at position pos of *ptr as in static_cast<bool>((*ptr >> pos) & static_cast<UIntType>(1)).
760 | Remarks: For unsigned integral types, static_cast<bool>((*ptr >> pos) & static_cast<UIntType>(1)) is equivalent to static_cast<bool>(*ptr & (static_cast<UIntType>(1) << pos)) for pos < std::binary_digits<UIntType>::value. 761 |

762 | 763 |

Assignment

764 |

765 | bit_pointer& operator=(std::nullptr_t) noexcept;
766 | Effects: Sets the bit pointer to a null bit pointer with position 0. 767 | Returns: *this. 768 |

769 |

770 | bit_pointer& operator=(const bit_pointer& other) noexcept;
771 | Effects: Copy assigns from the other bit pointer.
772 | Returns: *this. 773 |

774 |

775 | template <class T> bit_pointer& operator=(const bit_pointer<T>& other) noexcept;
776 | Effects: Copy assigns from the other bit pointer.
777 | Returns: *this. 778 |

779 |

780 | bit_pointer& operator=(underlying_type* ptr) noexcept;
781 | Effects: Assigns a bit pointer pointing to the bit at position 0 of ptr as in static_cast<bool>(*ptr & static_cast<UIntType>(1)) to the bit pointer.
782 | Returns: *this. 783 |

784 | 785 |

Conversion

786 |

787 | explicit constexpr operator bool() const noexcept;
788 | Effects: Returns false if the underlying pointer is null and the position is 0, returns true otherwise. 789 |

790 | 791 |

Access

792 |

793 | constexpr bit_reference<UIntType> operator*() const noexcept;
794 | Returns: A bit reference referencing the pointed bit. 795 |

796 |

797 | constexpr bit_reference<UIntType>* operator->() const noexcept;
798 | Returns: A pointer to a bit reference referencing the pointed bit. 799 |

800 |

801 | constexpr bit_reference<UIntType> operator[](difference_type n) const;
802 | Returns: A bit reference referencing the n-th bit after the pointed bit.
803 | Remarks: In that context, if pos + 1 < std::binary_digits<UIntType>::value, the next bit is the bit at pos + 1 in the same underlying object, but if pos + 1 == std::binary_digits<UIntType>::value, the next bit is the bit at position 0 of the next underlying object in memory. 804 |

805 | 806 |

Increment and decrement operators

807 |

808 | bit_pointer& operator++();
809 | bit_pointer& operator--();
810 | bit_pointer operator++(int);
811 | bit_pointer operator--(int);
812 | constexpr bit_pointer operator+(difference_type n) const;
813 | constexpr bit_pointer operator-(difference_type n) const;
814 | bit_pointer& operator+=(difference_type n);
815 | bit_pointer& operator-=(difference_type n);
816 | Effects: Performs usual increment and decrement operations.
817 | Remarks: In that context, if pos + 1 < std::binary_digits<UIntType>::value, the next bit is the bit at pos + 1 in the same underlying object, but if pos + 1 == std::binary_digits<UIntType>::value, the next bit is the bit at position 0 of the next underlying object in memory. 818 |

819 | 820 |

Non-member arithmetic operators

821 |

822 | template <class T> constexpr bit_pointer<T> operator+(typename bit_pointer<T>::difference_type n, bit_pointer<T> x);
823 | Returns: A bit pointer to the x + n bit. 824 |

825 |

826 | template <class T, class U> constexpr typename std::common_type< typename bit_pointer<T>::difference_type, typename bit_pointer<U>::difference_type >::type operator-(bit_pointer<T> lhs, bit_pointer<U> rhs);
827 | Returns: The number of bit pointer increments n so that rhs + n == lhs. 828 |

829 | 830 |

Comparison operators

831 |

832 | template <class T, class U> constexpr bool operator==(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
833 | template <class T, class U> constexpr bool operator!=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
834 | template <class T, class U> constexpr bool operator<(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
835 | template <class T, class U> constexpr bool operator<=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
836 | template <class T, class U> constexpr bool operator>(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
837 | template <class T, class U> constexpr bool operator>=(bit_pointer<T> lhs, bit_pointer<U> rhs) noexcept;
838 | Effects: Compares two bit pointers by comparing the pointer to the underlying object first, and the position of the bit in that object if the two underlying pointers are equal..
839 | Returns: The boolean value of the comparison. 840 |

841 | 842 |

Make functions

843 |

844 | template <class T> constexpr bit_pointer<T> make_bit_pointer(T* ptr) noexcept;
845 | Requires: std::binary_digits<T>::value should exist and be strictly positive.
846 | Effects: Constructs the bit pointer by pointing to the bit at position 0 of ptr as in static_cast<bool>(*ptr & static_cast<UIntType>(1)).
847 | Returns: The resulting bit pointer. 848 |

849 |

850 | template <class T> constexpr bit_pointer<T> make_bit_pointer(T* ptr, typename bit_pointer<T>::size_type pos);
851 | Requires: std::binary_digits<T>::value should exist, be strictly positive and pos should verify pos < std::binary_digits<T>::value.
852 | Effects: Constructs the bit pointer by pointing to the bit at position pos of *ptr as in static_cast<bool>((*ptr >> pos) & static_cast<UIntType>(1)).
853 | Returns: The resulting bit pointer.
854 | Remarks: For unsigned integral types, static_cast<bool>((*ptr >> pos) & static_cast<UIntType>(1)) is equivalent to static_cast<bool>(*ptr & (static_cast<UIntType>(1) << pos)) for pos < std::binary_digits<UIntType>::value. 855 |

856 | 857 |
858 | 859 |

Class template std::bit_iterator

860 | 861 |

862 | Add to the <bit> synopsis: 863 |

864 | 865 |
 866 | // Bit iterator class definition
 867 | template <class Iterator>
 868 | class bit_iterator
 869 | {public:
 870 |   
 871 |   // Types
 872 |   using iterator_type = Iterator;
 873 |   using underlying_type = typename _cv_iterator_traits<Iterator>::value_type;
 874 |   using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
 875 |   using value_type = bit_value;
 876 |   using difference_type = std::intmax_t;
 877 |   using pointer = bit_pointer<underlying_type>;
 878 |   using reference = bit_reference<underlying_type>;
 879 |   using size_type = std::size_t;
 880 | 
 881 |   // Lifecycle
 882 |   constexpr bit_iterator();
 883 |   template <class T> 
 884 |   constexpr bit_iterator(const bit_iterator<T>& other);
 885 |   explicit constexpr bit_iterator(iterator_type i);
 886 |   constexpr bit_iterator(iterator_type i, size_type pos);
 887 | 
 888 |   // Assignment
 889 |   template <class T>
 890 |   bit_iterator& operator=(const bit_iterator<T>& other);
 891 |   bit_iterator& operator=(iterator_type i);
 892 | 
 893 |   // Access
 894 |   constexpr reference operator*() const noexcept;
 895 |   constexpr pointer operator->() const noexcept;
 896 |   constexpr reference operator[](difference_type n) const;
 897 | 
 898 |   // Increment and decrement operators
 899 |   bit_iterator& operator++();
 900 |   bit_iterator& operator--();
 901 |   bit_iterator operator++(int);
 902 |   bit_iterator operator--(int);
 903 |   constexpr bit_iterator operator+(difference_type n) const;
 904 |   constexpr bit_iterator operator-(difference_type n) const;
 905 |   bit_iterator& operator+=(difference_type n);
 906 |   bit_iterator& operator-=(difference_type n);
 907 | 
 908 |   // Underlying details
 909 |   constexpr iterator_type base() const;
 910 |   constexpr size_type position() const noexcept;
 911 |   constexpr underlying_type mask() const noexcept;
 912 | };
 913 | 
 914 | // Non-member arithmetic operators
 915 | template <class T>
 916 | constexpr bit_iterator<T> operator+(
 917 |   typename bit_iterator<T>::difference_type n,
 918 |   const bit_iterator<T>& i
 919 | );
 920 | template <class T, class U>
 921 | constexpr typename std::common_type<
 922 |   typename bit_iterator<T>::difference_type,
 923 |   typename bit_iterator<U>::difference_type
 924 | >::type operator-(
 925 |   const bit_iterator<T>& lhs,
 926 |   const bit_iterator<U>& rhs
 927 | );
 928 | 
 929 | // Comparison operators
 930 | template <class T, class U>
 931 | constexpr bool operator==(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 932 | template <class T, class U>
 933 | constexpr bool operator!=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 934 | template <class T, class U>
 935 | constexpr bool operator<(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 936 | template <class T, class U>
 937 | constexpr bool operator<=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 938 | template <class T, class U>
 939 | constexpr bool operator>(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 940 | template <class T, class U>
 941 | constexpr bool operator>=(const bit_iterator<T>& lhs, const bit_iterator<U>& rhs);
 942 | 
 943 | // Make functions
 944 | template <class T>
 945 | constexpr bit_iterator<T> make_bit_iterator(T i);
 946 | template <class T>
 947 | constexpr bit_iterator<T> make_bit_iterator(
 948 |   T i,
 949 |   typename bit_iterator<T>::size_type pos
 950 | );
 951 | 
952 | 953 | Requires: std::binary_digits<std::iterator_traits<Iterator>::value_type>::value should exist and be strictly positive.
954 | Remarks: In the class definition above, _cv_iterator_traits is an internal helper struct (for illustration purpose only) whose value_type preserves cv-qualifiers, contrarily to std::iterator_traits. 955 | 956 |

957 | Detailed wording to be finished 958 |

959 | 960 |
961 | 962 |

Helper struct std::binary_digits

963 | 964 |

965 | Add to the <bit> synopsis: 966 |

967 | 968 |
 969 | // Binary digits structure definition
 970 | template <class UIntType>
 971 | struct binary_digits 
 972 | : std::integral_constant<std::size_t, std::numeric_limits<UIntType>::digits> 
 973 | {};
 974 | 
975 | 976 | Requires: std::is_integral<UIntType>::value && std::is_unsigned<UIntType>::value && !std::is_same<UIntType, bool>::value.
977 | Remarks: This helper struct allows users to extend the behaviour of bit utilities on other types (for example __uint128_t) through their own specializations, independently from std::numeric_limits::digits. 978 | 979 |
980 | 981 |

Design questions

982 | The design presented in the previous section raises some questions, including: 983 | 984 |
    985 |
  1. Should std::bit_value have a default constructor that does not initialize the internal value?
    986 | bit_value() noexcept = default; 987 |
  2. 988 |
  3. Should the classes have an independent constructor when the bit position is zero?
    989 | 990 | template <class UIntType>
    991 | explicit constexpr bit_value(UIntType val) noexcept;
    992 | explicit constexpr bit_reference(underlying_type& ref) noexcept;
    993 | explicit constexpr bit_pointer(underlying_type* ptr) noexcept;
    994 | explicit constexpr bit_iterator(iterator_type i); 995 |
    996 |
  4. 997 |
  5. What should happen when the position exceeds std::binary_digits, and in particular should the constructors taking a position parameter be marked noexcept?
    998 | 999 | template <class UIntType>
    1000 | constexpr bit_value(UIntType val, size_type pos);
    1001 | constexpr bit_reference(underlying_type& ref, size_type pos);
    1002 | constexpr bit_pointer(underlying_type* ptr, size_type pos);
    1003 | constexpr bit_iterator(iterator_type i, size_type pos); 1004 |
    1005 |
  6. 1006 |
  7. Should std::bit_value and std::bit_reference have an assignment operator taking the last bit of a UIntType?
    1007 | 1008 | template <class UIntType>
    1009 | bit_value& operator=(UIntType val) noexcept;
    1010 | bit_reference& operator=(underlying_type val) noexcept; 1011 |
    1012 |
  8. 1013 |
  9. Should std::bit_value and std::bit_reference have a set function member taking a bool?
    1014 | 1015 | void set(bool b) noexcept;
    1016 |
    1017 |
  10. 1018 |
  11. Should bit modification functions be free functions or member functions (name conflict for set)?
    1019 | 1020 | void set(bool b) noexcept;
    1021 | void set() noexcept;
    1022 | void reset() noexcept;
    1023 | void flip() noexcept;
    1024 |
    1025 |
  12. 1026 |
  13. Should std::bit_value and std::bit_reference have a facet for input and output operations? 1027 |
  14. 1028 |
  15. What should happen in the streaming functions when a value that is not 0 or 1 is read as an input? 1029 |
  16. 1030 |
  17. Should std::bit_value, std::bit_reference, std::bit_pointer and std::bit_iterator have maker functions?
    1031 | 1032 | template <class T>
    1033 | constexpr bit_value make_bit_value(T val) noexcept;
    1034 | template <class T>
    1035 | constexpr bit_value make_bit_value(T val, typename bit_value::size_type pos);
    1036 | template <class T>
    1037 | constexpr bit_reference<T> make_bit_reference(T& ref) noexcept;
    1038 | template <class T>
    1039 | constexpr bit_reference<T> make_bit_reference(T& ref, typename bit_reference<T>::size_type pos)
    1040 | template <class T>
    1041 | constexpr bit_pointer<T> make_bit_pointer(T* ptr) noexcept;
    1042 | template <class T>
    1043 | constexpr bit_pointer<T> make_bit_pointer(T* ptr, typename bit_pointer<T>::size_type pos);
    1044 | template <class T>
    1045 | constexpr bit_iterator<T> make_bit_iterator(T i);
    1046 | template <class T>
    1047 | constexpr bit_iterator<T> make_bit_iterator(T i, typename bit_iterator<T>::size_type pos);
    1048 |
    1049 |
  18. 1050 |
  19. Should std::bit_reference have member swap functions?
    1051 | 1052 | template <class T>
    1053 | void swap(bit_reference<T> other);
    1054 | void swap(bit_value& other);
    1055 |
    1056 |
  20. 1057 |
  21. Should we have the whole set of swap functions?
    1058 | 1059 | template <class T, class U>
    1060 | void swap(bit_reference<T> lhs, bit_reference<U> rhs) noexcept;
    1061 | template <class T>
    1062 | void swap(bit_reference<T> lhs, bit_value& rhs) noexcept;
    1063 | template <class U>
    1064 | void swap(bit_value& lhs, bit_reference<U> rhs) noexcept;
    1065 |
    1066 |
  22. 1067 |
  23. Should std::exchange be overloaded for std::bit_reference?
    1068 | 1069 | template <class T, class U = bit_value>
    1070 | bit_value exchange(bit_reference<T> x, U&& val);
    1071 |
    1072 |
  24. 1073 |
  25. Should we have specific comparison operators for std::bit_reference for optimization purposes (which ones?) instead of using implicit conversion to std::bit_value?
  26. 1074 |
  27. Should std::bit_pointer have a constructor and an assignment operator taking a nullptr, and should the constructor be explicit?
    1075 | 1076 | explicit constexpr bit_pointer(std::nullptr_t) noexcept;
    1077 | bit_pointer& operator=(underlying_type* ptr) noexcept;
    1078 |
    1079 |
  28. 1080 |
  29. Should the std::bit_pointer constructor using nullptr with no position be implicit?
    1081 | 1082 | explicit constexpr bit_pointer(std::nullptr_t) noexcept;
    1083 |
    1084 |
  30. 1085 |
  31. What should happen when a nullptr is provided with a non-zero position, and should a specific constructor exist for this case?
    1086 | 1087 | constexpr bit_pointer(std::nullptr_t, size_type); 1088 | 1089 |
  32. 1090 |
  33. What should difference_type be in std::bit_pointer and std::bit_iterator? 1091 |
  34. 1092 |
  35. Bikeshed the following names:
    1093 | 1094 | address
    1095 | position
    1096 | mask
    1097 | underlying_type
    1098 | binary_digits 1099 |
    1100 |
  36. 1101 |
1102 | 1103 |
1104 | 1105 |

Acknowledgements

1106 | The authors would like to thank Lawrence Crowl, Howard Hinnant, Jens Maurer, Tony Van Eerd, Klemens Morgenstern, Vicente Botet Escriba, Tomasz Kaminski, Odin Holmes and the other contributors of the ISO C++ Standard - Discussion and of the ISO C++ Standard - Future Proposals groups for their initial reviews and comments. 1107 | 1108 | Vincent Reverdy and Robert J. Brunner have been supported by the National Science Foundation Grant AST-1313415. Robert J. Brunner has been supported in part by the Center for Advanced Studies at the University of Illinois. 1109 | 1110 | 1111 | 1112 | -------------------------------------------------------------------------------- /doc/wg21/2017_07_toronto/d0237r7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/wg21/2017_07_toronto/d0237r7.pdf -------------------------------------------------------------------------------- /doc/wg21/2017_07_toronto/d0237r8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/wg21/2017_07_toronto/d0237r8.pdf -------------------------------------------------------------------------------- /doc/wg21/2017_07_toronto/p0237r7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/wg21/2017_07_toronto/p0237r7.pdf -------------------------------------------------------------------------------- /doc/wg21/2017_07_toronto/p0237r8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vreverdy/bit/dfa35579cf5494ac30a71477a1511e8b884f2190/doc/wg21/2017_07_toronto/p0237r8.pdf --------------------------------------------------------------------------------