17ec681f3Smrg/* 27ec681f3Smrg * Copyright Michael Schellenberger Costa 37ec681f3Smrg * Copyright © 2020 Valve Corporation 47ec681f3Smrg * 57ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 67ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 77ec681f3Smrg * to deal in the Software without restriction, including without limitation 87ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 97ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 107ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 117ec681f3Smrg * 127ec681f3Smrg * The above copyright notice and this permission notice (including the next 137ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 147ec681f3Smrg * Software. 157ec681f3Smrg * 167ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 197ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 207ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 217ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 227ec681f3Smrg * IN THE SOFTWARE. 237ec681f3Smrg * 247ec681f3Smrg */ 257ec681f3Smrg 267ec681f3Smrg#ifndef ACO_UTIL_H 277ec681f3Smrg#define ACO_UTIL_H 287ec681f3Smrg 297ec681f3Smrg#include "util/bitscan.h" 307ec681f3Smrg 317ec681f3Smrg#include <cassert> 327ec681f3Smrg#include <cstddef> 337ec681f3Smrg#include <iterator> 347ec681f3Smrg#include <vector> 357ec681f3Smrg 367ec681f3Smrgnamespace aco { 377ec681f3Smrg 387ec681f3Smrg/*! \brief Definition of a span object 397ec681f3Smrg * 407ec681f3Smrg * \details A "span" is an "array view" type for holding a view of contiguous 417ec681f3Smrg * data. The "span" object does not own the data itself. 427ec681f3Smrg */ 437ec681f3Smrgtemplate <typename T> class span { 447ec681f3Smrgpublic: 457ec681f3Smrg using value_type = T; 467ec681f3Smrg using pointer = value_type*; 477ec681f3Smrg using const_pointer = const value_type*; 487ec681f3Smrg using reference = value_type&; 497ec681f3Smrg using const_reference = const value_type&; 507ec681f3Smrg using iterator = pointer; 517ec681f3Smrg using const_iterator = const_pointer; 527ec681f3Smrg using reverse_iterator = std::reverse_iterator<iterator>; 537ec681f3Smrg using const_reverse_iterator = std::reverse_iterator<const_iterator>; 547ec681f3Smrg using size_type = uint16_t; 557ec681f3Smrg using difference_type = std::ptrdiff_t; 567ec681f3Smrg 577ec681f3Smrg /*! \brief Compiler generated default constructor 587ec681f3Smrg */ 597ec681f3Smrg constexpr span() = default; 607ec681f3Smrg 617ec681f3Smrg /*! \brief Constructor taking a pointer and the length of the span 627ec681f3Smrg * \param[in] data Pointer to the underlying data array 637ec681f3Smrg * \param[in] length The size of the span 647ec681f3Smrg */ 657ec681f3Smrg constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {} 667ec681f3Smrg 677ec681f3Smrg /*! \brief Returns an iterator to the begin of the span 687ec681f3Smrg * \return data 697ec681f3Smrg */ 707ec681f3Smrg constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); } 717ec681f3Smrg 727ec681f3Smrg /*! \brief Returns a const_iterator to the begin of the span 737ec681f3Smrg * \return data 747ec681f3Smrg */ 757ec681f3Smrg constexpr const_iterator begin() const noexcept 767ec681f3Smrg { 777ec681f3Smrg return (const_pointer)((uintptr_t)this + offset); 787ec681f3Smrg } 797ec681f3Smrg 807ec681f3Smrg /*! \brief Returns an iterator to the end of the span 817ec681f3Smrg * \return data + length 827ec681f3Smrg */ 837ec681f3Smrg constexpr iterator end() noexcept { return std::next(begin(), length); } 847ec681f3Smrg 857ec681f3Smrg /*! \brief Returns a const_iterator to the end of the span 867ec681f3Smrg * \return data + length 877ec681f3Smrg */ 887ec681f3Smrg constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 897ec681f3Smrg 907ec681f3Smrg /*! \brief Returns a const_iterator to the begin of the span 917ec681f3Smrg * \return data 927ec681f3Smrg */ 937ec681f3Smrg constexpr const_iterator cbegin() const noexcept { return begin(); } 947ec681f3Smrg 957ec681f3Smrg /*! \brief Returns a const_iterator to the end of the span 967ec681f3Smrg * \return data + length 977ec681f3Smrg */ 987ec681f3Smrg constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 997ec681f3Smrg 1007ec681f3Smrg /*! \brief Returns a reverse_iterator to the end of the span 1017ec681f3Smrg * \return reverse_iterator(end()) 1027ec681f3Smrg */ 1037ec681f3Smrg constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 1047ec681f3Smrg 1057ec681f3Smrg /*! \brief Returns a const_reverse_iterator to the end of the span 1067ec681f3Smrg * \return reverse_iterator(end()) 1077ec681f3Smrg */ 1087ec681f3Smrg constexpr const_reverse_iterator rbegin() const noexcept 1097ec681f3Smrg { 1107ec681f3Smrg return const_reverse_iterator(end()); 1117ec681f3Smrg } 1127ec681f3Smrg 1137ec681f3Smrg /*! \brief Returns a reverse_iterator to the begin of the span 1147ec681f3Smrg * \return reverse_iterator(begin()) 1157ec681f3Smrg */ 1167ec681f3Smrg constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 1177ec681f3Smrg 1187ec681f3Smrg /*! \brief Returns a const_reverse_iterator to the begin of the span 1197ec681f3Smrg * \return reverse_iterator(begin()) 1207ec681f3Smrg */ 1217ec681f3Smrg constexpr const_reverse_iterator rend() const noexcept 1227ec681f3Smrg { 1237ec681f3Smrg return const_reverse_iterator(begin()); 1247ec681f3Smrg } 1257ec681f3Smrg 1267ec681f3Smrg /*! \brief Returns a const_reverse_iterator to the end of the span 1277ec681f3Smrg * \return rbegin() 1287ec681f3Smrg */ 1297ec681f3Smrg constexpr const_reverse_iterator crbegin() const noexcept 1307ec681f3Smrg { 1317ec681f3Smrg return const_reverse_iterator(cend()); 1327ec681f3Smrg } 1337ec681f3Smrg 1347ec681f3Smrg /*! \brief Returns a const_reverse_iterator to the begin of the span 1357ec681f3Smrg * \return rend() 1367ec681f3Smrg */ 1377ec681f3Smrg constexpr const_reverse_iterator crend() const noexcept 1387ec681f3Smrg { 1397ec681f3Smrg return const_reverse_iterator(cbegin()); 1407ec681f3Smrg } 1417ec681f3Smrg 1427ec681f3Smrg /*! \brief Unchecked access operator 1437ec681f3Smrg * \param[in] index Index of the element we want to access 1447ec681f3Smrg * \return *(std::next(data, index)) 1457ec681f3Smrg */ 1467ec681f3Smrg constexpr reference operator[](const size_type index) noexcept 1477ec681f3Smrg { 1487ec681f3Smrg assert(length > index); 1497ec681f3Smrg return *(std::next(begin(), index)); 1507ec681f3Smrg } 1517ec681f3Smrg 1527ec681f3Smrg /*! \brief Unchecked const access operator 1537ec681f3Smrg * \param[in] index Index of the element we want to access 1547ec681f3Smrg * \return *(std::next(data, index)) 1557ec681f3Smrg */ 1567ec681f3Smrg constexpr const_reference operator[](const size_type index) const noexcept 1577ec681f3Smrg { 1587ec681f3Smrg assert(length > index); 1597ec681f3Smrg return *(std::next(begin(), index)); 1607ec681f3Smrg } 1617ec681f3Smrg 1627ec681f3Smrg /*! \brief Returns a reference to the last element of the span 1637ec681f3Smrg * \return *(std::next(data, length - 1)) 1647ec681f3Smrg */ 1657ec681f3Smrg constexpr reference back() noexcept 1667ec681f3Smrg { 1677ec681f3Smrg assert(length > 0); 1687ec681f3Smrg return *(std::next(begin(), length - 1)); 1697ec681f3Smrg } 1707ec681f3Smrg 1717ec681f3Smrg /*! \brief Returns a const_reference to the last element of the span 1727ec681f3Smrg * \return *(std::next(data, length - 1)) 1737ec681f3Smrg */ 1747ec681f3Smrg constexpr const_reference back() const noexcept 1757ec681f3Smrg { 1767ec681f3Smrg assert(length > 0); 1777ec681f3Smrg return *(std::next(begin(), length - 1)); 1787ec681f3Smrg } 1797ec681f3Smrg 1807ec681f3Smrg /*! \brief Returns a reference to the first element of the span 1817ec681f3Smrg * \return *begin() 1827ec681f3Smrg */ 1837ec681f3Smrg constexpr reference front() noexcept 1847ec681f3Smrg { 1857ec681f3Smrg assert(length > 0); 1867ec681f3Smrg return *begin(); 1877ec681f3Smrg } 1887ec681f3Smrg 1897ec681f3Smrg /*! \brief Returns a const_reference to the first element of the span 1907ec681f3Smrg * \return *cbegin() 1917ec681f3Smrg */ 1927ec681f3Smrg constexpr const_reference front() const noexcept 1937ec681f3Smrg { 1947ec681f3Smrg assert(length > 0); 1957ec681f3Smrg return *cbegin(); 1967ec681f3Smrg } 1977ec681f3Smrg 1987ec681f3Smrg /*! \brief Returns true if the span is empty 1997ec681f3Smrg * \return length == 0 2007ec681f3Smrg */ 2017ec681f3Smrg constexpr bool empty() const noexcept { return length == 0; } 2027ec681f3Smrg 2037ec681f3Smrg /*! \brief Returns the size of the span 2047ec681f3Smrg * \return length == 0 2057ec681f3Smrg */ 2067ec681f3Smrg constexpr size_type size() const noexcept { return length; } 2077ec681f3Smrg 2087ec681f3Smrg /*! \brief Decreases the size of the span by 1 2097ec681f3Smrg */ 2107ec681f3Smrg constexpr void pop_back() noexcept 2117ec681f3Smrg { 2127ec681f3Smrg assert(length > 0); 2137ec681f3Smrg --length; 2147ec681f3Smrg } 2157ec681f3Smrg 2167ec681f3Smrg /*! \brief Adds an element to the end of the span 2177ec681f3Smrg */ 2187ec681f3Smrg constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; } 2197ec681f3Smrg 2207ec681f3Smrg /*! \brief Clears the span 2217ec681f3Smrg */ 2227ec681f3Smrg constexpr void clear() noexcept 2237ec681f3Smrg { 2247ec681f3Smrg offset = 0; 2257ec681f3Smrg length = 0; 2267ec681f3Smrg } 2277ec681f3Smrg 2287ec681f3Smrgprivate: 2297ec681f3Smrg uint16_t offset{0}; //!> Byte offset from span to data 2307ec681f3Smrg size_type length{0}; //!> Size of the span 2317ec681f3Smrg}; 2327ec681f3Smrg 2337ec681f3Smrg/* 2347ec681f3Smrg * Cache-friendly set of 32-bit IDs with O(1) insert/erase/lookup and 2357ec681f3Smrg * the ability to efficiently iterate over contained elements. 2367ec681f3Smrg * 2377ec681f3Smrg * Internally implemented as a bit vector: If the set contains an ID, the 2387ec681f3Smrg * corresponding bit is set. It doesn't use std::vector<bool> since we then 2397ec681f3Smrg * couldn't efficiently iterate over the elements. 2407ec681f3Smrg * 2417ec681f3Smrg * The interface resembles a subset of std::set/std::unordered_set. 2427ec681f3Smrg */ 2437ec681f3Smrgstruct IDSet { 2447ec681f3Smrg struct Iterator { 2457ec681f3Smrg const IDSet* set; 2467ec681f3Smrg union { 2477ec681f3Smrg struct { 2487ec681f3Smrg uint32_t bit : 6; 2497ec681f3Smrg uint32_t word : 26; 2507ec681f3Smrg }; 2517ec681f3Smrg uint32_t id; 2527ec681f3Smrg }; 2537ec681f3Smrg 2547ec681f3Smrg Iterator& operator++(); 2557ec681f3Smrg 2567ec681f3Smrg bool operator!=(const Iterator& other) const; 2577ec681f3Smrg 2587ec681f3Smrg uint32_t operator*() const; 2597ec681f3Smrg }; 2607ec681f3Smrg 2617ec681f3Smrg size_t count(uint32_t id) const 2627ec681f3Smrg { 2637ec681f3Smrg if (id >= words.size() * 64) 2647ec681f3Smrg return 0; 2657ec681f3Smrg 2667ec681f3Smrg return words[id / 64u] & (1ull << (id % 64u)) ? 1 : 0; 2677ec681f3Smrg } 2687ec681f3Smrg 2697ec681f3Smrg Iterator find(uint32_t id) const 2707ec681f3Smrg { 2717ec681f3Smrg if (!count(id)) 2727ec681f3Smrg return end(); 2737ec681f3Smrg 2747ec681f3Smrg Iterator it; 2757ec681f3Smrg it.set = this; 2767ec681f3Smrg it.bit = id % 64u; 2777ec681f3Smrg it.word = id / 64u; 2787ec681f3Smrg return it; 2797ec681f3Smrg } 2807ec681f3Smrg 2817ec681f3Smrg std::pair<Iterator, bool> insert(uint32_t id) 2827ec681f3Smrg { 2837ec681f3Smrg if (words.size() * 64u <= id) 2847ec681f3Smrg words.resize(id / 64u + 1); 2857ec681f3Smrg 2867ec681f3Smrg Iterator it; 2877ec681f3Smrg it.set = this; 2887ec681f3Smrg it.bit = id % 64u; 2897ec681f3Smrg it.word = id / 64u; 2907ec681f3Smrg 2917ec681f3Smrg uint64_t mask = 1ull << it.bit; 2927ec681f3Smrg if (words[it.word] & mask) 2937ec681f3Smrg return std::make_pair(it, false); 2947ec681f3Smrg 2957ec681f3Smrg words[it.word] |= mask; 2967ec681f3Smrg bits_set++; 2977ec681f3Smrg return std::make_pair(it, true); 2987ec681f3Smrg } 2997ec681f3Smrg 3007ec681f3Smrg size_t erase(uint32_t id) 3017ec681f3Smrg { 3027ec681f3Smrg if (!count(id)) 3037ec681f3Smrg return 0; 3047ec681f3Smrg 3057ec681f3Smrg words[id / 64u] ^= 1ull << (id % 64u); 3067ec681f3Smrg bits_set--; 3077ec681f3Smrg return 1; 3087ec681f3Smrg } 3097ec681f3Smrg 3107ec681f3Smrg Iterator cbegin() const 3117ec681f3Smrg { 3127ec681f3Smrg Iterator it; 3137ec681f3Smrg it.set = this; 3147ec681f3Smrg for (size_t i = 0; i < words.size(); i++) { 3157ec681f3Smrg if (words[i]) { 3167ec681f3Smrg it.word = i; 3177ec681f3Smrg it.bit = ffsll(words[i]) - 1; 3187ec681f3Smrg return it; 3197ec681f3Smrg } 3207ec681f3Smrg } 3217ec681f3Smrg return end(); 3227ec681f3Smrg } 3237ec681f3Smrg 3247ec681f3Smrg Iterator cend() const 3257ec681f3Smrg { 3267ec681f3Smrg Iterator it; 3277ec681f3Smrg it.set = this; 3287ec681f3Smrg it.word = words.size(); 3297ec681f3Smrg it.bit = 0; 3307ec681f3Smrg return it; 3317ec681f3Smrg } 3327ec681f3Smrg 3337ec681f3Smrg Iterator begin() const { return cbegin(); } 3347ec681f3Smrg 3357ec681f3Smrg Iterator end() const { return cend(); } 3367ec681f3Smrg 3377ec681f3Smrg bool empty() const { return bits_set == 0; } 3387ec681f3Smrg 3397ec681f3Smrg size_t size() const { return bits_set; } 3407ec681f3Smrg 3417ec681f3Smrg std::vector<uint64_t> words; 3427ec681f3Smrg uint32_t bits_set = 0; 3437ec681f3Smrg}; 3447ec681f3Smrg 3457ec681f3Smrginline IDSet::Iterator& 3467ec681f3SmrgIDSet::Iterator::operator++() 3477ec681f3Smrg{ 3487ec681f3Smrg uint64_t m = set->words[word]; 3497ec681f3Smrg m &= ~((2ull << bit) - 1ull); 3507ec681f3Smrg if (!m) { 3517ec681f3Smrg /* don't continue past the end */ 3527ec681f3Smrg if (word == set->words.size()) 3537ec681f3Smrg return *this; 3547ec681f3Smrg 3557ec681f3Smrg word++; 3567ec681f3Smrg for (; word < set->words.size(); word++) { 3577ec681f3Smrg if (set->words[word]) { 3587ec681f3Smrg bit = ffsll(set->words[word]) - 1; 3597ec681f3Smrg return *this; 3607ec681f3Smrg } 3617ec681f3Smrg } 3627ec681f3Smrg bit = 0; 3637ec681f3Smrg } else { 3647ec681f3Smrg bit = ffsll(m) - 1; 3657ec681f3Smrg } 3667ec681f3Smrg return *this; 3677ec681f3Smrg} 3687ec681f3Smrg 3697ec681f3Smrginline bool 3707ec681f3SmrgIDSet::Iterator::operator!=(const IDSet::Iterator& other) const 3717ec681f3Smrg{ 3727ec681f3Smrg assert(set == other.set); 3737ec681f3Smrg return id != other.id; 3747ec681f3Smrg} 3757ec681f3Smrg 3767ec681f3Smrginline uint32_t 3777ec681f3SmrgIDSet::Iterator::operator*() const 3787ec681f3Smrg{ 3797ec681f3Smrg return (word << 6) | bit; 3807ec681f3Smrg} 3817ec681f3Smrg 3827ec681f3Smrg} // namespace aco 3837ec681f3Smrg 3847ec681f3Smrg#endif // ACO_UTIL_H 385