• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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