Home | History | Annotate | Line # | Download | only in compiler
      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     */
     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     */
     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     */
     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     */
     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     */
     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     */
     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     */
     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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    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     */
    201    constexpr bool empty() const noexcept { return length == 0; }
    202 
    203    /*! \brief                 Returns the size of the span
    204     *  \return                length == 0
    205     */
    206    constexpr size_type size() const noexcept { return length; }
    207 
    208    /*! \brief                 Decreases the size of the span by 1
    209     */
    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     */
    218    constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; }
    219 
    220    /*! \brief                 Clears the span
    221     */
    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 
    261    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 
    269    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 
    281    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 
    300    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 
    310    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 
    324    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 
    333    Iterator begin() const { return cbegin(); }
    334 
    335    Iterator end() const { return cend(); }
    336 
    337    bool empty() const { return bits_set == 0; }
    338 
    339    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