1 /* 2 * Copyright Michael Schellenberger Costa 3 * Copyright © 2020 Valve Corporation 4 * 5 * SPDX-License-Identifier: MIT 6 */ 7 8 #ifndef ACO_UTIL_H 9 #define ACO_UTIL_H 10 11 #include "util/bitscan.h" 12 #include "util/macros.h" 13 #include "util/u_math.h" 14 15 #include <array> 16 #include <cassert> 17 #include <cstddef> 18 #include <functional> 19 #include <iterator> 20 #include <map> 21 #include <memory> 22 #include <type_traits> 23 #include <unordered_map> 24 #include <vector> 25 26 namespace aco { 27 28 /*! \brief Definition of a span object 29 * 30 * \details A "span" is an "array view" type for holding a view of contiguous 31 * data. The "span" object does not own the data itself. 32 */ 33 template <typename T> class span { 34 public: 35 using value_type = T; 36 using pointer = value_type*; 37 using const_pointer = const value_type*; 38 using reference = value_type&; 39 using const_reference = const value_type&; 40 using iterator = pointer; 41 using const_iterator = const_pointer; 42 using reverse_iterator = std::reverse_iterator<iterator>; 43 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 44 using size_type = uint16_t; 45 using difference_type = std::ptrdiff_t; 46 47 /*! \brief Compiler generated default constructor 48 */ 49 constexpr span() = default; 50 51 /*! \brief Constructor taking a pointer and the length of the span 52 * \param[in] data Pointer to the underlying data array 53 * \param[in] length The size of the span 54 */ span(uint16_t offset_,const size_type length_)55 constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {} 56 57 /*! \brief Returns an iterator to the begin of the span 58 * \return data 59 */ begin()60 constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); } 61 62 /*! \brief Returns a const_iterator to the begin of the span 63 * \return data 64 */ begin()65 constexpr const_iterator begin() const noexcept 66 { 67 return (const_pointer)((uintptr_t)this + offset); 68 } 69 70 /*! \brief Returns an iterator to the end of the span 71 * \return data + length 72 */ end()73 constexpr iterator end() noexcept { return std::next(begin(), length); } 74 75 /*! \brief Returns a const_iterator to the end of the span 76 * \return data + length 77 */ end()78 constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 79 80 /*! \brief Returns a const_iterator to the begin of the span 81 * \return data 82 */ cbegin()83 constexpr const_iterator cbegin() const noexcept { return begin(); } 84 85 /*! \brief Returns a const_iterator to the end of the span 86 * \return data + length 87 */ cend()88 constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 89 90 /*! \brief Returns a reverse_iterator to the end of the span 91 * \return reverse_iterator(end()) 92 */ rbegin()93 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 94 95 /*! \brief Returns a const_reverse_iterator to the end of the span 96 * \return reverse_iterator(end()) 97 */ rbegin()98 constexpr const_reverse_iterator rbegin() const noexcept 99 { 100 return const_reverse_iterator(end()); 101 } 102 103 /*! \brief Returns a reverse_iterator to the begin of the span 104 * \return reverse_iterator(begin()) 105 */ rend()106 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 107 108 /*! \brief Returns a const_reverse_iterator to the begin of the span 109 * \return reverse_iterator(begin()) 110 */ rend()111 constexpr const_reverse_iterator rend() const noexcept 112 { 113 return const_reverse_iterator(begin()); 114 } 115 116 /*! \brief Returns a const_reverse_iterator to the end of the span 117 * \return rbegin() 118 */ crbegin()119 constexpr const_reverse_iterator crbegin() const noexcept 120 { 121 return const_reverse_iterator(cend()); 122 } 123 124 /*! \brief Returns a const_reverse_iterator to the begin of the span 125 * \return rend() 126 */ crend()127 constexpr const_reverse_iterator crend() const noexcept 128 { 129 return const_reverse_iterator(cbegin()); 130 } 131 132 /*! \brief Unchecked access operator 133 * \param[in] index Index of the element we want to access 134 * \return *(std::next(data, index)) 135 */ 136 constexpr reference operator[](const size_type index) noexcept 137 { 138 assert(length > index); 139 return *(std::next(begin(), index)); 140 } 141 142 /*! \brief Unchecked const access operator 143 * \param[in] index Index of the element we want to access 144 * \return *(std::next(data, index)) 145 */ 146 constexpr const_reference operator[](const size_type index) const noexcept 147 { 148 assert(length > index); 149 return *(std::next(begin(), index)); 150 } 151 152 /*! \brief Returns a reference to the last element of the span 153 * \return *(std::next(data, length - 1)) 154 */ back()155 constexpr reference back() noexcept 156 { 157 assert(length > 0); 158 return *(std::next(begin(), length - 1)); 159 } 160 161 /*! \brief Returns a const_reference to the last element of the span 162 * \return *(std::next(data, length - 1)) 163 */ back()164 constexpr const_reference back() const noexcept 165 { 166 assert(length > 0); 167 return *(std::next(begin(), length - 1)); 168 } 169 170 /*! \brief Returns a reference to the first element of the span 171 * \return *begin() 172 */ front()173 constexpr reference front() noexcept 174 { 175 assert(length > 0); 176 return *begin(); 177 } 178 179 /*! \brief Returns a const_reference to the first element of the span 180 * \return *cbegin() 181 */ front()182 constexpr const_reference front() const noexcept 183 { 184 assert(length > 0); 185 return *cbegin(); 186 } 187 188 /*! \brief Returns true if the span is empty 189 * \return length == 0 190 */ empty()191 constexpr bool empty() const noexcept { return length == 0; } 192 193 /*! \brief Returns the size of the span 194 * \return length == 0 195 */ size()196 constexpr size_type size() const noexcept { return length; } 197 198 /*! \brief Decreases the size of the span by 1 199 */ pop_back()200 constexpr void pop_back() noexcept 201 { 202 assert(length > 0); 203 --length; 204 } 205 206 /*! \brief Adds an element to the end of the span 207 */ push_back(const_reference val)208 constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; } 209 210 /*! \brief Clears the span 211 */ clear()212 constexpr void clear() noexcept 213 { 214 offset = 0; 215 length = 0; 216 } 217 218 private: 219 uint16_t offset{0}; //!> Byte offset from span to data 220 size_type length{0}; //!> Size of the span 221 }; 222 223 /* 224 * Light-weight memory resource which allows to sequentially allocate from 225 * a buffer. Both, the release() method and the destructor release all managed 226 * memory. 227 * 228 * The memory resource is not thread-safe. 229 * This class mimics std::pmr::monotonic_buffer_resource 230 */ 231 class monotonic_buffer_resource final { 232 public: 233 explicit monotonic_buffer_resource(size_t size = initial_size) 234 { 235 /* The size parameter refers to the total size of the buffer. 236 * The usable data_size is size - sizeof(Buffer). 237 */ 238 size = MAX2(size, minimum_size); 239 buffer = (Buffer*)malloc(size); 240 buffer->next = nullptr; 241 buffer->data_size = size - sizeof(Buffer); 242 buffer->current_idx = 0; 243 } 244 ~monotonic_buffer_resource()245 ~monotonic_buffer_resource() 246 { 247 release(); 248 free(buffer); 249 } 250 251 /* Move-constructor and -assignment */ monotonic_buffer_resource(monotonic_buffer_resource && other)252 monotonic_buffer_resource(monotonic_buffer_resource&& other) : monotonic_buffer_resource() 253 { 254 *this = std::move(other); 255 } 256 monotonic_buffer_resource& operator=(monotonic_buffer_resource&& other) 257 { 258 release(); 259 std::swap(buffer, other.buffer); 260 return *this; 261 } 262 263 /* Delete copy-constructor and -assignment to avoid double free() */ 264 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; 265 monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; 266 allocate(size_t size,size_t alignment)267 void* allocate(size_t size, size_t alignment) 268 { 269 buffer->current_idx = align(buffer->current_idx, alignment); 270 if (buffer->current_idx + size <= buffer->data_size) { 271 uint8_t* ptr = &buffer->data[buffer->current_idx]; 272 buffer->current_idx += size; 273 return ptr; 274 } 275 276 /* create new larger buffer */ 277 uint32_t total_size = buffer->data_size + sizeof(Buffer); 278 do { 279 total_size *= 2; 280 } while (total_size - sizeof(Buffer) < size); 281 Buffer* next = buffer; 282 buffer = (Buffer*)malloc(total_size); 283 buffer->next = next; 284 buffer->data_size = total_size - sizeof(Buffer); 285 buffer->current_idx = 0; 286 287 return allocate(size, alignment); 288 } 289 release()290 void release() 291 { 292 while (buffer->next) { 293 Buffer* next = buffer->next; 294 free(buffer); 295 buffer = next; 296 } 297 buffer->current_idx = 0; 298 } 299 300 bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; } 301 302 private: 303 struct Buffer { 304 Buffer* next; 305 uint32_t current_idx; 306 uint32_t data_size; 307 uint8_t data[]; 308 }; 309 310 Buffer* buffer; 311 static constexpr size_t initial_size = 4096; 312 static constexpr size_t minimum_size = 128; 313 static_assert(minimum_size > sizeof(Buffer)); 314 }; 315 316 /* 317 * Small memory allocator which wraps monotonic_buffer_resource 318 * in order to implement <allocator_traits>. 319 * 320 * This class mimics std::pmr::polymorphic_allocator with monotonic_buffer_resource 321 * as memory resource. The advantage of this specialization is the absence of 322 * virtual function calls and the propagation on swap, copy- and move assignment. 323 */ 324 template <typename T> class monotonic_allocator { 325 public: 326 monotonic_allocator() = delete; monotonic_allocator(monotonic_buffer_resource & m)327 monotonic_allocator(monotonic_buffer_resource& m) : memory_resource(m) {} 328 template <typename U> monotonic_allocator(const monotonic_allocator<U> & rhs)329 explicit monotonic_allocator(const monotonic_allocator<U>& rhs) 330 : memory_resource(rhs.memory_resource) 331 {} 332 333 /* Memory Allocation */ allocate(size_t size)334 T* allocate(size_t size) 335 { 336 uint32_t bytes = sizeof(T) * size; 337 return (T*)memory_resource.get().allocate(bytes, alignof(T)); 338 } 339 340 /* Memory will be freed on destruction of memory_resource */ deallocate(T * ptr,size_t size)341 void deallocate(T* ptr, size_t size) {} 342 343 /* Implement <allocator_traits> */ 344 using value_type = T; 345 template <class U> struct rebind { 346 using other = monotonic_allocator<U>; 347 }; 348 349 typedef std::true_type propagate_on_container_copy_assignment; 350 typedef std::true_type propagate_on_container_move_assignment; 351 typedef std::true_type propagate_on_container_swap; 352 353 template <typename> friend class monotonic_allocator; 354 template <typename X, typename Y> 355 friend bool operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b); 356 template <typename X, typename Y> 357 friend bool operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b); 358 359 private: 360 std::reference_wrapper<monotonic_buffer_resource> memory_resource; 361 }; 362 363 /* Necessary for <allocator_traits>. */ 364 template <typename X, typename Y> 365 inline bool 366 operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b) 367 { 368 return a.memory_resource.get() == b.memory_resource.get(); 369 } 370 template <typename X, typename Y> 371 inline bool 372 operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b) 373 { 374 return !(a == b); 375 } 376 377 /* 378 * aco::map - alias for std::map with monotonic_allocator 379 * 380 * This template specialization mimics std::pmr::map. 381 */ 382 template <class Key, class T, class Compare = std::less<Key>> 383 using map = std::map<Key, T, Compare, aco::monotonic_allocator<std::pair<const Key, T>>>; 384 385 /* 386 * aco::unordered_map - alias for std::unordered_map with monotonic_allocator 387 * 388 * This template specialization mimics std::pmr::unordered_map. 389 */ 390 template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> 391 using unordered_map = 392 std::unordered_map<Key, T, Hash, Pred, aco::monotonic_allocator<std::pair<const Key, T>>>; 393 394 /* 395 * Cache-friendly set of 32-bit IDs with fast insert/erase/lookup and 396 * the ability to efficiently iterate over contained elements. 397 * 398 * Internally implemented as a map of fixed-size bit vectors: If the set contains an ID, the 399 * corresponding bit in the appropriate bit vector is set. It doesn't use std::vector<bool> since 400 * we then couldn't efficiently iterate over the elements. 401 * 402 * The interface resembles a subset of std::set/std::unordered_set. 403 */ 404 struct IDSet { 405 static const uint32_t block_size = 1024u; 406 using block_t = std::array<uint64_t, block_size / 64>; 407 408 struct Iterator { 409 const IDSet* set; 410 aco::map<uint32_t, block_t>::const_iterator block; 411 uint32_t id; 412 413 Iterator& operator++(); 414 415 bool operator!=(const Iterator& other) const; 416 417 uint32_t operator*() const; 418 }; 419 countIDSet420 size_t count(uint32_t id) const { return find(id) != end(); } 421 findIDSet422 Iterator find(uint32_t id) const 423 { 424 uint32_t block_index = id / block_size; 425 auto it = words.find(block_index); 426 if (it == words.end()) 427 return end(); 428 429 const block_t& block = it->second; 430 uint32_t sub_id = id % block_size; 431 432 if (block[sub_id / 64u] & (1ull << (sub_id % 64u))) 433 return Iterator{this, it, id}; 434 else 435 return end(); 436 } 437 insertIDSet438 std::pair<Iterator, bool> insert(uint32_t id) 439 { 440 uint32_t block_index = id / block_size; 441 auto it = words.try_emplace(block_index).first; 442 block_t& block = it->second; 443 uint32_t sub_id = id % block_size; 444 445 uint64_t* word = &block[sub_id / 64u]; 446 uint64_t mask = 1ull << (sub_id % 64u); 447 if (*word & mask) 448 return std::make_pair(Iterator{this, it, id}, false); 449 450 *word |= mask; 451 return std::make_pair(Iterator{this, it, id}, true); 452 } 453 insertIDSet454 bool insert(const IDSet other) 455 { 456 bool inserted = false; 457 458 for (auto it = other.words.begin(); it != other.words.end(); ++it) { 459 const block_t& src = it->second; 460 if (src == block_t{0}) 461 continue; 462 463 block_t& dst = words[it->first]; 464 for (unsigned j = 0; j < src.size(); j++) { 465 uint64_t new_bits = src[j] & ~dst[j]; 466 if (new_bits) { 467 inserted = true; 468 dst[j] |= new_bits; 469 } 470 } 471 } 472 return inserted; 473 } 474 eraseIDSet475 size_t erase(uint32_t id) 476 { 477 uint32_t block_index = id / block_size; 478 auto it = words.find(block_index); 479 if (it == words.end()) 480 return 0; 481 482 block_t& block = it->second; 483 uint32_t sub_id = id % block_size; 484 485 uint64_t* word = &block[sub_id / 64u]; 486 uint64_t mask = 1ull << (sub_id % 64u); 487 if (!(*word & mask)) 488 return 0; 489 490 *word ^= mask; 491 return 1; 492 } 493 cbeginIDSet494 Iterator cbegin() const 495 { 496 Iterator res; 497 res.set = this; 498 499 for (auto it = words.begin(); it != words.end(); ++it) { 500 uint32_t first = get_first_set(it->second); 501 if (first != UINT32_MAX) { 502 res.block = it; 503 res.id = it->first * block_size + first; 504 return res; 505 } 506 } 507 508 return cend(); 509 } 510 cendIDSet511 Iterator cend() const { return Iterator{this, words.end(), UINT32_MAX}; } 512 beginIDSet513 Iterator begin() const { return cbegin(); } 514 endIDSet515 Iterator end() const { return cend(); } 516 sizeIDSet517 size_t size() const 518 { 519 size_t bits_set = 0; 520 for (auto block : words) { 521 for (uint64_t word : block.second) 522 bits_set += util_bitcount64(word); 523 } 524 return bits_set; 525 } 526 emptyIDSet527 bool empty() const { return !size(); } 528 IDSetIDSet529 explicit IDSet(monotonic_buffer_resource& m) : words(m) {} IDSetIDSet530 explicit IDSet(const IDSet& other, monotonic_buffer_resource& m) : words(other.words, m) {} 531 532 bool operator==(const IDSet& other) const 533 { 534 auto it = words.begin(); 535 for (auto block : other.words) { 536 if (block.second == block_t{0}) 537 continue; 538 while (it != words.end() && it->second == block_t{0}) 539 it++; 540 if (it == words.end() || block != *it) 541 return false; 542 it++; 543 } 544 545 return true; 546 } 547 bool operator!=(const IDSet& other) const { return !(*this == other); } 548 549 private: get_first_setIDSet550 static uint32_t get_first_set(const block_t& words) 551 { 552 for (size_t i = 0; i < words.size(); i++) { 553 if (words[i]) 554 return i * 64u + (ffsll(words[i]) - 1); 555 } 556 return UINT32_MAX; 557 } 558 559 aco::map<uint32_t, block_t> words; 560 }; 561 562 inline IDSet::Iterator& 563 IDSet::Iterator::operator++() 564 { 565 uint32_t block_index = id / block_size; 566 const block_t& block_words = block->second; 567 uint32_t sub_id = id % block_size; 568 569 uint64_t m = block_words[sub_id / 64u]; 570 uint32_t bit = sub_id % 64u; 571 m = (m >> bit) >> 1; 572 if (m) { 573 id += ffsll(m); 574 return *this; 575 } 576 577 for (uint32_t i = sub_id / 64u + 1; i < block_words.size(); i++) { 578 if (block_words[i]) { 579 id = block_index * block_size + i * 64u + ffsll(block_words[i]) - 1; 580 return *this; 581 } 582 } 583 584 for (++block; block != set->words.end(); ++block) { 585 uint32_t first = get_first_set(block->second); 586 if (first != UINT32_MAX) { 587 id = block->first * block_size + first; 588 return *this; 589 } 590 } 591 592 id = UINT32_MAX; 593 return *this; 594 } 595 596 inline bool 597 IDSet::Iterator::operator!=(const IDSet::Iterator& other) const 598 { 599 assert(set == other.set); 600 assert(id != other.id || block == other.block); 601 return id != other.id; 602 } 603 604 inline uint32_t 605 IDSet::Iterator::operator*() const 606 { 607 return id; 608 } 609 610 /* 611 * Helper class for a integer/bool (access_type) packed into 612 * a bigger integer (data_type) with an offset and size. 613 * It can be implicitly converted to access_type and supports 614 * all arithmetic assignment operators. 615 * 616 * When used together with a union, this allows storing 617 * multiple fields packed into a single integer. 618 * 619 * Example usage: 620 * union { 621 * bitfield_uint<uint32_t, 0, 5, uint8_t> int5; 622 * bitfield_uint<uint32_t, 5, 26, uint32_t> int26; 623 * bitfield_uint<uint32_t, 31, 1, bool> bool1; 624 * }; 625 * 626 */ 627 template <typename data_type, unsigned offset, unsigned size, typename access_type> 628 class bitfield_uint { 629 public: 630 static_assert(sizeof(data_type) >= sizeof(access_type), ""); 631 static_assert(std::is_unsigned<access_type>::value, ""); 632 static_assert(std::is_unsigned<data_type>::value, ""); 633 static_assert(sizeof(data_type) * 8 >= offset + size, ""); 634 static_assert(sizeof(access_type) * 8 >= size, ""); 635 static_assert(size > 0, ""); 636 static_assert(!std::is_same_v<access_type, bool> || size == 1, ""); 637 638 bitfield_uint() = default; 639 bitfield_uint(const access_type & value)640 constexpr bitfield_uint(const access_type& value) { *this = value; } 641 access_type()642 constexpr operator access_type() const { return (storage >> offset) & mask; } 643 644 constexpr bitfield_uint& operator=(const access_type& value) 645 { 646 storage &= ~(mask << offset); 647 storage |= data_type(value & mask) << offset; 648 return *this; 649 } 650 651 constexpr bitfield_uint& operator=(const bitfield_uint& value) 652 { 653 return *this = access_type(value); 654 } 655 656 constexpr bitfield_uint& operator|=(const access_type& value) 657 { 658 storage |= data_type(value & mask) << offset; 659 return *this; 660 } 661 662 constexpr bitfield_uint& operator^=(const access_type& value) 663 { 664 storage ^= data_type(value & mask) << offset; 665 return *this; 666 } 667 668 constexpr bitfield_uint& operator&=(const access_type& value) 669 { 670 storage &= (data_type(value & mask) << offset) | ~(mask << offset); 671 return *this; 672 } 673 674 constexpr bitfield_uint& operator<<=(const access_type& shift) 675 { 676 static_assert(!std::is_same_v<access_type, bool>, ""); 677 assert(shift < size); 678 return *this = access_type(*this) << shift; 679 } 680 681 constexpr bitfield_uint& operator>>=(const access_type& shift) 682 { 683 static_assert(!std::is_same_v<access_type, bool>, ""); 684 assert(shift < size); 685 return *this = access_type(*this) >> shift; 686 } 687 688 constexpr bitfield_uint& operator*=(const access_type& op) 689 { 690 static_assert(!std::is_same_v<access_type, bool>, ""); 691 return *this = access_type(*this) * op; 692 } 693 694 constexpr bitfield_uint& operator/=(const access_type& op) 695 { 696 static_assert(!std::is_same_v<access_type, bool>, ""); 697 return *this = access_type(*this) / op; 698 } 699 700 constexpr bitfield_uint& operator%=(const access_type& op) 701 { 702 static_assert(!std::is_same_v<access_type, bool>, ""); 703 return *this = access_type(*this) % op; 704 } 705 706 constexpr bitfield_uint& operator+=(const access_type& op) 707 { 708 static_assert(!std::is_same_v<access_type, bool>, ""); 709 return *this = access_type(*this) + op; 710 } 711 712 constexpr bitfield_uint& operator-=(const access_type& op) 713 { 714 static_assert(!std::is_same_v<access_type, bool>, ""); 715 return *this = access_type(*this) - op; 716 } 717 718 constexpr bitfield_uint& operator++() 719 { 720 static_assert(!std::is_same_v<access_type, bool>, ""); 721 return *this += 1; 722 } 723 724 constexpr access_type operator++(int) 725 { 726 static_assert(!std::is_same_v<access_type, bool>, ""); 727 access_type temp = *this; 728 ++*this; 729 return temp; 730 } 731 732 constexpr bitfield_uint& operator--() 733 { 734 static_assert(!std::is_same_v<access_type, bool>, ""); 735 return *this -= 1; 736 } 737 738 constexpr access_type operator--(int) 739 { 740 static_assert(!std::is_same_v<access_type, bool>, ""); 741 access_type temp = *this; 742 --*this; 743 return temp; 744 } 745 swap(access_type & other)746 constexpr void swap(access_type& other) 747 { 748 access_type tmp = *this; 749 *this = other; 750 other = tmp; 751 } 752 753 template <typename other_dt, unsigned other_off, unsigned other_s> swap(bitfield_uint<other_dt,other_off,other_s,access_type> & other)754 constexpr void swap(bitfield_uint<other_dt, other_off, other_s, access_type>& other) 755 { 756 access_type tmp = *this; 757 *this = other; 758 other = tmp; 759 } 760 761 protected: 762 static const data_type mask = BITFIELD64_MASK(size); 763 764 data_type storage; 765 }; 766 767 /* 768 * Reference to a single bit in an integer that can be converted to a bool 769 * and supports bool (bitwise) assignment operators. 770 */ 771 template <typename T> struct bit_reference { bit_referencebit_reference772 constexpr bit_reference(T& s, unsigned b) : storage(s), bit(b) {} 773 774 constexpr bit_reference& operator=(const bit_reference& other) { return *this = (bool)other; } 775 776 constexpr bit_reference& operator=(bool val) 777 { 778 storage &= ~(T(0x1) << bit); 779 storage |= T(val) << bit; 780 return *this; 781 } 782 783 constexpr bit_reference& operator^=(bool val) 784 { 785 storage ^= T(val) << bit; 786 return *this; 787 } 788 789 constexpr bit_reference& operator|=(bool val) 790 { 791 storage |= T(val) << bit; 792 return *this; 793 } 794 795 constexpr bit_reference& operator&=(bool val) 796 { 797 storage &= ~(T(!val) << bit); 798 return *this; 799 } 800 801 constexpr operator bool() const { return (storage >> bit) & 0x1; } 802 swapbit_reference803 constexpr void swap(bool& other) 804 { 805 bool tmp = (bool)*this; 806 *this = other; 807 other = tmp; 808 } 809 swapbit_reference810 template <typename other_T> constexpr void swap(bit_reference<other_T> other) 811 { 812 bool tmp = (bool)*this; 813 *this = (bool)other; 814 other = tmp; 815 } 816 817 T& storage; 818 unsigned bit; 819 }; 820 821 /* 822 * Base template for (const) bit iterators over an integer. 823 * Only intended to be used with the two specializations 824 * bitfield_array::iterator and bitfield_array::const_iterator. 825 */ 826 template <typename T, typename refT, typename ptrT> struct bitfield_iterator { 827 using difference_type = int; 828 using value_type = bool; 829 using iterator_category = std::random_access_iterator_tag; 830 using reference = refT; 831 using const_reference = bool; 832 using pointer = ptrT; 833 using iterator = bitfield_iterator<T, refT, ptrT>; 834 using ncT = std::remove_const_t<T>; 835 bitfield_iteratorbitfield_iterator836 constexpr bitfield_iterator() : bf(nullptr), index(0) {} bitfield_iteratorbitfield_iterator837 constexpr bitfield_iterator(T* p, unsigned i) : bf(p), index(i) {} 838 839 /* const iterator must be constructable from iterator */ bitfield_iteratorbitfield_iterator840 constexpr bitfield_iterator( 841 const bitfield_iterator<ncT, bit_reference<ncT>, bit_reference<ncT>*>& x) 842 : bf(x.bf), index(x.index) 843 {} 844 845 constexpr bool operator==(const bitfield_iterator& other) const 846 { 847 return bf == other.bf && index == other.index; 848 } 849 850 constexpr bool operator<(const bitfield_iterator& other) const { return index < other.index; } 851 852 constexpr bool operator!=(const bitfield_iterator& other) const { return !(*this == other); } 853 854 constexpr bool operator>(const bitfield_iterator& other) const { return other < *this; } 855 856 constexpr bool operator<=(const bitfield_iterator& other) const { return !(other < *this); } 857 858 constexpr bool operator>=(const bitfield_iterator& other) const { return !(*this < other); } 859 860 constexpr reference operator*() const { return bit_reference<T>(*bf, index); } 861 862 constexpr iterator& operator++() 863 { 864 index++; 865 return *this; 866 } 867 868 constexpr iterator operator++(int) 869 { 870 iterator tmp = *this; 871 index++; 872 return tmp; 873 } 874 875 constexpr iterator& operator--() 876 { 877 index--; 878 return *this; 879 } 880 881 constexpr iterator operator--(int) 882 { 883 iterator tmp = *this; 884 index--; 885 return tmp; 886 } 887 888 constexpr iterator& operator+=(difference_type value) 889 { 890 index += value; 891 return *this; 892 } 893 894 constexpr iterator& operator-=(difference_type value) 895 { 896 *this += -value; 897 return *this; 898 } 899 900 constexpr iterator operator+(difference_type value) const 901 { 902 iterator tmp = *this; 903 return tmp += value; 904 } 905 906 constexpr iterator operator-(difference_type value) const 907 { 908 iterator tmp = *this; 909 return tmp -= value; 910 } 911 912 constexpr reference operator[](difference_type value) const { return *(*this + value); } 913 914 T* bf; 915 unsigned index; 916 }; 917 918 template <typename T, typename refT, typename ptrT> 919 constexpr inline bitfield_iterator<T, refT, ptrT> 920 operator+(int n, const bitfield_iterator<T, refT, ptrT>& x) 921 { 922 return x + n; 923 } 924 925 template <typename T, typename refT, typename ptrT> 926 constexpr inline int 927 operator-(const bitfield_iterator<T, refT, ptrT> x, const bitfield_iterator<T, refT, ptrT>& y) 928 { 929 return x.index - y.index; 930 } 931 932 /* 933 * Extends bitfield_uint with operator[] and iterators that 934 * allow accessing single bits within the uint. Can be used 935 * as a more compact version of bool arrays that also still 936 * allows accessing the whole array as an integer. 937 */ 938 template <typename data_type, unsigned offset, unsigned size, typename access_type> 939 class bitfield_array : public bitfield_uint<data_type, offset, size, access_type> { 940 public: 941 using value_type = bool; 942 using size_type = unsigned; 943 using difference_type = int; 944 using reference = bit_reference<data_type>; 945 using const_reference = bool; 946 using pointer = bit_reference<data_type>*; 947 using const_pointer = const bool*; 948 using iterator = 949 bitfield_iterator<data_type, bit_reference<data_type>, bit_reference<data_type>*>; 950 using const_iterator = bitfield_iterator<const data_type, bool, const bool*>; 951 using reverse_iterator = std::reverse_iterator<iterator>; 952 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 953 954 bitfield_array() = default; 955 bitfield_array(const access_type & value)956 constexpr bitfield_array(const access_type& value) { *this = value; } 957 958 constexpr bitfield_array& operator=(const access_type& value) 959 { 960 storage &= ~(mask << offset); 961 storage |= data_type(value & mask) << offset; 962 return *this; 963 } 964 965 constexpr bitfield_array& operator=(const bitfield_array& value) 966 { 967 return *this = access_type(value); 968 } 969 970 constexpr reference operator[](unsigned index) 971 { 972 assert(index < size); 973 return reference(storage, offset + index); 974 } 975 976 constexpr bool operator[](unsigned index) const 977 { 978 assert(index < size); 979 return (storage >> (offset + index)) & 0x1; 980 } 981 begin()982 constexpr iterator begin() noexcept { return iterator(&storage, offset); } 983 end()984 constexpr iterator end() noexcept { return std::next(begin(), size); } 985 begin()986 constexpr const_iterator begin() const noexcept { return const_iterator(&storage, offset); } 987 end()988 constexpr const_iterator end() const noexcept { return std::next(begin(), size); } 989 cbegin()990 constexpr const_iterator cbegin() const noexcept { return begin(); } 991 cend()992 constexpr const_iterator cend() const noexcept { return std::next(begin(), size); } 993 rbegin()994 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 995 rend()996 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 997 rbegin()998 constexpr const_reverse_iterator rbegin() const noexcept 999 { 1000 return const_reverse_iterator(end()); 1001 } 1002 rend()1003 constexpr const_reverse_iterator rend() const noexcept 1004 { 1005 return const_reverse_iterator(begin()); 1006 } 1007 crbegin()1008 constexpr const_reverse_iterator crbegin() const noexcept 1009 { 1010 return const_reverse_iterator(cend()); 1011 } 1012 crend()1013 constexpr const_reverse_iterator crend() const noexcept 1014 { 1015 return const_reverse_iterator(cbegin()); 1016 } 1017 1018 private: 1019 using bitfield_uint<data_type, offset, size, access_type>::storage; 1020 using bitfield_uint<data_type, offset, size, access_type>::mask; 1021 }; 1022 1023 template <typename T, unsigned offset> using bitfield_bool = bitfield_uint<T, offset, 1, bool>; 1024 1025 template <typename T, unsigned offset, unsigned size> 1026 using bitfield_uint8 = bitfield_uint<T, offset, size, uint8_t>; 1027 1028 template <typename T, unsigned offset, unsigned size> 1029 using bitfield_uint16 = bitfield_uint<T, offset, size, uint16_t>; 1030 1031 template <typename T, unsigned offset, unsigned size> 1032 using bitfield_uint32 = bitfield_uint<T, offset, size, uint32_t>; 1033 1034 template <typename T, unsigned offset, unsigned size> 1035 using bitfield_uint64 = bitfield_uint<T, offset, size, uint64_t>; 1036 1037 template <typename T, unsigned offset, unsigned size> 1038 using bitfield_array8 = bitfield_array<T, offset, size, uint8_t>; 1039 1040 template <typename T, unsigned offset, unsigned size> 1041 using bitfield_array16 = bitfield_array<T, offset, size, uint16_t>; 1042 1043 template <typename T, unsigned offset, unsigned size> 1044 using bitfield_array32 = bitfield_array<T, offset, size, uint32_t>; 1045 1046 template <typename T, unsigned offset, unsigned size> 1047 using bitfield_array64 = bitfield_array<T, offset, size, uint64_t>; 1048 1049 using bitarray8 = bitfield_array<uint8_t, 0, 8, uint8_t>; 1050 using bitarray32 = bitfield_array<uint32_t, 0, 32, uint32_t>; 1051 1052 /* 1053 * Resizable array optimized for small lengths. If it's smaller than Size, the elements will be 1054 * inlined into the object. 1055 */ 1056 template <typename T, uint32_t Size> class small_vec { 1057 public: 1058 /* We could support destructors with some effort, but currently there's no use case. */ 1059 static_assert(std::is_trivially_destructible<T>::value); 1060 1061 using value_type = T; 1062 using pointer = value_type*; 1063 using const_pointer = const value_type*; 1064 using reference = value_type&; 1065 using const_reference = const value_type&; 1066 using iterator = pointer; 1067 using const_iterator = const_pointer; 1068 using reverse_iterator = std::reverse_iterator<iterator>; 1069 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 1070 using size_type = uint16_t; 1071 using difference_type = std::ptrdiff_t; 1072 1073 constexpr small_vec() = default; small_vec(const small_vec & other)1074 constexpr small_vec(const small_vec& other) { *this = other; } small_vec(small_vec && other)1075 constexpr small_vec(small_vec&& other) noexcept { *this = std::move(other); } 1076 ~small_vec()1077 ~small_vec() 1078 { 1079 if (capacity > Size) 1080 free(data); 1081 } 1082 1083 constexpr small_vec& operator=(const small_vec& other) 1084 { 1085 if (&other == this) 1086 return *this; 1087 clear(); 1088 reserve(other.capacity); 1089 length = other.length; 1090 std::uninitialized_copy(other.begin(), other.end(), begin()); 1091 return *this; 1092 } 1093 1094 constexpr small_vec& operator=(small_vec&& other) noexcept 1095 { 1096 if (&other == this) 1097 return *this; 1098 clear(); 1099 length = other.length; 1100 capacity = other.capacity; 1101 if (capacity > Size) 1102 data = other.data; 1103 else 1104 std::uninitialized_move(other.begin(), other.end(), begin()); 1105 other.length = 0; 1106 other.capacity = Size; 1107 return *this; 1108 } 1109 begin()1110 constexpr iterator begin() noexcept { return capacity > Size ? data : (T*)inline_data; } 1111 begin()1112 constexpr const_iterator begin() const noexcept 1113 { 1114 return capacity > Size ? data : (T*)inline_data; 1115 } 1116 end()1117 constexpr iterator end() noexcept { return std::next(begin(), length); } 1118 end()1119 constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 1120 cbegin()1121 constexpr const_iterator cbegin() const noexcept { return begin(); } 1122 cend()1123 constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 1124 rbegin()1125 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 1126 rbegin()1127 constexpr const_reverse_iterator rbegin() const noexcept 1128 { 1129 return const_reverse_iterator(end()); 1130 } 1131 rend()1132 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 1133 rend()1134 constexpr const_reverse_iterator rend() const noexcept 1135 { 1136 return const_reverse_iterator(begin()); 1137 } 1138 crbegin()1139 constexpr const_reverse_iterator crbegin() const noexcept 1140 { 1141 return const_reverse_iterator(cend()); 1142 } 1143 crend()1144 constexpr const_reverse_iterator crend() const noexcept 1145 { 1146 return const_reverse_iterator(cbegin()); 1147 } 1148 1149 constexpr reference operator[](const size_type index) noexcept 1150 { 1151 assert(length > index); 1152 return *(std::next(begin(), index)); 1153 } 1154 1155 constexpr const_reference operator[](const size_type index) const noexcept 1156 { 1157 assert(length > index); 1158 return *(std::next(begin(), index)); 1159 } 1160 back()1161 constexpr reference back() noexcept 1162 { 1163 assert(length > 0); 1164 return *(std::next(begin(), length - 1)); 1165 } 1166 back()1167 constexpr const_reference back() const noexcept 1168 { 1169 assert(length > 0); 1170 return *(std::next(begin(), length - 1)); 1171 } 1172 front()1173 constexpr reference front() noexcept 1174 { 1175 assert(length > 0); 1176 return *begin(); 1177 } 1178 front()1179 constexpr const_reference front() const noexcept 1180 { 1181 assert(length > 0); 1182 return *cbegin(); 1183 } 1184 empty()1185 constexpr bool empty() const noexcept { return length == 0; } 1186 size()1187 constexpr size_type size() const noexcept { return length; } 1188 pop_back()1189 constexpr void pop_back() noexcept 1190 { 1191 assert(length > 0); 1192 --length; 1193 } 1194 reserve(size_type n)1195 constexpr void reserve(size_type n) 1196 { 1197 if (n > capacity) { 1198 if constexpr (std::is_trivial<T>::value) { 1199 if (capacity > Size) { 1200 data = (T*)realloc(data, sizeof(T) * n); 1201 capacity = n; 1202 return; 1203 } 1204 } 1205 T* ptr = (T*)malloc(sizeof(T) * n); 1206 std::uninitialized_move(begin(), end(), ptr); 1207 if (capacity > Size) 1208 free(data); 1209 data = ptr; 1210 capacity = n; 1211 } 1212 } 1213 push_back(const value_type & val)1214 constexpr void push_back(const value_type& val) noexcept 1215 { 1216 if (length == capacity) 1217 reserve(2 * capacity); 1218 1219 new (std::next(begin(), length++)) T(val); 1220 } 1221 emplace_back(Args...args)1222 template <typename... Args> constexpr void emplace_back(Args... args) noexcept 1223 { 1224 if (length == capacity) 1225 reserve(2 * capacity); 1226 1227 new (std::next(begin(), length++)) T(args...); 1228 } 1229 insert(const_iterator it,const value_type & val)1230 constexpr void insert(const_iterator it, const value_type& val) noexcept 1231 { 1232 size_t idx = it - begin(); 1233 assert(idx <= size()); 1234 1235 if (length == capacity) 1236 reserve(2 * capacity); 1237 1238 if (idx == length) { 1239 new (end()) T(val); 1240 } else { 1241 /* We can't do this one as part of move_backward because end() is uninitialized. */ 1242 new (end()) T(std::move(*(end() - 1))); 1243 std::move_backward(std::next(begin(), idx), std::prev(end(), 1), end()); 1244 *std::next(begin(), idx) = val; 1245 } 1246 length++; 1247 } 1248 erase(const_iterator it)1249 constexpr void erase(const_iterator it) noexcept 1250 { 1251 std::move(iterator(it) + 1, end(), iterator(it)); 1252 length--; 1253 } 1254 resize(uint32_t new_size)1255 constexpr void resize(uint32_t new_size) noexcept 1256 { 1257 if (new_size > capacity) 1258 reserve(new_size); 1259 1260 for (uint32_t i = length; i < new_size; i++) 1261 new (std::next(begin(), i)) T(); 1262 1263 length = new_size; 1264 } 1265 clear()1266 constexpr void clear() noexcept 1267 { 1268 if (capacity > Size) 1269 free(data); 1270 length = 0; 1271 capacity = Size; 1272 } 1273 1274 constexpr bool operator==(const small_vec& other) const 1275 { 1276 if (size() != other.size()) 1277 return false; 1278 for (unsigned i = 0; i < size(); i++) { 1279 if (*(std::next(begin(), i)) != other[i]) 1280 return false; 1281 } 1282 return true; 1283 } 1284 1285 private: 1286 uint32_t length = 0; 1287 uint32_t capacity = Size; 1288 union { 1289 T* data = NULL; 1290 alignas(T) uint8_t inline_data[sizeof(T) * Size]; 1291 }; 1292 }; 1293 1294 } // namespace aco 1295 1296 #endif // ACO_UTIL_H 1297