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