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 31 #include <cassert> 32 #include <cstddef> 33 #include <iterator> 34 #include <vector> 35 36 namespace aco { 37 38 /*! \brief Definition of a span object 39 * 40 * \details A "span" is an "array view" type for holding a view of contiguous 41 * data. The "span" object does not own the data itself. 42 */ 43 template <typename T> class span { 44 public: 45 using value_type = T; 46 using pointer = value_type*; 47 using const_pointer = const value_type*; 48 using reference = value_type&; 49 using const_reference = const value_type&; 50 using iterator = pointer; 51 using const_iterator = const_pointer; 52 using reverse_iterator = std::reverse_iterator<iterator>; 53 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 54 using size_type = uint16_t; 55 using difference_type = std::ptrdiff_t; 56 57 /*! \brief Compiler generated default constructor 58 */ 59 constexpr span() = default; 60 61 /*! \brief Constructor taking a pointer and the length of the span 62 * \param[in] data Pointer to the underlying data array 63 * \param[in] length The size of the span 64 */ span(uint16_t offset_,const size_type length_)65 constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {} 66 67 /*! \brief Returns an iterator to the begin of the span 68 * \return data 69 */ begin()70 constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); } 71 72 /*! \brief Returns a const_iterator to the begin of the span 73 * \return data 74 */ begin()75 constexpr const_iterator begin() const noexcept 76 { 77 return (const_pointer)((uintptr_t)this + offset); 78 } 79 80 /*! \brief Returns an iterator to the end of the span 81 * \return data + length 82 */ end()83 constexpr iterator end() noexcept { return std::next(begin(), length); } 84 85 /*! \brief Returns a const_iterator to the end of the span 86 * \return data + length 87 */ end()88 constexpr const_iterator end() const noexcept { return std::next(begin(), length); } 89 90 /*! \brief Returns a const_iterator to the begin of the span 91 * \return data 92 */ cbegin()93 constexpr const_iterator cbegin() const noexcept { return begin(); } 94 95 /*! \brief Returns a const_iterator to the end of the span 96 * \return data + length 97 */ cend()98 constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } 99 100 /*! \brief Returns a reverse_iterator to the end of the span 101 * \return reverse_iterator(end()) 102 */ rbegin()103 constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 104 105 /*! \brief Returns a const_reverse_iterator to the end of the span 106 * \return reverse_iterator(end()) 107 */ rbegin()108 constexpr const_reverse_iterator rbegin() const noexcept 109 { 110 return const_reverse_iterator(end()); 111 } 112 113 /*! \brief Returns a reverse_iterator to the begin of the span 114 * \return reverse_iterator(begin()) 115 */ rend()116 constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 117 118 /*! \brief Returns a const_reverse_iterator to the begin of the span 119 * \return reverse_iterator(begin()) 120 */ rend()121 constexpr const_reverse_iterator rend() const noexcept 122 { 123 return const_reverse_iterator(begin()); 124 } 125 126 /*! \brief Returns a const_reverse_iterator to the end of the span 127 * \return rbegin() 128 */ crbegin()129 constexpr const_reverse_iterator crbegin() const noexcept 130 { 131 return const_reverse_iterator(cend()); 132 } 133 134 /*! \brief Returns a const_reverse_iterator to the begin of the span 135 * \return rend() 136 */ crend()137 constexpr const_reverse_iterator crend() const noexcept 138 { 139 return const_reverse_iterator(cbegin()); 140 } 141 142 /*! \brief Unchecked access operator 143 * \param[in] index Index of the element we want to access 144 * \return *(std::next(data, index)) 145 */ 146 constexpr reference operator[](const size_type index) noexcept 147 { 148 assert(length > index); 149 return *(std::next(begin(), index)); 150 } 151 152 /*! \brief Unchecked const access operator 153 * \param[in] index Index of the element we want to access 154 * \return *(std::next(data, index)) 155 */ 156 constexpr const_reference operator[](const size_type index) const noexcept 157 { 158 assert(length > index); 159 return *(std::next(begin(), index)); 160 } 161 162 /*! \brief Returns a reference to the last element of the span 163 * \return *(std::next(data, length - 1)) 164 */ back()165 constexpr reference back() noexcept 166 { 167 assert(length > 0); 168 return *(std::next(begin(), length - 1)); 169 } 170 171 /*! \brief Returns a const_reference to the last element of the span 172 * \return *(std::next(data, length - 1)) 173 */ back()174 constexpr const_reference back() const noexcept 175 { 176 assert(length > 0); 177 return *(std::next(begin(), length - 1)); 178 } 179 180 /*! \brief Returns a reference to the first element of the span 181 * \return *begin() 182 */ front()183 constexpr reference front() noexcept 184 { 185 assert(length > 0); 186 return *begin(); 187 } 188 189 /*! \brief Returns a const_reference to the first element of the span 190 * \return *cbegin() 191 */ front()192 constexpr const_reference front() const noexcept 193 { 194 assert(length > 0); 195 return *cbegin(); 196 } 197 198 /*! \brief Returns true if the span is empty 199 * \return length == 0 200 */ empty()201 constexpr bool empty() const noexcept { return length == 0; } 202 203 /*! \brief Returns the size of the span 204 * \return length == 0 205 */ size()206 constexpr size_type size() const noexcept { return length; } 207 208 /*! \brief Decreases the size of the span by 1 209 */ pop_back()210 constexpr void pop_back() noexcept 211 { 212 assert(length > 0); 213 --length; 214 } 215 216 /*! \brief Adds an element to the end of the span 217 */ push_back(const_reference val)218 constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; } 219 220 /*! \brief Clears the span 221 */ clear()222 constexpr void clear() noexcept 223 { 224 offset = 0; 225 length = 0; 226 } 227 228 private: 229 uint16_t offset{0}; //!> Byte offset from span to data 230 size_type length{0}; //!> Size of the span 231 }; 232 233 /* 234 * Cache-friendly set of 32-bit IDs with O(1) insert/erase/lookup and 235 * the ability to efficiently iterate over contained elements. 236 * 237 * Internally implemented as a bit vector: If the set contains an ID, the 238 * corresponding bit is set. It doesn't use std::vector<bool> since we then 239 * couldn't efficiently iterate over the elements. 240 * 241 * The interface resembles a subset of std::set/std::unordered_set. 242 */ 243 struct IDSet { 244 struct Iterator { 245 const IDSet* set; 246 union { 247 struct { 248 uint32_t bit : 6; 249 uint32_t word : 26; 250 }; 251 uint32_t id; 252 }; 253 254 Iterator& operator++(); 255 256 bool operator!=(const Iterator& other) const; 257 258 uint32_t operator*() const; 259 }; 260 countIDSet261 size_t count(uint32_t id) const 262 { 263 if (id >= words.size() * 64) 264 return 0; 265 266 return words[id / 64u] & (1ull << (id % 64u)) ? 1 : 0; 267 } 268 findIDSet269 Iterator find(uint32_t id) const 270 { 271 if (!count(id)) 272 return end(); 273 274 Iterator it; 275 it.set = this; 276 it.bit = id % 64u; 277 it.word = id / 64u; 278 return it; 279 } 280 insertIDSet281 std::pair<Iterator, bool> insert(uint32_t id) 282 { 283 if (words.size() * 64u <= id) 284 words.resize(id / 64u + 1); 285 286 Iterator it; 287 it.set = this; 288 it.bit = id % 64u; 289 it.word = id / 64u; 290 291 uint64_t mask = 1ull << it.bit; 292 if (words[it.word] & mask) 293 return std::make_pair(it, false); 294 295 words[it.word] |= mask; 296 bits_set++; 297 return std::make_pair(it, true); 298 } 299 eraseIDSet300 size_t erase(uint32_t id) 301 { 302 if (!count(id)) 303 return 0; 304 305 words[id / 64u] ^= 1ull << (id % 64u); 306 bits_set--; 307 return 1; 308 } 309 cbeginIDSet310 Iterator cbegin() const 311 { 312 Iterator it; 313 it.set = this; 314 for (size_t i = 0; i < words.size(); i++) { 315 if (words[i]) { 316 it.word = i; 317 it.bit = ffsll(words[i]) - 1; 318 return it; 319 } 320 } 321 return end(); 322 } 323 cendIDSet324 Iterator cend() const 325 { 326 Iterator it; 327 it.set = this; 328 it.word = words.size(); 329 it.bit = 0; 330 return it; 331 } 332 beginIDSet333 Iterator begin() const { return cbegin(); } 334 endIDSet335 Iterator end() const { return cend(); } 336 emptyIDSet337 bool empty() const { return bits_set == 0; } 338 sizeIDSet339 size_t size() const { return bits_set; } 340 341 std::vector<uint64_t> words; 342 uint32_t bits_set = 0; 343 }; 344 345 inline IDSet::Iterator& 346 IDSet::Iterator::operator++() 347 { 348 uint64_t m = set->words[word]; 349 m &= ~((2ull << bit) - 1ull); 350 if (!m) { 351 /* don't continue past the end */ 352 if (word == set->words.size()) 353 return *this; 354 355 word++; 356 for (; word < set->words.size(); word++) { 357 if (set->words[word]) { 358 bit = ffsll(set->words[word]) - 1; 359 return *this; 360 } 361 } 362 bit = 0; 363 } else { 364 bit = ffsll(m) - 1; 365 } 366 return *this; 367 } 368 369 inline bool 370 IDSet::Iterator::operator!=(const IDSet::Iterator& other) const 371 { 372 assert(set == other.set); 373 return id != other.id; 374 } 375 376 inline uint32_t 377 IDSet::Iterator::operator*() const 378 { 379 return (word << 6) | bit; 380 } 381 382 } // namespace aco 383 384 #endif // ACO_UTIL_H 385