├── .gitignore ├── Makefile ├── __aux.h ├── bitvector.h ├── example.cc └── utility.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*.swp 3 | *.s 4 | *.o 5 | *.core 6 | example 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ccconf example CXX=g++48 CXXFLAGS+=-std=c++11 -Wall -g -I. 2 | CXXFLAGS = -std=c++11 -Wall -g -I. 3 | CXX = g++48 4 | 5 | .PHONY : all clean 6 | all : example 7 | clean : 8 | rm -f example example.o tags 9 | 10 | tags : *.h example.cc 11 | ctags *.h example.cc 12 | 13 | example : example.o 14 | ${CXX} ${LDFLAGS} -o example example.o 15 | example.o: example.cc bitvector.h utility.h __aux.h 16 | -------------------------------------------------------------------------------- /__aux.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 Zhihao Yuan. 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 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef ___AUX_H 27 | #define ___AUX_H 1 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace stdex { 36 | namespace aux { 37 | 38 | template 39 | struct or_shift 40 | { 41 | template 42 | static constexpr auto apply(Int n) -> Int 43 | { 44 | return or_shift::apply(n | (n >> N)); 45 | } 46 | }; 47 | 48 | template <> 49 | struct or_shift<1> 50 | { 51 | template 52 | static constexpr auto apply(Int n) -> Int 53 | { 54 | return n | (n >> 1); 55 | } 56 | }; 57 | 58 | template ::type> 59 | constexpr auto pow2_roundup(Int n) -> R 60 | { 61 | return or_shift< 62 | std::numeric_limits::digits / 2>::apply(R(n) - 1) + 1; 63 | } 64 | 65 | template 66 | struct fill_bits 67 | { 68 | template 69 | static constexpr auto apply(Int n) -> Int 70 | { 71 | return _lambda(fill_bits::apply(n)); 72 | } 73 | 74 | private: 75 | template 76 | static constexpr auto _lambda(Int x) -> Int 77 | { 78 | return (x << (N / 2)) ^ x; 79 | } 80 | }; 81 | 82 | template <> 83 | struct fill_bits 84 | { 85 | template 86 | static constexpr auto apply(Int n) -> Int 87 | { 88 | return n; 89 | } 90 | }; 91 | 92 | template 93 | constexpr auto magic(Int n) 94 | -> typename std::enable_if::value, Int>::type 95 | { 96 | return fill_bits::digits>::apply(n); 97 | } 98 | 99 | template 100 | struct m1 : std::integral_constant {}; 101 | 102 | template 103 | struct m2 : std::integral_constant {}; 104 | 105 | template 106 | struct m4 : std::integral_constant {}; 107 | 108 | template 109 | struct h01 : std::integral_constant {}; 110 | 111 | template 112 | /* c++14 */ inline auto popcount(Int x) -> std::size_t 113 | { 114 | x -= (x >> 1) & m1(); 115 | x = (x & m2()) + ((x >> 2) & m2()); 116 | x = (x + (x >> 4)) & m4(); 117 | return Int(x * h01()) >> 118 | (std::numeric_limits::digits - CHAR_BIT); 119 | } 120 | 121 | template 122 | struct set_bit1_loop 123 | { 124 | template 125 | static void apply(Int i, RandomAccessIterator it, T one, 126 | std::random_access_iterator_tag tag) 127 | { 128 | if (i & (Int(1) << (N - I))) 129 | it[I] = one; 130 | set_bit1_loop::apply(i, it, one, tag); 131 | } 132 | }; 133 | 134 | template 135 | struct set_bit1_loop 136 | { 137 | template 138 | static void apply(Int i, RandomAccessIterator it, T one, 139 | std::random_access_iterator_tag) 140 | { 141 | if (i & Int(1)) 142 | it[N] = one; 143 | } 144 | }; 145 | 146 | template 147 | inline void fill_bit1_impl(Int i, Iter it, T one) 148 | { 149 | set_bit1_loop<0, Width - 1>::apply(i, it, one, 150 | typename std::iterator_traits::iterator_category()); 151 | } 152 | 153 | template 154 | inline void fill_bit1(Int i, Iter it, T one) 155 | { 156 | constexpr auto digits = std::numeric_limits::digits; 157 | fill_bit1_impl(i, it, one); 158 | } 159 | 160 | template 162 | struct fill_bit1_upto_impl; 163 | 164 | template 165 | struct fill_bit1_upto_impl High)>::type> 167 | { 168 | template 169 | static void apply(size_t n, Int i, Iter it, T one) 170 | { 171 | throw 1; 172 | } 173 | }; 174 | 175 | template 176 | struct fill_bit1_upto_impl 177 | { 178 | template 179 | static void apply(size_t n, Int i, Iter it, T one) 180 | // precondition: n == Mid 181 | { 182 | fill_bit1_impl(i, it, one); 183 | } 184 | }; 185 | 186 | template 187 | struct fill_bit1_upto_impl::type> 189 | { 190 | template 191 | static void apply(size_t n, Int i, Iter it, T one) 192 | // precondition: Low <= n or n <= High 193 | { 194 | if (n < Mid) 195 | fill_bit1_upto_impl::apply(n, i, it, one); 196 | else if (n == Mid) 197 | fill_bit1_impl(i, it, one); 198 | else 199 | fill_bit1_upto_impl::apply(n, i, it, one); 200 | } 201 | }; 202 | 203 | template 204 | inline void fill_bit1_upto(size_t n, Int i, Iter it, T one) 205 | // precondition: 0 < n <= bitsof(Int) 206 | { 207 | constexpr auto digits = std::numeric_limits::digits; 208 | fill_bit1_upto_impl<1, digits>::apply(n, i, it, one); 209 | } 210 | 211 | template 212 | struct parse_byte_impl 213 | { 214 | template 215 | static auto apply(Iter it, UnaryPredicate f) -> unsigned char 216 | { 217 | if (f(*it)) 218 | return parse_byte_impl<(Byte << 1) ^ 1, I + 1>::apply( 219 | ++it, f); 220 | else 221 | return parse_byte_impl<(Byte << 1), I + 1>::apply( 222 | ++it, f); 223 | } 224 | 225 | template 226 | static auto apply(Iter it, Iter ed, UnaryPredicate f) -> unsigned char 227 | // precondition: distance(it, ed) <= CHAR_BIT 228 | { 229 | if (it == ed) 230 | return Byte; 231 | if (f(*it)) 232 | return parse_byte_impl<(Byte << 1) ^ 1, I + 1>::apply( 233 | ++it, ed, f); 234 | else 235 | return parse_byte_impl<(Byte << 1), I + 1>::apply( 236 | ++it, ed, f); 237 | } 238 | }; 239 | 240 | template 241 | struct parse_byte_impl 242 | { 243 | template 244 | static auto apply(Iter it, UnaryPredicate f) -> unsigned char 245 | { 246 | return Byte; 247 | } 248 | 249 | template 250 | static auto apply(Iter it, Iter ed, UnaryPredicate f) -> unsigned char 251 | // precondition: it == ed 252 | { 253 | return Byte; 254 | } 255 | }; 256 | 257 | template 258 | inline auto parse_byte(Iter it, UnaryPredicate f) -> unsigned char 259 | { 260 | return parse_byte_impl<0, 0>::apply(it, f); 261 | } 262 | 263 | template 264 | inline auto parse_byte(Iter it, Iter ed, UnaryPredicate f) -> unsigned char 265 | { 266 | return parse_byte_impl<0, 0>::apply(it, ed, f); 267 | } 268 | 269 | } 270 | 271 | template 272 | struct same_allocator : std::integral_constant::template 274 | rebind_alloc::value_type>, 275 | Alloc1>::value> 276 | {}; 277 | 278 | template 279 | inline auto reverser(Iter it) -> std::reverse_iterator 280 | { 281 | return std::reverse_iterator(it); 282 | } 283 | 284 | template 286 | inline auto backward_difference(BidirectionalIterator1 first, 287 | BidirectionalIterator1 last, BidirectionalIterator2 d_last, 288 | BinaryOperation f) -> BidirectionalIterator2 289 | { 290 | using value_t = typename std::iterator_traits< 291 | BidirectionalIterator1>::value_type; 292 | 293 | if (first == last) 294 | return d_last; 295 | 296 | value_t acc = *--last; 297 | while (first != last) 298 | { 299 | value_t val = *--last; 300 | *--d_last = f(acc, val); 301 | acc = std::move(val); 302 | } 303 | *--d_last = f(acc, value_t()); 304 | 305 | return d_last; 306 | } 307 | 308 | } 309 | 310 | #endif 311 | -------------------------------------------------------------------------------- /bitvector.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 Zhihao Yuan. 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 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef _BITVECTOR_H 27 | #define _BITVECTOR_H 1 28 | 29 | #include "utility.h" 30 | #include "__aux.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace stdex { 39 | 40 | template 41 | struct basic_bitvector 42 | { 43 | typedef Allocator allocator_type; 44 | 45 | private: 46 | template 47 | friend struct basic_bitvector; 48 | 49 | friend struct std::hash; 50 | 51 | typedef std::allocator_traits _alloc_traits; 52 | typedef typename _alloc_traits::value_type _block_type; 53 | static_assert(std::is_unsigned<_block_type>(), 54 | "underlying type must be unsigned"); 55 | 56 | typedef _block_type* _block_iterator; 57 | typedef _block_type const* _block_const_iterator; 58 | 59 | struct _blocks 60 | { 61 | _block_type* p; 62 | std::size_t cap; 63 | }; 64 | 65 | static constexpr auto _bits_per_block = 66 | std::numeric_limits<_block_type>::digits; 67 | 68 | template 69 | static constexpr std::size_t count_to_bits(std::size_t n) 70 | { 71 | return n * N; 72 | } 73 | 74 | template 75 | static constexpr std::size_t bits_to_count(std::size_t n) 76 | { 77 | return (n + (N - 1)) / N; 78 | } 79 | 80 | template 81 | static constexpr std::size_t block_index(std::size_t n) 82 | { 83 | return n / N; 84 | } 85 | 86 | template 87 | static constexpr std::size_t bit_index(std::size_t n) 88 | { 89 | return n % N; 90 | } 91 | 92 | static constexpr _block_type bit_mask(std::size_t n) 93 | { 94 | return _block_type(1) << bit_index(n); 95 | } 96 | 97 | static constexpr auto _bits_internal = 98 | count_to_bits(sizeof(_blocks)); 99 | static constexpr auto _blocks_internal = 100 | bits_to_count(_bits_internal); 101 | static constexpr auto _bits_in_use = std::size_t(1) << 102 | (std::numeric_limits::digits - 1); 103 | 104 | using _bits = _block_type[_blocks_internal]; 105 | static_assert(sizeof(_bits) == sizeof(_blocks), 106 | "unsupported representation"); 107 | 108 | using _zeros = std::integral_constant<_block_type, 0>; 109 | using _ones = std::integral_constant<_block_type, _block_type(~0)>; 110 | 111 | public: 112 | 113 | struct reference 114 | { 115 | private: 116 | typedef typename basic_bitvector::_block_type& _bref_t; 117 | friend basic_bitvector; 118 | 119 | reference(_bref_t loc, std::size_t mask) : 120 | loc_(loc), 121 | mask_(mask) 122 | {} 123 | 124 | public: 125 | reference& operator=(bool value) noexcept 126 | { 127 | if (value) 128 | loc_ |= mask_; 129 | else 130 | loc_ &= ~mask_; 131 | 132 | return *this; 133 | } 134 | 135 | reference& operator=(reference other) noexcept 136 | { 137 | return (*this) = static_cast(other); 138 | } 139 | 140 | operator bool() const noexcept 141 | { 142 | return loc_ & mask_; 143 | } 144 | 145 | bool operator~() const noexcept 146 | { 147 | return !(*this); 148 | } 149 | 150 | reference& flip() noexcept 151 | { 152 | loc_ ^= mask_; 153 | return *this; 154 | } 155 | 156 | private: 157 | _bref_t loc_; 158 | std::size_t mask_; 159 | }; 160 | 161 | #define size_ sz_alloc_.first() 162 | #define alloc_ sz_alloc_.second() 163 | #define cap_ st_.blocks.cap 164 | #define p_ st_.blocks.p 165 | #define bits_ st_.bits 166 | 167 | basic_bitvector() noexcept( 168 | std::is_nothrow_default_constructible()) : 169 | sz_alloc_(_bits_in_use) 170 | {} 171 | 172 | explicit basic_bitvector(allocator_type const& a) : 173 | sz_alloc_(_bits_in_use, a) 174 | {} 175 | 176 | explicit basic_bitvector(std::size_t n, 177 | allocator_type const& a = allocator_type()) : 178 | sz_alloc_(_bits_in_use, a) 179 | { 180 | init_to_hold(n); 181 | size_ ^= n; 182 | 183 | reset(); 184 | } 185 | 186 | basic_bitvector(std::size_t n, bool const& value, 187 | allocator_type const& a = allocator_type()) : 188 | sz_alloc_(_bits_in_use, a) 189 | { 190 | init_to_hold(n); 191 | size_ ^= n; 192 | 193 | assign_to(value); 194 | } 195 | 196 | basic_bitvector(basic_bitvector const& v) : 197 | basic_bitvector(v, _alloc_traits:: 198 | select_on_container_copy_construction(v.alloc_)) 199 | {} 200 | 201 | basic_bitvector(basic_bitvector const& v, allocator_type const& a) : 202 | sz_alloc_(v.size_, a) 203 | { 204 | // internal -> internal 205 | if (v.using_bits()) 206 | st_ = v.st_; 207 | 208 | // heap -> internal 209 | else if (v.size() <= _bits_internal) 210 | { 211 | std::copy_n(v.p_, _blocks_internal, bits_); 212 | size_ ^= _bits_in_use; 213 | } 214 | 215 | // heap -> shrunk heap 216 | else 217 | { 218 | allocate_preferred(v.size()); 219 | copy_to_heap(v); 220 | } 221 | } 222 | 223 | template 224 | basic_bitvector(basic_bitvector const& v) : 225 | basic_bitvector(v, static_cast(v.alloc_)) 226 | {} 227 | 228 | template 229 | basic_bitvector(basic_bitvector const& v, 230 | allocator_type const& a, 231 | typename std::enable_if< 232 | same_allocator::value>::type* = 0) : 233 | sz_alloc_(_bits_in_use, a) 234 | { 235 | auto sz = v.size(); 236 | 237 | init_to_hold(sz); 238 | size_ ^= sz; 239 | 240 | std::memcpy(begin(), v.begin(), bits_to_count(sz)); 241 | } 242 | 243 | basic_bitvector(basic_bitvector&& v) noexcept( 244 | std::is_nothrow_move_constructible()) : 245 | st_(v.st_), 246 | sz_alloc_(std::move(v.sz_alloc_)) 247 | { 248 | // minimal change to prevent deallocation 249 | v.size_ = _bits_in_use; 250 | } 251 | 252 | basic_bitvector(basic_bitvector&& v, allocator_type const& a) : 253 | sz_alloc_(v.size_, a) 254 | { 255 | // exchangeable, or internal -> internal 256 | if (alloc_ == v.alloc_ or v.using_bits()) 257 | { 258 | st_ = v.st_; 259 | // minimal change to prevent deallocation 260 | v.size_ = _bits_in_use; 261 | } 262 | 263 | // heap -> internal 264 | else if (v.size() <= _bits_internal) 265 | { 266 | std::copy_n(v.p_, _blocks_internal, bits_); 267 | size_ ^= _bits_in_use; 268 | } 269 | 270 | // heap -> heap 271 | else 272 | { 273 | allocate_preferred(v.size()); 274 | copy_to_heap(v); 275 | } 276 | } 277 | 278 | template 279 | explicit basic_bitvector(std::basic_string 280 | const& str, 281 | typename std::basic_string:: 282 | size_type pos = 0, 283 | typename std::basic_string:: 284 | size_type n = (std::basic_string::npos), 285 | charT zero = charT('0'), 286 | charT one = charT('1')) : 287 | basic_bitvector(str, {}, pos, n, zero, one) 288 | {} 289 | 290 | template 291 | explicit basic_bitvector(charT const* str, 292 | typename std::basic_string:: 293 | size_type n = (std::basic_string::npos), 294 | charT zero = charT('0'), 295 | charT one = charT('1')) : 296 | basic_bitvector(str, {}, n, zero, one) 297 | {} 298 | 299 | template 300 | explicit basic_bitvector(std::basic_string 301 | const& str, 302 | allocator_type const& a, 303 | typename std::basic_string:: 304 | size_type pos = 0, 305 | typename std::basic_string:: 306 | size_type n = (std::basic_string::npos), 307 | charT zero = charT('0'), 308 | charT one = charT('1')) : 309 | sz_alloc_(_bits_in_use, a) 310 | { 311 | if (pos > str.size()) 312 | throw std::out_of_range( 313 | "basic_bitvector::basic_bitvector"); 314 | 315 | auto it = std::begin(str) + pos; 316 | auto sz = std::min(n, str.size() - pos); 317 | 318 | from_string(it, sz, zero, one); 319 | } 320 | 321 | template 322 | explicit basic_bitvector(charT const* str, 323 | allocator_type const& a, 324 | typename std::basic_string:: 325 | size_type n = (std::basic_string::npos), 326 | charT zero = charT('0'), 327 | charT one = charT('1')) : 328 | sz_alloc_(_bits_in_use, a) 329 | { 330 | using traits = typename std::basic_string::traits_type; 331 | auto sz = std::min(n, traits::length(str)); 332 | 333 | from_string(str, sz, zero, one); 334 | } 335 | 336 | ~basic_bitvector() noexcept 337 | { 338 | if (not using_bits()) 339 | deallocate(); 340 | } 341 | 342 | // WIP: N2525 343 | basic_bitvector& operator=(basic_bitvector v) 344 | { 345 | swap(v); 346 | return *this; 347 | } 348 | 349 | void assign(std::size_t n, bool const& value) 350 | { 351 | expand_to_hold(n); 352 | set_size(n); 353 | 354 | assign_to(value); 355 | } 356 | 357 | allocator_type get_allocator() const noexcept 358 | { 359 | return alloc_; 360 | } 361 | 362 | template 363 | bool operator==(basic_bitvector const& rhs) const 364 | { 365 | if (size() != rhs.size()) 366 | return false; 367 | else 368 | return equals(rhs); 369 | } 370 | 371 | template 372 | bool operator!=(basic_bitvector const& rhs) const 373 | { 374 | return !(*this == rhs); 375 | } 376 | 377 | reference operator[](std::size_t pos) 378 | { 379 | return { begin()[block_index(pos)], bit_mask(pos) }; 380 | } 381 | 382 | bool operator[](std::size_t pos) const 383 | { 384 | return begin()[block_index(pos)] & bit_mask(pos); 385 | } 386 | 387 | bool test(std::size_t pos) const 388 | { 389 | if (pos >= size()) 390 | throw std::out_of_range("basic_bitvector::test"); 391 | 392 | return (*this)[pos]; 393 | } 394 | 395 | bool all() const noexcept 396 | { 397 | bool r = std::none_of(begin(), filled_end(), 398 | [](_block_type v) -> bool 399 | { 400 | return static_cast<_block_type>(~v); 401 | }); 402 | 403 | if (!r) 404 | return false; 405 | else 406 | return not has_incomplete_block() 407 | or !dezeroed_last_block(); 408 | } 409 | 410 | bool any() const noexcept 411 | { 412 | bool r = std::any_of(begin(), filled_end(), 413 | [](_block_type v) -> bool 414 | { 415 | return v; 416 | }); 417 | 418 | if (r) 419 | return true; 420 | else 421 | return has_incomplete_block() and zeroed_last_block(); 422 | } 423 | 424 | bool none() const noexcept 425 | { 426 | return not any(); 427 | } 428 | 429 | std::size_t count() const noexcept 430 | { 431 | auto n = std::accumulate(begin(), filled_end(), 432 | std::size_t(0), 433 | [](std::size_t n, _block_type v) 434 | { 435 | return n + stdex::aux::popcount(v); 436 | }); 437 | 438 | if (has_incomplete_block()) 439 | return n + stdex::aux::popcount(zeroed_last_block()); 440 | else 441 | return n; 442 | } 443 | 444 | bool empty() const noexcept 445 | { 446 | return size() == 0; 447 | } 448 | 449 | std::size_t size() const noexcept 450 | { 451 | return actual_size(size_); 452 | } 453 | 454 | std::size_t max_size() const noexcept 455 | { 456 | auto amax = _alloc_traits::max_size(alloc_); 457 | auto hmax = actual_size(std::numeric_limits< 458 | std::size_t>::max()); 459 | 460 | if (hmax / _bits_per_block <= amax) 461 | return hmax; 462 | else 463 | return count_to_bits(amax); 464 | } 465 | 466 | void shrink_to_fit() /* noexcept */ 467 | { 468 | if (aux::pow2_roundup(size()) < capacity()) 469 | swap_to_fit(); 470 | } 471 | 472 | template 473 | basic_bitvector& operator&=(basic_bitvector const& v) 474 | { 475 | if (size() != v.size()) 476 | throw std::invalid_argument( 477 | "basic_bitvector::operator&="); 478 | 479 | return transformed_by(bit_and(), v); 480 | } 481 | 482 | template 483 | basic_bitvector& operator|=(basic_bitvector const& v) 484 | { 485 | if (size() != v.size()) 486 | throw std::invalid_argument( 487 | "basic_bitvector::operator|="); 488 | 489 | return transformed_by(bit_or(), v); 490 | } 491 | 492 | template 493 | basic_bitvector& operator^=(basic_bitvector const& v) 494 | { 495 | if (size() != v.size()) 496 | throw std::invalid_argument( 497 | "basic_bitvector::operator^="); 498 | 499 | return transformed_by(bit_xor(), v); 500 | } 501 | 502 | template 503 | basic_bitvector operator&(basic_bitvector const& rhs) const 504 | { 505 | basic_bitvector v(*this); 506 | v &= rhs; 507 | return v; 508 | } 509 | 510 | template 511 | basic_bitvector operator|(basic_bitvector const& rhs) const 512 | { 513 | basic_bitvector v(*this); 514 | v |= rhs; 515 | return v; 516 | } 517 | 518 | template 519 | basic_bitvector operator^(basic_bitvector const& rhs) const 520 | { 521 | basic_bitvector v(*this); 522 | v ^= rhs; 523 | return v; 524 | } 525 | 526 | basic_bitvector operator~() const 527 | { 528 | basic_bitvector v(*this); 529 | v.flip(); 530 | return v; 531 | } 532 | 533 | basic_bitvector& operator<<=(std::size_t pos) 534 | { 535 | if (pos >= size()) 536 | reset(); 537 | else 538 | shift_left(begin(), end(), pos); 539 | 540 | return *this; 541 | } 542 | 543 | basic_bitvector& operator>>=(std::size_t pos) 544 | { 545 | if (pos >= size()) 546 | reset(); 547 | else 548 | { 549 | if (has_incomplete_block()) 550 | last_block() = zeroed_last_block(); 551 | 552 | shift_right(begin(), end(), pos); 553 | } 554 | 555 | return *this; 556 | } 557 | 558 | basic_bitvector operator<<(std::size_t pos) const 559 | { 560 | basic_bitvector v(*this); 561 | v <<= pos; 562 | return v; 563 | } 564 | 565 | basic_bitvector operator>>(std::size_t pos) const 566 | { 567 | basic_bitvector v(*this); 568 | v >>= pos; 569 | return v; 570 | } 571 | 572 | basic_bitvector& set() noexcept 573 | { 574 | std::fill(begin(), end(), _ones()); 575 | return *this; 576 | } 577 | 578 | basic_bitvector& set(std::size_t pos, bool value = true) 579 | { 580 | if (pos >= size()) 581 | throw std::out_of_range("basic_bitvector::set"); 582 | 583 | set_bit_to(pos, value); 584 | return *this; 585 | } 586 | 587 | basic_bitvector& reset() noexcept 588 | { 589 | std::fill(begin(), end(), _zeros()); 590 | return *this; 591 | } 592 | 593 | basic_bitvector& reset(std::size_t pos) 594 | { 595 | if (pos >= size()) 596 | throw std::out_of_range("basic_bitvector::reset"); 597 | 598 | unset_bit(pos); 599 | return *this; 600 | } 601 | 602 | basic_bitvector& flip() noexcept 603 | { 604 | std::transform(begin(), end(), 605 | begin(), 606 | [](_block_type v) 607 | { 608 | return ~v; 609 | }); 610 | 611 | return *this; 612 | } 613 | 614 | basic_bitvector& flip(std::size_t pos) 615 | { 616 | if (pos >= size()) 617 | throw std::out_of_range("basic_bitvector::flip"); 618 | 619 | flip_bit(pos); 620 | return *this; 621 | } 622 | 623 | void clear() noexcept 624 | { 625 | size_ &= _bits_in_use; 626 | } 627 | 628 | void push_back(bool value) 629 | { 630 | auto i = size(); 631 | 632 | expand_to_hold(i + 1); 633 | set_bit_to(i, value); 634 | ++size_; 635 | } 636 | 637 | void pop_back() 638 | { 639 | --size_; 640 | } 641 | 642 | void resize(std::size_t n, bool value = false) 643 | { 644 | auto sz = size(); 645 | auto oldn = bits_to_count(sz); 646 | auto newn = bits_to_count(n); 647 | 648 | expand_to_hold(n); 649 | if (has_incomplete_block() and sz < n) 650 | last_block() = value ? 651 | oned_last_block() : 652 | zeroed_last_block(); 653 | 654 | set_size(n); 655 | if (oldn < newn) 656 | std::fill(begin() + oldn, end(), 657 | value ? _ones() : _zeros()); 658 | } 659 | 660 | void swap(basic_bitvector& v) noexcept( 661 | is_nothrow_swappable()) 662 | { 663 | using std::swap; 664 | 665 | swap(alloc_, v.alloc_); 666 | swap(size_, v.size_); 667 | swap(st_, v.st_); 668 | } 669 | 670 | template , 672 | typename _Allocator = std::allocator> 673 | std::basic_string 674 | to_string(charT zero = charT('0'), charT one = charT('1')) const 675 | { 676 | std::basic_string s(size(), zero); 677 | auto it = s.begin(); 678 | 679 | if (has_incomplete_block()) 680 | { 681 | auto extra = extra_size(); 682 | aux::fill_bit1_upto(extra, last_block(), it, one); 683 | it += extra; 684 | } 685 | 686 | std::for_each(reverser(filled_end()), reverser(begin()), 687 | [&](_block_type v) 688 | { 689 | aux::fill_bit1(v, it, one); 690 | it += _bits_per_block; 691 | }); 692 | 693 | return s; 694 | } 695 | 696 | unsigned long to_ulong() const 697 | { 698 | if (size() > std::numeric_limits::digits) 699 | throw std::overflow_error("basic_bitvector::to_ulong"); 700 | 701 | return as_integral(); 702 | } 703 | 704 | unsigned long long to_ullong() const 705 | { 706 | if (size() > std::numeric_limits::digits) 707 | throw std::overflow_error("basic_bitvector::to_ullong"); 708 | 709 | return as_integral(); 710 | } 711 | 712 | private: 713 | void set_bit_to(std::size_t pos, bool value) 714 | { 715 | if (value) 716 | set_bit(pos); 717 | else 718 | unset_bit(pos); 719 | } 720 | 721 | void set_bit(std::size_t pos) 722 | { 723 | begin()[block_index(pos)] |= bit_mask(pos); 724 | } 725 | 726 | void unset_bit(std::size_t pos) 727 | { 728 | begin()[block_index(pos)] &= ~bit_mask(pos); 729 | } 730 | 731 | void flip_bit(std::size_t pos) 732 | { 733 | begin()[block_index(pos)] ^= bit_mask(pos); 734 | } 735 | 736 | void assign_to(bool value) 737 | { 738 | if (value) 739 | set(); 740 | else 741 | reset(); 742 | } 743 | 744 | bool has_incomplete_block() const 745 | { 746 | return extra_size() != 0; 747 | } 748 | 749 | bool has_incomplete_byte() const 750 | { 751 | return extra_size() != 0; 752 | } 753 | 754 | template 755 | std::size_t extra_size() const 756 | { 757 | return bit_index(size()); 758 | } 759 | 760 | _block_type& last_block() 761 | { 762 | return *filled_end(); 763 | } 764 | 765 | _block_type last_block() const 766 | { 767 | return *filled_end(); 768 | } 769 | 770 | _block_type zeroed_last_block() const 771 | { 772 | return last_block() & extra_mask(); 773 | } 774 | 775 | _block_type dezeroed_last_block() const 776 | { 777 | return ~last_block() & extra_mask(); 778 | } 779 | 780 | _block_type oned_last_block() const 781 | { 782 | return last_block() | ~extra_mask(); 783 | } 784 | 785 | _block_type extra_mask() const 786 | { 787 | return _ones() >> (_bits_per_block - extra_size()); 788 | } 789 | 790 | unsigned char zeroed_last_byte() const 791 | { 792 | return begin_of_bytes()[block_index(size())] & 793 | (UCHAR_MAX >> (CHAR_BIT - extra_size())); 794 | } 795 | 796 | bool using_bits() const 797 | { 798 | return size_ & _bits_in_use; 799 | } 800 | 801 | std::size_t capacity() const 802 | { 803 | if (using_bits()) 804 | return _bits_internal; 805 | else 806 | return count_to_bits(cap_); 807 | } 808 | 809 | void expand_to_hold(std::size_t sz) 810 | { 811 | if (sz > capacity()) { 812 | if (sz > max_size()) 813 | throw std::length_error("bitvector"); 814 | 815 | basic_bitvector v(alloc_); 816 | v.allocate_preferred(sz); 817 | v.size_ = size(); 818 | v.copy_to_heap(*this); 819 | swap(v); 820 | } 821 | } 822 | 823 | void init_to_hold(std::size_t sz) 824 | { 825 | if (sz > _bits_internal) { 826 | if (sz > max_size()) 827 | throw std::length_error("bitvector"); 828 | 829 | allocate_preferred(sz); 830 | size_ = 0; 831 | } 832 | } 833 | 834 | void set_size(std::size_t sz) 835 | { 836 | size_ = (size_ & _bits_in_use) ^ sz; 837 | } 838 | 839 | void copy_to_heap(basic_bitvector const& v) 840 | { 841 | std::copy(v.begin(), v.end(), p_); 842 | } 843 | 844 | void init_after(std::size_t sz) 845 | { 846 | auto n = bits_to_count(sz); 847 | std::fill_n(p_ + n, cap_ - n, _zeros()); 848 | } 849 | 850 | void swap_to_fit() 851 | try 852 | { 853 | basic_bitvector v(*this); 854 | swap(v); 855 | } 856 | catch (...) 857 | { 858 | } 859 | 860 | _block_const_iterator begin() const 861 | { 862 | return using_bits() ? bits_ : p_; 863 | } 864 | 865 | _block_const_iterator filled_end() const 866 | { 867 | return begin() + block_index(size()); 868 | } 869 | 870 | _block_const_iterator end() const 871 | { 872 | return begin() + bits_to_count(size()); 873 | } 874 | 875 | _block_iterator begin() 876 | { 877 | return using_bits() ? bits_ : p_; 878 | } 879 | 880 | _block_iterator filled_end() 881 | { 882 | return begin() + block_index(size()); 883 | } 884 | 885 | _block_iterator end() 886 | { 887 | return begin() + bits_to_count(size()); 888 | } 889 | 890 | unsigned char* begin_of_bytes() 891 | { 892 | return reinterpret_cast(begin()); 893 | } 894 | 895 | unsigned char const* begin_of_bytes() const 896 | { 897 | return reinterpret_cast(begin()); 898 | } 899 | 900 | void allocate(std::size_t sz) 901 | { 902 | auto n = bits_to_count(sz); 903 | p_ = _alloc_traits::allocate(alloc_, n); 904 | cap_ = n; 905 | } 906 | 907 | void allocate_preferred(std::size_t sz) 908 | { 909 | allocate(aux::pow2_roundup(sz)); 910 | init_after(sz); 911 | } 912 | 913 | void deallocate() 914 | { 915 | _alloc_traits::deallocate(alloc_, p_, cap_); 916 | } 917 | 918 | template 920 | void from_string(Iter it, Size sz, charT zero, charT one) 921 | { 922 | if (not std::all_of(it, it + sz, 923 | [=](charT c) 924 | { 925 | return traits::eq(c, zero) or traits::eq(c, one); 926 | })) 927 | throw std::invalid_argument( 928 | "basic_bitvector::basic_bitvector"); 929 | 930 | init_to_hold(sz); 931 | size_ ^= sz; 932 | 933 | auto bytes = reverser(begin_of_bytes() + 934 | bits_to_count(sz)); 935 | 936 | auto is_one = [=](charT c) 937 | { 938 | return traits::eq(c, one); 939 | }; 940 | 941 | if (has_incomplete_byte()) 942 | { 943 | auto extra = extra_size(); 944 | *bytes = aux::parse_byte(it, it + extra, is_one); 945 | ++bytes; 946 | it += extra; 947 | } 948 | 949 | std::generate_n(bytes, block_index(sz), 950 | [&] 951 | { 952 | auto byte = aux::parse_byte(it, is_one); 953 | it += CHAR_BIT; 954 | return byte; 955 | }); 956 | } 957 | 958 | template 959 | R as_integral() const 960 | { 961 | return as_integral(std::integral_constant() 963 | and sizeof(_block_type) >= sizeof(R)>()); 964 | } 965 | 966 | template 967 | R as_integral(std::true_type) const 968 | { 969 | return zeroed_last_block(); 970 | } 971 | 972 | template 973 | R as_integral(std::false_type) const 974 | { 975 | auto r = 976 | std::accumulate(reverser(filled_end()), reverser(begin()), 977 | has_incomplete_block() ? R(zeroed_last_block()) : R(0), 978 | [](R r, _block_type v) 979 | { 980 | return (r << _bits_per_block) ^ v; 981 | }); 982 | 983 | return r; 984 | } 985 | 986 | template 987 | auto equals(basic_bitvector<_Allocator> const& rhs) const 988 | -> typename std::enable_if< 989 | same_allocator::value, bool>::type 990 | { 991 | using Block = typename basic_bitvector<_Allocator>::_block_type; 992 | 993 | return equals(rhs, std::integral_constant::value>()); 995 | } 996 | 997 | template 998 | bool equals(basic_bitvector<_Allocator> const& rhs, 999 | std::true_type) const 1000 | { 1001 | auto r = std::equal(begin(), filled_end(), rhs.begin()); 1002 | 1003 | if (has_incomplete_block()) 1004 | return r and (zeroed_last_block() == 1005 | rhs.zeroed_last_block()); 1006 | else 1007 | return r; 1008 | } 1009 | 1010 | template 1011 | bool equals(basic_bitvector<_Allocator> const& rhs, 1012 | std::false_type) const 1013 | { 1014 | auto r = !std::memcmp(begin(), rhs.begin(), 1015 | block_index(size())); 1016 | 1017 | if (has_incomplete_byte()) 1018 | return r and (zeroed_last_byte() == 1019 | rhs.zeroed_last_byte()); 1020 | else 1021 | return r; 1022 | } 1023 | 1024 | template 1025 | auto transformed_by(BinaryOperation f, 1026 | basic_bitvector<_Allocator> const& v) 1027 | -> typename std::enable_if< 1028 | same_allocator::value, 1029 | basic_bitvector&>::type 1030 | { 1031 | using Block = typename basic_bitvector<_Allocator>::_block_type; 1032 | 1033 | transformed_by(f, v, std::integral_constant::value>()); 1035 | 1036 | return *this; 1037 | } 1038 | 1039 | template 1040 | void transformed_by(BinaryOperation f, 1041 | basic_bitvector<_Allocator> const& v, 1042 | std::true_type) 1043 | { 1044 | std::transform(begin(), end(), v.begin(), begin(), f); 1045 | } 1046 | 1047 | template 1048 | void transformed_by(BinaryOperation f, 1049 | basic_bitvector<_Allocator> const& v, 1050 | std::false_type) 1051 | { 1052 | auto it = begin_of_bytes(); 1053 | 1054 | std::transform(it, it + bits_to_count(size()), 1055 | v.begin_of_bytes(), it, f); 1056 | } 1057 | 1058 | static void shift_left(_block_iterator first, _block_iterator last, 1059 | std::size_t pos) 1060 | { 1061 | auto off = pos % _bits_per_block; 1062 | auto diff = _bits_per_block - off; 1063 | auto wipe = pos / _bits_per_block; 1064 | auto nfirst = first + wipe; 1065 | auto nlast = last - wipe; 1066 | 1067 | if (diff == _bits_per_block) 1068 | std::copy_backward(first, nlast, last); 1069 | else 1070 | backward_difference(first, nlast, last, 1071 | [=](_block_type cur, _block_type prev) 1072 | { 1073 | return (cur << off) ^ (prev >> diff); 1074 | }); 1075 | 1076 | std::fill(first, nfirst, _zeros()); 1077 | } 1078 | 1079 | static void shift_right(_block_iterator first, _block_iterator last, 1080 | std::size_t pos) 1081 | { 1082 | auto off = pos % _bits_per_block; 1083 | auto diff = _bits_per_block - off; 1084 | auto wipe = pos / _bits_per_block; 1085 | auto nfirst = first + wipe; 1086 | auto nlast = last - wipe; 1087 | 1088 | if (diff == _bits_per_block) 1089 | std::copy(nfirst, last, first); 1090 | else 1091 | backward_difference(reverser(last), reverser(nfirst), 1092 | reverser(first), 1093 | [=](_block_type cur, _block_type prev) 1094 | { 1095 | return (cur >> off) ^ (prev << diff); 1096 | }); 1097 | 1098 | std::fill(nlast, last, _zeros()); 1099 | } 1100 | 1101 | struct bit_and { 1102 | template 1103 | T operator()(T l, T r) { return l & r; } 1104 | }; 1105 | 1106 | struct bit_or { 1107 | template 1108 | T operator()(T l, T r) { return l | r; } 1109 | }; 1110 | 1111 | struct bit_xor { 1112 | template 1113 | T operator()(T l, T r) { return l ^ r; } 1114 | }; 1115 | 1116 | #undef size_ 1117 | #undef alloc_ 1118 | #undef cap_ 1119 | #undef p_ 1120 | #undef bits_ 1121 | 1122 | static std::size_t actual_size(std::size_t n) 1123 | { 1124 | return n & ~_bits_in_use; 1125 | } 1126 | 1127 | union _ut 1128 | { 1129 | _blocks blocks; 1130 | _bits bits; 1131 | 1132 | _ut() : bits() {} 1133 | } st_; 1134 | compressed_pair sz_alloc_; 1135 | }; 1136 | 1137 | template 1138 | inline void swap(basic_bitvector& a, basic_bitvector& b) 1139 | noexcept(noexcept(a.swap(b))) 1140 | { 1141 | a.swap(b); 1142 | } 1143 | 1144 | typedef basic_bitvector> bitvector; 1145 | 1146 | } 1147 | 1148 | namespace std { 1149 | 1150 | template 1151 | struct hash> 1152 | : unary_function, size_t> 1153 | { 1154 | size_t operator()(stdex::basic_bitvector const& v) const 1155 | noexcept 1156 | { 1157 | return v.sz_alloc_.first(); 1158 | } 1159 | }; 1160 | 1161 | } 1162 | 1163 | #endif 1164 | -------------------------------------------------------------------------------- /example.cc: -------------------------------------------------------------------------------- 1 | #include "bitvector.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | stdex::bitvector v; 9 | std::cout << std::boolalpha; 10 | 11 | std::cout 12 | << "sizeof:\t\t\t" << sizeof(v) << std::endl 13 | << "max size:\t\t" << v.max_size() << std::endl 14 | << "nothrow default ctor:\t" 15 | << std::is_nothrow_default_constructible< 16 | stdex::bitvector>() << std::endl 17 | << "nothrow swap:\t\t" << noexcept(swap(v, v)) << std::endl 18 | << "default init size:\t" << v.size() << std::endl 19 | ; 20 | 21 | v = stdex::bitvector(128, true); 22 | v.push_back(true); 23 | 24 | std::cout << "all with all bit set:\t" << v.all() << std::endl; 25 | 26 | std::cout << std::noboolalpha; 27 | 28 | std::cout 29 | << "size after insertion:\t" << v.size() << std::endl 30 | << "last bit:\t\t" << v.test(128) << std::endl 31 | ; 32 | 33 | v.set(128, false); 34 | std::cout << "after set to false:\t" << v[128] << std::endl; 35 | 36 | v.flip(128); 37 | std::cout << "after flipped:\t\t" << v[128] << std::endl; 38 | 39 | v.reset(128); 40 | std::cout << "after reset:\t\t" << v[128] << std::endl; 41 | 42 | auto r = v[128]; 43 | r.flip(); 44 | 45 | std::cout 46 | << "after proxy flipped:\t" << v[128] << std::endl 47 | << "proxy:\t\t\t" << r << std::endl 48 | << "proxy inversed:\t\t" << ~r << std::endl 49 | ; 50 | 51 | v[127].flip(); 52 | stdex::bitvector v2(v); 53 | 54 | std::cout 55 | << "popcount after a flip:\t" << v.count() << std::endl 56 | << "popcount of copied:\t" << v2.count() << std::endl 57 | ; 58 | 59 | stdex::bitvector v3(200); 60 | swap(v, v3); 61 | 62 | std::cout 63 | << "size after swap:\t" << v.size() << std::endl 64 | << "size of swapped:\t" << v3.size() << std::endl 65 | << "popcount after swap:\t" << v.count() << std::endl 66 | ; 67 | 68 | v.pop_back(); 69 | std::cout << "size after popped:\t" << v.size() << std::endl; 70 | 71 | v.resize(277, 1); 72 | std::cout << "popcount after resized:\t" << v.count() << std::endl; 73 | 74 | v.clear(); 75 | std::cout << "size after cleared:\t" << v.size() << std::endl; 76 | 77 | v.assign(64, 1); 78 | v.shrink_to_fit(); 79 | std::cout << "popcount after assign:\t" << v.count() << std::endl; 80 | 81 | v = v2; 82 | std::cout << "after assignment:\t" << v.count() << std::endl; 83 | 84 | std::cout << std::boolalpha; 85 | 86 | std::cout << "all with one bit unset:\t" << v.all() << std::endl; 87 | 88 | v.reset(); 89 | std::cout << "any with no bit set:\t" << v.any() << std::endl; 90 | 91 | v.set(128); 92 | std::cout << "any with last bit set:\t" << v.any() << std::endl; 93 | 94 | v.flip(); 95 | std::cout << "popcount after flip:\t" << v.count() << std::endl; 96 | 97 | stdex::bitvector v5(std::move(v3), v2.get_allocator()); 98 | std::cout << "size of move init'ed:\t" << v5.size() << std::endl; 99 | 100 | stdex::basic_bitvector> v4; 101 | std::cout << "ulong of 0b(empty):\t" << v4.to_ulong() << std::endl; 102 | 103 | v4 = decltype(v4)("10011"); 104 | std::cout << "ulong of 0b" << v4.to_string() << ":\t" 105 | << v4.to_ulong() << std::endl; 106 | 107 | v4.push_back(0); 108 | v4.push_back(0); 109 | v4.push_back(0); 110 | v4.push_back(1); 111 | std::cout << "ulong of 0b" << v4.to_string() << ":\t" 112 | << v4.to_ulong() << std::endl; 113 | 114 | std::string s("0bXXYYYYXX"); 115 | decltype(v4) v6(s, 2, s.size(), 'X', 'Y'); 116 | std::cout << "string of " << s << ":\t" 117 | << v6.to_string() << std::endl; 118 | 119 | v2 = v6; 120 | 121 | std::cout 122 | << "equal to self:\t\t" << (v6 == v6) << std::endl 123 | << "equal to diff content:\t" << (v6 == v4) << std::endl 124 | << "equal to diff type:\t" << (v6 == v2) << std::endl 125 | ; 126 | 127 | v6.resize(v4.size()); 128 | std::cout << "content after resized:\t" << v6.to_string() << std::endl; 129 | 130 | v6 ^= v4; 131 | std::cout << "after ^= " << v4.to_string() << ":\t" 132 | << v6.to_string() << std::endl; 133 | 134 | decltype(v4) v8(v); 135 | std::cout << "equal of a larger case:\t" << (v == v8) << std::endl; 136 | 137 | v8 &= ~v; 138 | std::cout << "no bit set after &=:\t" << v8.none() << std::endl; 139 | 140 | decltype(v4) v7(32, true); 141 | v7.resize(20); 142 | 143 | std::cout 144 | << "20 visible bits:\t" << v7.to_string() << std::endl 145 | << "lshift by 0:\t\t" << (v7 << 0).to_string() << std::endl 146 | << "lshift by 1:\t\t" << (v7 << 1).to_string() << std::endl 147 | << "rshift by 8:\t\t" << (v7 >> 8).to_string() << std::endl 148 | << "rshift by 9:\t\t" << (v7 >> 9).to_string() << std::endl 149 | ; 150 | 151 | stdex::basic_bitvector< 152 | std::allocator> v9 = stdex::bitvector(64, true); 153 | 154 | std::cout 155 | << "size after conversion:\t" << v9.size() << std::endl 156 | << "all with all bit set:\t" << v9.all() << std::endl 157 | ; 158 | 159 | std::unordered_map m = { 160 | {v, 1}, {v2, 2}, {v3, 4}, {v4, 8} 161 | }; 162 | } 163 | -------------------------------------------------------------------------------- /utility.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 Zhihao Yuan. 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 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef _UTILITY_H 27 | #define _UTILITY_H 1 28 | 29 | #include 30 | #include 31 | 32 | namespace stdex { 33 | 34 | using std::swap; 35 | 36 | // assume T is swappable 37 | template 38 | struct is_nothrow_swappable : 39 | std::integral_constant(), std::declval()))> 41 | {}; 42 | 43 | template 44 | struct compressed_pair : std::tuple 45 | { 46 | typedef T1 first_type; 47 | typedef T2 second_type; 48 | 49 | private: 50 | typedef std::tuple _base; 51 | 52 | public: 53 | constexpr compressed_pair() noexcept( 54 | std::is_nothrow_default_constructible<_base>()) 55 | {} 56 | 57 | constexpr explicit compressed_pair(first_type x) : 58 | _base(std::move(x), {}) 59 | {} 60 | 61 | constexpr explicit compressed_pair(second_type y) : 62 | _base({}, std::move(y)) 63 | {} 64 | 65 | constexpr compressed_pair(first_type x, second_type y) : 66 | _base(std::move(x), std::move(y)) 67 | {} 68 | 69 | /* c++14 */ auto first() noexcept 70 | -> first_type& 71 | { 72 | return std::get<0>(*this); 73 | } 74 | 75 | constexpr auto first() const noexcept 76 | -> first_type const& 77 | { 78 | return std::get<0>(*this); 79 | } 80 | 81 | /* c++14 */ auto second() noexcept 82 | -> second_type& 83 | { 84 | return std::get<1>(*this); 85 | } 86 | 87 | constexpr auto second() const noexcept 88 | -> second_type const& 89 | { 90 | return std::get<1>(*this); 91 | } 92 | }; 93 | 94 | } 95 | 96 | #endif 97 | --------------------------------------------------------------------------------