1 /* 2 * Copyright Michael Schellenberger Costa 3 * Copyright © 2020 Valve Corporation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 */ 25 26 #ifndef ACO_UTIL_H 27 #define ACO_UTIL_H 28 29 #include "util/bitscan.h" 30 #include "util/macros.h" 31 #include "util/u_math.h" 32 33 #include <array> 34 #include <cassert> 35 #include <cstddef> 36 #include <functional> 37 #include <iterator> 38 #include <map> 39 #include <type_traits> 40 #include <unordered_map> 41 #include <vector> 42 43 namespace aco { 44 45 /*! \brief Definition of a span object 46 * 47 * \details A "span" is an "array view" type for holding a view of contiguous 48 * data. The "span" object does not own the data itself. 49 */ 50 template <typename T> class span { 51 public: 52 using value_type = T; 53 using pointer = value_type*; 54 using const_pointer = const value_type*; 55 using reference = value_type&; 56 using const_reference = const value_type&; 57 using iterator = pointer; 58 using const_iterator = const_pointer; 59 using reverse_iterator = std::reverse_iterator<iterator>; 60 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 61 using size_type = uint16_t; 62 using difference_type = std::ptrdiff_t; 63 64 /*! \brief Compiler generated default constructor 65 */ 66 constexpr span() = default; 67 68 /*! \brief Constructor taking a pointer and the length of the span 69 * \param[in] data Pointer to the underlying data array 70 * \param[in] length The size of the span 71 */ span(uint16_t offset_,const size_type length_)72 constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {} 73 74 /*! \brief Returns an iterator to the begin of the span 75 * \return data 76 */ begin()77 constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); } 78 79 /*! \brief Returns a const_iterator to the begin of the span 80 * \return data 81 */ begin()82 constexpr const_iterator begin() const noexcept 83 { 84 return (const_pointer)((uintptr_t)this + offset); 85 } 86 87 /*! \brief Returns an iterator to the end of the span 88 * \return data + length 89 */ end()90 constexpr iterator end() noexcept { return std::next(begin(), length); } 91 92 /*! \brief Returns a const_iterator to the end of the span 93 * \return data + length 94 */ end()95 constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 96 97 /*! \brief Returns a const_iterator to the begin of the span 98 * \return data 99 */ cbegin()100 constexpr const_iterator cbegin() const noexcept { return begin(); } 101 102 /*! \brief Returns a const_iterator to the end of the span 103 * \return data + length 104 */ cend()105 constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 106 107 /*! \brief Returns a reverse_iterator to the end of the span 108 * \return reverse_iterator(end()) 109 */ rbegin()110 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 111 112 /*! \brief Returns a const_reverse_iterator to the end of the span 113 * \return reverse_iterator(end()) 114 */ rbegin()115 constexpr const_reverse_iterator rbegin() const noexcept 116 { 117 return const_reverse_iterator(end()); 118 } 119 120 /*! \brief Returns a reverse_iterator to the begin of the span 121 * \return reverse_iterator(begin()) 122 */ rend()123 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 124 125 /*! \brief Returns a const_reverse_iterator to the begin of the span 126 * \return reverse_iterator(begin()) 127 */ rend()128 constexpr const_reverse_iterator rend() const noexcept 129 { 130 return const_reverse_iterator(begin()); 131 } 132 133 /*! \brief Returns a const_reverse_iterator to the end of the span 134 * \return rbegin() 135 */ crbegin()136 constexpr const_reverse_iterator crbegin() const noexcept 137 { 138 return const_reverse_iterator(cend()); 139 } 140 141 /*! \brief Returns a const_reverse_iterator to the begin of the span 142 * \return rend() 143 */ crend()144 constexpr const_reverse_iterator crend() const noexcept 145 { 146 return const_reverse_iterator(cbegin()); 147 } 148 149 /*! \brief Unchecked access operator 150 * \param[in] index Index of the element we want to access 151 * \return *(std::next(data, index)) 152 */ 153 constexpr reference operator[](const size_type index) noexcept 154 { 155 assert(length > index); 156 return *(std::next(begin(), index)); 157 } 158 159 /*! \brief Unchecked const access operator 160 * \param[in] index Index of the element we want to access 161 * \return *(std::next(data, index)) 162 */ 163 constexpr const_reference operator[](const size_type index) const noexcept 164 { 165 assert(length > index); 166 return *(std::next(begin(), index)); 167 } 168 169 /*! \brief Returns a reference to the last element of the span 170 * \return *(std::next(data, length - 1)) 171 */ back()172 constexpr reference back() noexcept 173 { 174 assert(length > 0); 175 return *(std::next(begin(), length - 1)); 176 } 177 178 /*! \brief Returns a const_reference to the last element of the span 179 * \return *(std::next(data, length - 1)) 180 */ back()181 constexpr const_reference back() const noexcept 182 { 183 assert(length > 0); 184 return *(std::next(begin(), length - 1)); 185 } 186 187 /*! \brief Returns a reference to the first element of the span 188 * \return *begin() 189 */ front()190 constexpr reference front() noexcept 191 { 192 assert(length > 0); 193 return *begin(); 194 } 195 196 /*! \brief Returns a const_reference to the first element of the span 197 * \return *cbegin() 198 */ front()199 constexpr const_reference front() const noexcept 200 { 201 assert(length > 0); 202 return *cbegin(); 203 } 204 205 /*! \brief Returns true if the span is empty 206 * \return length == 0 207 */ empty()208 constexpr bool empty() const noexcept { return length == 0; } 209 210 /*! \brief Returns the size of the span 211 * \return length == 0 212 */ size()213 constexpr size_type size() const noexcept { return length; } 214 215 /*! \brief Decreases the size of the span by 1 216 */ pop_back()217 constexpr void pop_back() noexcept 218 { 219 assert(length > 0); 220 --length; 221 } 222 223 /*! \brief Adds an element to the end of the span 224 */ push_back(const_reference val)225 constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; } 226 227 /*! \brief Clears the span 228 */ clear()229 constexpr void clear() noexcept 230 { 231 offset = 0; 232 length = 0; 233 } 234 235 private: 236 uint16_t offset{0}; //!> Byte offset from span to data 237 size_type length{0}; //!> Size of the span 238 }; 239 240 /* 241 * Cache-friendly set of 32-bit IDs with fast insert/erase/lookup and 242 * the ability to efficiently iterate over contained elements. 243 * 244 * Internally implemented as a map of fixed-size bit vectors: If the set contains an ID, the 245 * corresponding bit in the appropriate bit vector is set. It doesn't use std::vector<bool> since 246 * we then couldn't efficiently iterate over the elements. 247 * 248 * The interface resembles a subset of std::set/std::unordered_set. 249 */ 250 struct IDSet { 251 static const uint32_t block_size = 1024u; 252 using block_t = std::array<uint64_t, block_size / 64>; 253 254 struct Iterator { 255 const IDSet* set; 256 std::map<uint32_t, block_t>::const_iterator block; 257 uint32_t id; 258 259 Iterator& operator++(); 260 261 bool operator!=(const Iterator& other) const; 262 263 uint32_t operator*() const; 264 }; 265 countIDSet266 size_t count(uint32_t id) const { return find(id) != end(); } 267 findIDSet268 Iterator find(uint32_t id) const 269 { 270 uint32_t block_index = id / block_size; 271 auto it = words.find(block_index); 272 if (it == words.end()) 273 return end(); 274 275 const block_t& block = it->second; 276 uint32_t sub_id = id % block_size; 277 278 if (block[sub_id / 64u] & (1ull << (sub_id % 64u))) 279 return Iterator{this, it, id}; 280 else 281 return end(); 282 } 283 insertIDSet284 std::pair<Iterator, bool> insert(uint32_t id) 285 { 286 uint32_t block_index = id / block_size; 287 auto it = words.try_emplace(block_index).first; 288 block_t& block = it->second; 289 uint32_t sub_id = id % block_size; 290 291 uint64_t* word = &block[sub_id / 64u]; 292 uint64_t mask = 1ull << (sub_id % 64u); 293 if (*word & mask) 294 return std::make_pair(Iterator{this, it, id}, false); 295 296 *word |= mask; 297 return std::make_pair(Iterator{this, it, id}, true); 298 } 299 insertIDSet300 bool insert(const IDSet other) 301 { 302 bool inserted = false; 303 304 for (auto it = other.words.begin(); it != other.words.end(); ++it) { 305 block_t& dst = words[it->first]; 306 const block_t& src = it->second; 307 308 for (unsigned j = 0; j < src.size(); j++) { 309 uint64_t new_bits = src[j] & ~dst[j]; 310 if (new_bits) { 311 inserted = true; 312 dst[j] |= new_bits; 313 } 314 } 315 } 316 return inserted; 317 } 318 eraseIDSet319 size_t erase(uint32_t id) 320 { 321 uint32_t block_index = id / block_size; 322 auto it = words.find(block_index); 323 if (it == words.end()) 324 return 0; 325 326 block_t& block = it->second; 327 uint32_t sub_id = id % block_size; 328 329 uint64_t* word = &block[sub_id / 64u]; 330 uint64_t mask = 1ull << (sub_id % 64u); 331 if (!(*word & mask)) 332 return 0; 333 334 *word ^= mask; 335 return 1; 336 } 337 cbeginIDSet338 Iterator cbegin() const 339 { 340 Iterator res; 341 res.set = this; 342 343 for (auto it = words.begin(); it != words.end(); ++it) { 344 uint32_t first = get_first_set(it->second); 345 if (first != UINT32_MAX) { 346 res.block = it; 347 res.id = it->first * block_size + first; 348 return res; 349 } 350 } 351 352 return cend(); 353 } 354 cendIDSet355 Iterator cend() const { return Iterator{this, words.end(), UINT32_MAX}; } 356 beginIDSet357 Iterator begin() const { return cbegin(); } 358 endIDSet359 Iterator end() const { return cend(); } 360 sizeIDSet361 size_t size() const 362 { 363 size_t bits_set = 0; 364 for (auto block : words) { 365 for (uint64_t word : block.second) 366 bits_set += util_bitcount64(word); 367 } 368 return bits_set; 369 } 370 emptyIDSet371 bool empty() const { return !size(); } 372 373 private: get_first_setIDSet374 static uint32_t get_first_set(const block_t& words) 375 { 376 for (size_t i = 0; i < words.size(); i++) { 377 if (words[i]) 378 return i * 64u + (ffsll(words[i]) - 1); 379 } 380 return UINT32_MAX; 381 } 382 383 std::map<uint32_t, block_t> words; 384 }; 385 386 inline IDSet::Iterator& 387 IDSet::Iterator::operator++() 388 { 389 uint32_t block_index = id / block_size; 390 const block_t& block_words = block->second; 391 uint32_t sub_id = id % block_size; 392 393 uint64_t m = block_words[sub_id / 64u]; 394 uint32_t bit = sub_id % 64u; 395 m = (m >> bit) >> 1; 396 if (m) { 397 id += ffsll(m); 398 return *this; 399 } 400 401 for (uint32_t i = sub_id / 64u + 1; i < block_words.size(); i++) { 402 if (block_words[i]) { 403 id = block_index * block_size + i * 64u + ffsll(block_words[i]) - 1; 404 return *this; 405 } 406 } 407 408 for (++block; block != set->words.end(); ++block) { 409 uint32_t first = get_first_set(block->second); 410 if (first != UINT32_MAX) { 411 id = block->first * block_size + first; 412 return *this; 413 } 414 } 415 416 id = UINT32_MAX; 417 return *this; 418 } 419 420 inline bool 421 IDSet::Iterator::operator!=(const IDSet::Iterator& other) const 422 { 423 assert(set == other.set); 424 assert(id != other.id || block == other.block); 425 return id != other.id; 426 } 427 428 inline uint32_t 429 IDSet::Iterator::operator*() const 430 { 431 return id; 432 } 433 434 /* 435 * Light-weight memory resource which allows to sequentially allocate from 436 * a buffer. Both, the release() method and the destructor release all managed 437 * memory. 438 * 439 * The memory resource is not thread-safe. 440 * This class mimics std::pmr::monotonic_buffer_resource 441 */ 442 class monotonic_buffer_resource final { 443 public: 444 explicit monotonic_buffer_resource(size_t size = initial_size) 445 { 446 /* The size parameter refers to the total size of the buffer. 447 * The usable data_size is size - sizeof(Buffer). 448 */ 449 size = MAX2(size, minimum_size); 450 buffer = (Buffer*)malloc(size); 451 buffer->next = nullptr; 452 buffer->data_size = size - sizeof(Buffer); 453 buffer->current_idx = 0; 454 } 455 ~monotonic_buffer_resource()456 ~monotonic_buffer_resource() 457 { 458 release(); 459 free(buffer); 460 } 461 462 /* Delete copy-constructor and -assignment to avoid double free() */ 463 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; 464 monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; 465 allocate(size_t size,size_t alignment)466 void* allocate(size_t size, size_t alignment) 467 { 468 buffer->current_idx = align(buffer->current_idx, alignment); 469 if (buffer->current_idx + size <= buffer->data_size) { 470 uint8_t* ptr = &buffer->data[buffer->current_idx]; 471 buffer->current_idx += size; 472 return ptr; 473 } 474 475 /* create new larger buffer */ 476 uint32_t total_size = buffer->data_size + sizeof(Buffer); 477 do { 478 total_size *= 2; 479 } while (total_size - sizeof(Buffer) < size); 480 Buffer* next = buffer; 481 buffer = (Buffer*)malloc(total_size); 482 buffer->next = next; 483 buffer->data_size = total_size - sizeof(Buffer); 484 buffer->current_idx = 0; 485 486 return allocate(size, alignment); 487 } 488 release()489 void release() 490 { 491 while (buffer->next) { 492 Buffer* next = buffer->next; 493 free(buffer); 494 buffer = next; 495 } 496 buffer->current_idx = 0; 497 } 498 499 bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; } 500 501 private: 502 struct Buffer { 503 Buffer* next; 504 uint32_t current_idx; 505 uint32_t data_size; 506 uint8_t data[]; 507 }; 508 509 Buffer* buffer; 510 static constexpr size_t initial_size = 4096; 511 static constexpr size_t minimum_size = 128; 512 static_assert(minimum_size > sizeof(Buffer)); 513 }; 514 515 /* 516 * Small memory allocator which wraps monotonic_buffer_resource 517 * in order to implement <allocator_traits>. 518 * 519 * This class mimics std::pmr::polymorphic_allocator with monotonic_buffer_resource 520 * as memory resource. The advantage of this specialization is the absence of 521 * virtual function calls and the propagation on swap, copy- and move assignment. 522 */ 523 template <typename T> class monotonic_allocator { 524 public: 525 monotonic_allocator() = delete; monotonic_allocator(monotonic_buffer_resource & m)526 monotonic_allocator(monotonic_buffer_resource& m) : memory_resource(m) {} 527 template <typename U> monotonic_allocator(const monotonic_allocator<U> & rhs)528 explicit monotonic_allocator(const monotonic_allocator<U>& rhs) 529 : memory_resource(rhs.memory_resource) 530 {} 531 532 /* Memory Allocation */ allocate(size_t size)533 T* allocate(size_t size) 534 { 535 uint32_t bytes = sizeof(T) * size; 536 return (T*)memory_resource.get().allocate(bytes, alignof(T)); 537 } 538 539 /* Memory will be freed on destruction of memory_resource */ deallocate(T * ptr,size_t size)540 void deallocate(T* ptr, size_t size) {} 541 542 /* Implement <allocator_traits> */ 543 using value_type = T; 544 template <class U> struct rebind { 545 using other = monotonic_allocator<U>; 546 }; 547 548 typedef std::true_type propagate_on_container_copy_assignment; 549 typedef std::true_type propagate_on_container_move_assignment; 550 typedef std::true_type propagate_on_container_swap; 551 552 template <typename> friend class monotonic_allocator; 553 template <typename X, typename Y> 554 friend bool operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b); 555 template <typename X, typename Y> 556 friend bool operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b); 557 558 private: 559 std::reference_wrapper<monotonic_buffer_resource> memory_resource; 560 }; 561 562 /* Necessary for <allocator_traits>. */ 563 template <typename X, typename Y> 564 inline bool 565 operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b) 566 { 567 return a.memory_resource.get() == b.memory_resource.get(); 568 } 569 template <typename X, typename Y> 570 inline bool 571 operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b) 572 { 573 return !(a == b); 574 } 575 576 /* 577 * aco::map - alias for std::map with monotonic_allocator 578 * 579 * This template specialization mimics std::pmr::map. 580 */ 581 template <class Key, class T, class Compare = std::less<Key>> 582 using map = std::map<Key, T, Compare, aco::monotonic_allocator<std::pair<const Key, T>>>; 583 584 /* 585 * aco::unordered_map - alias for std::unordered_map with monotonic_allocator 586 * 587 * This template specialization mimics std::pmr::unordered_map. 588 */ 589 template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> 590 using unordered_map = 591 std::unordered_map<Key, T, Hash, Pred, aco::monotonic_allocator<std::pair<const Key, T>>>; 592 593 /* 594 * Helper class for a integer/bool (access_type) packed into 595 * a bigger integer (data_type) with an offset and size. 596 * It can be implicitly converted to access_type and supports 597 * all arithmetic assignment operators. 598 * 599 * When used together with a union, this allows storing 600 * multiple fields packed into a single integer. 601 * 602 * Example usage: 603 * union { 604 * bitfield_uint<uint32_t, 0, 5, uint8_t> int5; 605 * bitfield_uint<uint32_t, 5, 26, uint32_t> int26; 606 * bitfield_uint<uint32_t, 31, 1, bool> bool1; 607 * }; 608 * 609 */ 610 template <typename data_type, unsigned offset, unsigned size, typename access_type> 611 class bitfield_uint { 612 public: 613 static_assert(sizeof(data_type) >= sizeof(access_type), ""); 614 static_assert(std::is_unsigned<access_type>::value, ""); 615 static_assert(std::is_unsigned<data_type>::value, ""); 616 static_assert(sizeof(data_type) * 8 >= offset + size, ""); 617 static_assert(sizeof(access_type) * 8 >= size, ""); 618 static_assert(size > 0, ""); 619 static_assert(!std::is_same_v<access_type, bool> || size == 1, ""); 620 621 bitfield_uint() = default; 622 bitfield_uint(const access_type & value)623 constexpr bitfield_uint(const access_type& value) { *this = value; } 624 access_type()625 constexpr operator access_type() const { return (storage >> offset) & mask; } 626 627 constexpr bitfield_uint& operator=(const access_type& value) 628 { 629 storage &= ~(mask << offset); 630 storage |= data_type(value & mask) << offset; 631 return *this; 632 } 633 634 constexpr bitfield_uint& operator=(const bitfield_uint& value) 635 { 636 return *this = access_type(value); 637 } 638 639 constexpr bitfield_uint& operator|=(const access_type& value) 640 { 641 storage |= data_type(value & mask) << offset; 642 return *this; 643 } 644 645 constexpr bitfield_uint& operator^=(const access_type& value) 646 { 647 storage ^= data_type(value & mask) << offset; 648 return *this; 649 } 650 651 constexpr bitfield_uint& operator&=(const access_type& value) 652 { 653 storage &= (data_type(value & mask) << offset) | ~(mask << offset); 654 return *this; 655 } 656 657 constexpr bitfield_uint& operator<<=(const access_type& shift) 658 { 659 static_assert(!std::is_same_v<access_type, bool>, ""); 660 assert(shift < size); 661 return *this = access_type(*this) << shift; 662 } 663 664 constexpr bitfield_uint& operator>>=(const access_type& shift) 665 { 666 static_assert(!std::is_same_v<access_type, bool>, ""); 667 assert(shift < size); 668 return *this = access_type(*this) >> shift; 669 } 670 671 constexpr bitfield_uint& operator*=(const access_type& op) 672 { 673 static_assert(!std::is_same_v<access_type, bool>, ""); 674 return *this = access_type(*this) * op; 675 } 676 677 constexpr bitfield_uint& operator/=(const access_type& op) 678 { 679 static_assert(!std::is_same_v<access_type, bool>, ""); 680 return *this = access_type(*this) / op; 681 } 682 683 constexpr bitfield_uint& operator%=(const access_type& op) 684 { 685 static_assert(!std::is_same_v<access_type, bool>, ""); 686 return *this = access_type(*this) % op; 687 } 688 689 constexpr bitfield_uint& operator+=(const access_type& op) 690 { 691 static_assert(!std::is_same_v<access_type, bool>, ""); 692 return *this = access_type(*this) + op; 693 } 694 695 constexpr bitfield_uint& operator-=(const access_type& op) 696 { 697 static_assert(!std::is_same_v<access_type, bool>, ""); 698 return *this = access_type(*this) - op; 699 } 700 701 constexpr bitfield_uint& operator++() 702 { 703 static_assert(!std::is_same_v<access_type, bool>, ""); 704 return *this += 1; 705 } 706 707 constexpr access_type operator++(int) 708 { 709 static_assert(!std::is_same_v<access_type, bool>, ""); 710 access_type temp = *this; 711 ++*this; 712 return temp; 713 } 714 715 constexpr bitfield_uint& operator--() 716 { 717 static_assert(!std::is_same_v<access_type, bool>, ""); 718 return *this -= 1; 719 } 720 721 constexpr access_type operator--(int) 722 { 723 static_assert(!std::is_same_v<access_type, bool>, ""); 724 access_type temp = *this; 725 --*this; 726 return temp; 727 } 728 swap(access_type & other)729 constexpr void swap(access_type& other) 730 { 731 access_type tmp = *this; 732 *this = other; 733 other = tmp; 734 } 735 736 template <typename other_dt, unsigned other_off, unsigned other_s> swap(bitfield_uint<other_dt,other_off,other_s,access_type> & other)737 constexpr void swap(bitfield_uint<other_dt, other_off, other_s, access_type>& other) 738 { 739 access_type tmp = *this; 740 *this = other; 741 other = tmp; 742 } 743 744 protected: 745 static const data_type mask = BITFIELD64_MASK(size); 746 747 data_type storage; 748 }; 749 750 /* 751 * Reference to a single bit in an integer that can be converted to a bool 752 * and supports bool (bitwise) assignment operators. 753 */ 754 template <typename T> struct bit_reference { bit_referencebit_reference755 constexpr bit_reference(T& s, unsigned b) : storage(s), bit(b) {} 756 757 constexpr bit_reference& operator=(const bit_reference& other) { return *this = (bool)other; } 758 759 constexpr bit_reference& operator=(bool val) 760 { 761 storage &= ~(T(0x1) << bit); 762 storage |= T(val) << bit; 763 return *this; 764 } 765 766 constexpr bit_reference& operator^=(bool val) 767 { 768 storage ^= T(val) << bit; 769 return *this; 770 } 771 772 constexpr bit_reference& operator|=(bool val) 773 { 774 storage |= T(val) << bit; 775 return *this; 776 } 777 778 constexpr bit_reference& operator&=(bool val) 779 { 780 storage &= T(val) << bit; 781 return *this; 782 } 783 784 constexpr operator bool() const { return (storage >> bit) & 0x1; } 785 swapbit_reference786 constexpr void swap(bool& other) 787 { 788 bool tmp = (bool)*this; 789 *this = other; 790 other = tmp; 791 } 792 swapbit_reference793 template <typename other_T> constexpr void swap(bit_reference<other_T> other) 794 { 795 bool tmp = (bool)*this; 796 *this = (bool)other; 797 other = tmp; 798 } 799 800 T& storage; 801 unsigned bit; 802 }; 803 804 /* 805 * Base template for (const) bit iterators over an integer. 806 * Only intended to be used with the two specializations 807 * bitfield_array::iterator and bitfield_array::const_iterator. 808 */ 809 template <typename T, typename refT, typename ptrT> struct bitfield_iterator { 810 using difference_type = int; 811 using value_type = bool; 812 using iterator_category = std::random_access_iterator_tag; 813 using reference = refT; 814 using const_reference = bool; 815 using pointer = ptrT; 816 using iterator = bitfield_iterator<T, refT, ptrT>; 817 using ncT = std::remove_const_t<T>; 818 bitfield_iteratorbitfield_iterator819 constexpr bitfield_iterator() : bf(nullptr), index(0) {} bitfield_iteratorbitfield_iterator820 constexpr bitfield_iterator(T* p, unsigned i) : bf(p), index(i) {} 821 822 /* const iterator must be constructable from iterator */ bitfield_iteratorbitfield_iterator823 constexpr bitfield_iterator( 824 const bitfield_iterator<ncT, bit_reference<ncT>, bit_reference<ncT>*>& x) 825 : bf(x.bf), index(x.index) 826 {} 827 828 constexpr bool operator==(const bitfield_iterator& other) const 829 { 830 return bf == other.bf && index == other.index; 831 } 832 833 constexpr bool operator<(const bitfield_iterator& other) const { return index < other.index; } 834 835 constexpr bool operator!=(const bitfield_iterator& other) const { return !(*this == other); } 836 837 constexpr bool operator>(const bitfield_iterator& other) const { return other < *this; } 838 839 constexpr bool operator<=(const bitfield_iterator& other) const { return !(other < *this); } 840 841 constexpr bool operator>=(const bitfield_iterator& other) const { return !(*this < other); } 842 843 constexpr reference operator*() const { return bit_reference<T>(*bf, index); } 844 845 constexpr iterator& operator++() 846 { 847 index++; 848 return *this; 849 } 850 851 constexpr iterator operator++(int) 852 { 853 iterator tmp = *this; 854 index++; 855 return tmp; 856 } 857 858 constexpr iterator& operator--() 859 { 860 index--; 861 return *this; 862 } 863 864 constexpr iterator operator--(int) 865 { 866 iterator tmp = *this; 867 index--; 868 return tmp; 869 } 870 871 constexpr iterator& operator+=(difference_type value) 872 { 873 index += value; 874 return *this; 875 } 876 877 constexpr iterator& operator-=(difference_type value) 878 { 879 *this += -value; 880 return *this; 881 } 882 883 constexpr iterator operator+(difference_type value) const 884 { 885 iterator tmp = *this; 886 return tmp += value; 887 } 888 889 constexpr iterator operator-(difference_type value) const 890 { 891 iterator tmp = *this; 892 return tmp -= value; 893 } 894 895 constexpr reference operator[](difference_type value) const { return *(*this + value); } 896 897 T* bf; 898 unsigned index; 899 }; 900 901 template <typename T, typename refT, typename ptrT> 902 constexpr inline bitfield_iterator<T, refT, ptrT> 903 operator+(int n, const bitfield_iterator<T, refT, ptrT>& x) 904 { 905 return x + n; 906 } 907 908 template <typename T, typename refT, typename ptrT> 909 constexpr inline int 910 operator-(const bitfield_iterator<T, refT, ptrT> x, const bitfield_iterator<T, refT, ptrT>& y) 911 { 912 return x.index - y.index; 913 } 914 915 /* 916 * Extends bitfield_uint with operator[] and iterators that 917 * allow accessing single bits within the uint. Can be used 918 * as a more compact version of bool arrays that also still 919 * allows accessing the whole array as an integer. 920 */ 921 template <typename data_type, unsigned offset, unsigned size, typename access_type> 922 class bitfield_array : public bitfield_uint<data_type, offset, size, access_type> { 923 public: 924 using value_type = bool; 925 using size_type = unsigned; 926 using difference_type = int; 927 using reference = bit_reference<data_type>; 928 using const_reference = bool; 929 using pointer = bit_reference<data_type>*; 930 using const_pointer = const bool*; 931 using iterator = 932 bitfield_iterator<data_type, bit_reference<data_type>, bit_reference<data_type>*>; 933 using const_iterator = bitfield_iterator<const data_type, bool, const bool*>; 934 using reverse_iterator = std::reverse_iterator<iterator>; 935 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 936 937 bitfield_array() = default; 938 bitfield_array(const access_type & value)939 constexpr bitfield_array(const access_type& value) { *this = value; } 940 941 constexpr bitfield_array& operator=(const access_type& value) 942 { 943 storage &= ~(mask << offset); 944 storage |= data_type(value & mask) << offset; 945 return *this; 946 } 947 948 constexpr bitfield_array& operator=(const bitfield_array& value) 949 { 950 return *this = access_type(value); 951 } 952 953 constexpr reference operator[](unsigned index) 954 { 955 assert(index < size); 956 return reference(storage, offset + index); 957 } 958 959 constexpr bool operator[](unsigned index) const 960 { 961 assert(index < size); 962 return (storage >> (offset + index)) & 0x1; 963 } 964 begin()965 constexpr iterator begin() noexcept { return iterator(&storage, offset); } 966 end()967 constexpr iterator end() noexcept { return std::next(begin(), size); } 968 begin()969 constexpr const_iterator begin() const noexcept { return const_iterator(&storage, offset); } 970 end()971 constexpr const_iterator end() const noexcept { return std::next(begin(), size); } 972 cbegin()973 constexpr const_iterator cbegin() const noexcept { return begin(); } 974 cend()975 constexpr const_iterator cend() const noexcept { return std::next(begin(), size); } 976 rbegin()977 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 978 rend()979 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 980 rbegin()981 constexpr const_reverse_iterator rbegin() const noexcept 982 { 983 return const_reverse_iterator(end()); 984 } 985 rend()986 constexpr const_reverse_iterator rend() const noexcept 987 { 988 return const_reverse_iterator(begin()); 989 } 990 crbegin()991 constexpr const_reverse_iterator crbegin() const noexcept 992 { 993 return const_reverse_iterator(cend()); 994 } 995 crend()996 constexpr const_reverse_iterator crend() const noexcept 997 { 998 return const_reverse_iterator(cbegin()); 999 } 1000 1001 private: 1002 using bitfield_uint<data_type, offset, size, access_type>::storage; 1003 using bitfield_uint<data_type, offset, size, access_type>::mask; 1004 }; 1005 1006 template <typename T, unsigned offset> using bitfield_bool = bitfield_uint<T, offset, 1, bool>; 1007 1008 template <typename T, unsigned offset, unsigned size> 1009 using bitfield_uint8 = bitfield_uint<T, offset, size, uint8_t>; 1010 1011 template <typename T, unsigned offset, unsigned size> 1012 using bitfield_uint16 = bitfield_uint<T, offset, size, uint16_t>; 1013 1014 template <typename T, unsigned offset, unsigned size> 1015 using bitfield_uint32 = bitfield_uint<T, offset, size, uint32_t>; 1016 1017 template <typename T, unsigned offset, unsigned size> 1018 using bitfield_uint64 = bitfield_uint<T, offset, size, uint64_t>; 1019 1020 template <typename T, unsigned offset, unsigned size> 1021 using bitfield_array8 = bitfield_array<T, offset, size, uint8_t>; 1022 1023 template <typename T, unsigned offset, unsigned size> 1024 using bitfield_array16 = bitfield_array<T, offset, size, uint16_t>; 1025 1026 template <typename T, unsigned offset, unsigned size> 1027 using bitfield_array32 = bitfield_array<T, offset, size, uint32_t>; 1028 1029 template <typename T, unsigned offset, unsigned size> 1030 using bitfield_array64 = bitfield_array<T, offset, size, uint64_t>; 1031 1032 using bitarray8 = bitfield_array<uint8_t, 0, 8, uint8_t>; 1033 1034 } // namespace aco 1035 1036 #endif // ACO_UTIL_H 1037