1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright Michael Schellenberger Costa 3bf215546Sopenharmony_ci * Copyright © 2020 Valve Corporation 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22bf215546Sopenharmony_ci * IN THE SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#ifndef ACO_UTIL_H 27bf215546Sopenharmony_ci#define ACO_UTIL_H 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "util/bitscan.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include <cassert> 32bf215546Sopenharmony_ci#include <cstddef> 33bf215546Sopenharmony_ci#include <iterator> 34bf215546Sopenharmony_ci#include <vector> 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cinamespace aco { 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci/*! \brief Definition of a span object 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * \details A "span" is an "array view" type for holding a view of contiguous 41bf215546Sopenharmony_ci * data. The "span" object does not own the data itself. 42bf215546Sopenharmony_ci */ 43bf215546Sopenharmony_citemplate <typename T> class span { 44bf215546Sopenharmony_cipublic: 45bf215546Sopenharmony_ci using value_type = T; 46bf215546Sopenharmony_ci using pointer = value_type*; 47bf215546Sopenharmony_ci using const_pointer = const value_type*; 48bf215546Sopenharmony_ci using reference = value_type&; 49bf215546Sopenharmony_ci using const_reference = const value_type&; 50bf215546Sopenharmony_ci using iterator = pointer; 51bf215546Sopenharmony_ci using const_iterator = const_pointer; 52bf215546Sopenharmony_ci using reverse_iterator = std::reverse_iterator<iterator>; 53bf215546Sopenharmony_ci using const_reverse_iterator = std::reverse_iterator<const_iterator>; 54bf215546Sopenharmony_ci using size_type = uint16_t; 55bf215546Sopenharmony_ci using difference_type = std::ptrdiff_t; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci /*! \brief Compiler generated default constructor 58bf215546Sopenharmony_ci */ 59bf215546Sopenharmony_ci constexpr span() = default; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci /*! \brief Constructor taking a pointer and the length of the span 62bf215546Sopenharmony_ci * \param[in] data Pointer to the underlying data array 63bf215546Sopenharmony_ci * \param[in] length The size of the span 64bf215546Sopenharmony_ci */ 65bf215546Sopenharmony_ci constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {} 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci /*! \brief Returns an iterator to the begin of the span 68bf215546Sopenharmony_ci * \return data 69bf215546Sopenharmony_ci */ 70bf215546Sopenharmony_ci constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); } 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci /*! \brief Returns a const_iterator to the begin of the span 73bf215546Sopenharmony_ci * \return data 74bf215546Sopenharmony_ci */ 75bf215546Sopenharmony_ci constexpr const_iterator begin() const noexcept 76bf215546Sopenharmony_ci { 77bf215546Sopenharmony_ci return (const_pointer)((uintptr_t)this + offset); 78bf215546Sopenharmony_ci } 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci /*! \brief Returns an iterator to the end of the span 81bf215546Sopenharmony_ci * \return data + length 82bf215546Sopenharmony_ci */ 83bf215546Sopenharmony_ci constexpr iterator end() noexcept { return std::next(begin(), length); } 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci /*! \brief Returns a const_iterator to the end of the span 86bf215546Sopenharmony_ci * \return data + length 87bf215546Sopenharmony_ci */ 88bf215546Sopenharmony_ci constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci /*! \brief Returns a const_iterator to the begin of the span 91bf215546Sopenharmony_ci * \return data 92bf215546Sopenharmony_ci */ 93bf215546Sopenharmony_ci constexpr const_iterator cbegin() const noexcept { return begin(); } 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci /*! \brief Returns a const_iterator to the end of the span 96bf215546Sopenharmony_ci * \return data + length 97bf215546Sopenharmony_ci */ 98bf215546Sopenharmony_ci constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci /*! \brief Returns a reverse_iterator to the end of the span 101bf215546Sopenharmony_ci * \return reverse_iterator(end()) 102bf215546Sopenharmony_ci */ 103bf215546Sopenharmony_ci constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci /*! \brief Returns a const_reverse_iterator to the end of the span 106bf215546Sopenharmony_ci * \return reverse_iterator(end()) 107bf215546Sopenharmony_ci */ 108bf215546Sopenharmony_ci constexpr const_reverse_iterator rbegin() const noexcept 109bf215546Sopenharmony_ci { 110bf215546Sopenharmony_ci return const_reverse_iterator(end()); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci /*! \brief Returns a reverse_iterator to the begin of the span 114bf215546Sopenharmony_ci * \return reverse_iterator(begin()) 115bf215546Sopenharmony_ci */ 116bf215546Sopenharmony_ci constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci /*! \brief Returns a const_reverse_iterator to the begin of the span 119bf215546Sopenharmony_ci * \return reverse_iterator(begin()) 120bf215546Sopenharmony_ci */ 121bf215546Sopenharmony_ci constexpr const_reverse_iterator rend() const noexcept 122bf215546Sopenharmony_ci { 123bf215546Sopenharmony_ci return const_reverse_iterator(begin()); 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci /*! \brief Returns a const_reverse_iterator to the end of the span 127bf215546Sopenharmony_ci * \return rbegin() 128bf215546Sopenharmony_ci */ 129bf215546Sopenharmony_ci constexpr const_reverse_iterator crbegin() const noexcept 130bf215546Sopenharmony_ci { 131bf215546Sopenharmony_ci return const_reverse_iterator(cend()); 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci /*! \brief Returns a const_reverse_iterator to the begin of the span 135bf215546Sopenharmony_ci * \return rend() 136bf215546Sopenharmony_ci */ 137bf215546Sopenharmony_ci constexpr const_reverse_iterator crend() const noexcept 138bf215546Sopenharmony_ci { 139bf215546Sopenharmony_ci return const_reverse_iterator(cbegin()); 140bf215546Sopenharmony_ci } 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci /*! \brief Unchecked access operator 143bf215546Sopenharmony_ci * \param[in] index Index of the element we want to access 144bf215546Sopenharmony_ci * \return *(std::next(data, index)) 145bf215546Sopenharmony_ci */ 146bf215546Sopenharmony_ci constexpr reference operator[](const size_type index) noexcept 147bf215546Sopenharmony_ci { 148bf215546Sopenharmony_ci assert(length > index); 149bf215546Sopenharmony_ci return *(std::next(begin(), index)); 150bf215546Sopenharmony_ci } 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci /*! \brief Unchecked const access operator 153bf215546Sopenharmony_ci * \param[in] index Index of the element we want to access 154bf215546Sopenharmony_ci * \return *(std::next(data, index)) 155bf215546Sopenharmony_ci */ 156bf215546Sopenharmony_ci constexpr const_reference operator[](const size_type index) const noexcept 157bf215546Sopenharmony_ci { 158bf215546Sopenharmony_ci assert(length > index); 159bf215546Sopenharmony_ci return *(std::next(begin(), index)); 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci /*! \brief Returns a reference to the last element of the span 163bf215546Sopenharmony_ci * \return *(std::next(data, length - 1)) 164bf215546Sopenharmony_ci */ 165bf215546Sopenharmony_ci constexpr reference back() noexcept 166bf215546Sopenharmony_ci { 167bf215546Sopenharmony_ci assert(length > 0); 168bf215546Sopenharmony_ci return *(std::next(begin(), length - 1)); 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci /*! \brief Returns a const_reference to the last element of the span 172bf215546Sopenharmony_ci * \return *(std::next(data, length - 1)) 173bf215546Sopenharmony_ci */ 174bf215546Sopenharmony_ci constexpr const_reference back() const noexcept 175bf215546Sopenharmony_ci { 176bf215546Sopenharmony_ci assert(length > 0); 177bf215546Sopenharmony_ci return *(std::next(begin(), length - 1)); 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci /*! \brief Returns a reference to the first element of the span 181bf215546Sopenharmony_ci * \return *begin() 182bf215546Sopenharmony_ci */ 183bf215546Sopenharmony_ci constexpr reference front() noexcept 184bf215546Sopenharmony_ci { 185bf215546Sopenharmony_ci assert(length > 0); 186bf215546Sopenharmony_ci return *begin(); 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci /*! \brief Returns a const_reference to the first element of the span 190bf215546Sopenharmony_ci * \return *cbegin() 191bf215546Sopenharmony_ci */ 192bf215546Sopenharmony_ci constexpr const_reference front() const noexcept 193bf215546Sopenharmony_ci { 194bf215546Sopenharmony_ci assert(length > 0); 195bf215546Sopenharmony_ci return *cbegin(); 196bf215546Sopenharmony_ci } 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /*! \brief Returns true if the span is empty 199bf215546Sopenharmony_ci * \return length == 0 200bf215546Sopenharmony_ci */ 201bf215546Sopenharmony_ci constexpr bool empty() const noexcept { return length == 0; } 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci /*! \brief Returns the size of the span 204bf215546Sopenharmony_ci * \return length == 0 205bf215546Sopenharmony_ci */ 206bf215546Sopenharmony_ci constexpr size_type size() const noexcept { return length; } 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci /*! \brief Decreases the size of the span by 1 209bf215546Sopenharmony_ci */ 210bf215546Sopenharmony_ci constexpr void pop_back() noexcept 211bf215546Sopenharmony_ci { 212bf215546Sopenharmony_ci assert(length > 0); 213bf215546Sopenharmony_ci --length; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci /*! \brief Adds an element to the end of the span 217bf215546Sopenharmony_ci */ 218bf215546Sopenharmony_ci constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci /*! \brief Clears the span 221bf215546Sopenharmony_ci */ 222bf215546Sopenharmony_ci constexpr void clear() noexcept 223bf215546Sopenharmony_ci { 224bf215546Sopenharmony_ci offset = 0; 225bf215546Sopenharmony_ci length = 0; 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ciprivate: 229bf215546Sopenharmony_ci uint16_t offset{0}; //!> Byte offset from span to data 230bf215546Sopenharmony_ci size_type length{0}; //!> Size of the span 231bf215546Sopenharmony_ci}; 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci/* 234bf215546Sopenharmony_ci * Cache-friendly set of 32-bit IDs with O(1) insert/erase/lookup and 235bf215546Sopenharmony_ci * the ability to efficiently iterate over contained elements. 236bf215546Sopenharmony_ci * 237bf215546Sopenharmony_ci * Internally implemented as a bit vector: If the set contains an ID, the 238bf215546Sopenharmony_ci * corresponding bit is set. It doesn't use std::vector<bool> since we then 239bf215546Sopenharmony_ci * couldn't efficiently iterate over the elements. 240bf215546Sopenharmony_ci * 241bf215546Sopenharmony_ci * The interface resembles a subset of std::set/std::unordered_set. 242bf215546Sopenharmony_ci */ 243bf215546Sopenharmony_cistruct IDSet { 244bf215546Sopenharmony_ci struct Iterator { 245bf215546Sopenharmony_ci const IDSet* set; 246bf215546Sopenharmony_ci union { 247bf215546Sopenharmony_ci struct { 248bf215546Sopenharmony_ci uint32_t bit : 6; 249bf215546Sopenharmony_ci uint32_t word : 26; 250bf215546Sopenharmony_ci }; 251bf215546Sopenharmony_ci uint32_t id; 252bf215546Sopenharmony_ci }; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci Iterator& operator++(); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci bool operator!=(const Iterator& other) const; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci uint32_t operator*() const; 259bf215546Sopenharmony_ci }; 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci size_t count(uint32_t id) const 262bf215546Sopenharmony_ci { 263bf215546Sopenharmony_ci if (id >= words.size() * 64) 264bf215546Sopenharmony_ci return 0; 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci return words[id / 64u] & (1ull << (id % 64u)) ? 1 : 0; 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci Iterator find(uint32_t id) const 270bf215546Sopenharmony_ci { 271bf215546Sopenharmony_ci if (!count(id)) 272bf215546Sopenharmony_ci return end(); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci Iterator it; 275bf215546Sopenharmony_ci it.set = this; 276bf215546Sopenharmony_ci it.bit = id % 64u; 277bf215546Sopenharmony_ci it.word = id / 64u; 278bf215546Sopenharmony_ci return it; 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci std::pair<Iterator, bool> insert(uint32_t id) 282bf215546Sopenharmony_ci { 283bf215546Sopenharmony_ci if (words.size() * 64u <= id) 284bf215546Sopenharmony_ci words.resize(id / 64u + 1); 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci Iterator it; 287bf215546Sopenharmony_ci it.set = this; 288bf215546Sopenharmony_ci it.bit = id % 64u; 289bf215546Sopenharmony_ci it.word = id / 64u; 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci uint64_t mask = 1ull << it.bit; 292bf215546Sopenharmony_ci if (words[it.word] & mask) 293bf215546Sopenharmony_ci return std::make_pair(it, false); 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci words[it.word] |= mask; 296bf215546Sopenharmony_ci bits_set++; 297bf215546Sopenharmony_ci return std::make_pair(it, true); 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci size_t erase(uint32_t id) 301bf215546Sopenharmony_ci { 302bf215546Sopenharmony_ci if (!count(id)) 303bf215546Sopenharmony_ci return 0; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci words[id / 64u] ^= 1ull << (id % 64u); 306bf215546Sopenharmony_ci bits_set--; 307bf215546Sopenharmony_ci return 1; 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci Iterator cbegin() const 311bf215546Sopenharmony_ci { 312bf215546Sopenharmony_ci Iterator it; 313bf215546Sopenharmony_ci it.set = this; 314bf215546Sopenharmony_ci for (size_t i = 0; i < words.size(); i++) { 315bf215546Sopenharmony_ci if (words[i]) { 316bf215546Sopenharmony_ci it.word = i; 317bf215546Sopenharmony_ci it.bit = ffsll(words[i]) - 1; 318bf215546Sopenharmony_ci return it; 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci } 321bf215546Sopenharmony_ci return end(); 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci Iterator cend() const 325bf215546Sopenharmony_ci { 326bf215546Sopenharmony_ci Iterator it; 327bf215546Sopenharmony_ci it.set = this; 328bf215546Sopenharmony_ci it.word = words.size(); 329bf215546Sopenharmony_ci it.bit = 0; 330bf215546Sopenharmony_ci return it; 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci Iterator begin() const { return cbegin(); } 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci Iterator end() const { return cend(); } 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ci bool empty() const { return bits_set == 0; } 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci size_t size() const { return bits_set; } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci std::vector<uint64_t> words; 342bf215546Sopenharmony_ci uint32_t bits_set = 0; 343bf215546Sopenharmony_ci}; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ciinline IDSet::Iterator& 346bf215546Sopenharmony_ciIDSet::Iterator::operator++() 347bf215546Sopenharmony_ci{ 348bf215546Sopenharmony_ci uint64_t m = set->words[word]; 349bf215546Sopenharmony_ci m &= ~((2ull << bit) - 1ull); 350bf215546Sopenharmony_ci if (!m) { 351bf215546Sopenharmony_ci /* don't continue past the end */ 352bf215546Sopenharmony_ci if (word == set->words.size()) 353bf215546Sopenharmony_ci return *this; 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci word++; 356bf215546Sopenharmony_ci for (; word < set->words.size(); word++) { 357bf215546Sopenharmony_ci if (set->words[word]) { 358bf215546Sopenharmony_ci bit = ffsll(set->words[word]) - 1; 359bf215546Sopenharmony_ci return *this; 360bf215546Sopenharmony_ci } 361bf215546Sopenharmony_ci } 362bf215546Sopenharmony_ci bit = 0; 363bf215546Sopenharmony_ci } else { 364bf215546Sopenharmony_ci bit = ffsll(m) - 1; 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci return *this; 367bf215546Sopenharmony_ci} 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ciinline bool 370bf215546Sopenharmony_ciIDSet::Iterator::operator!=(const IDSet::Iterator& other) const 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci assert(set == other.set); 373bf215546Sopenharmony_ci return id != other.id; 374bf215546Sopenharmony_ci} 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ciinline uint32_t 377bf215546Sopenharmony_ciIDSet::Iterator::operator*() const 378bf215546Sopenharmony_ci{ 379bf215546Sopenharmony_ci return (word << 6) | bit; 380bf215546Sopenharmony_ci} 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci} // namespace aco 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci#endif // ACO_UTIL_H 385