• 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 #include "util/macros.h"
31 #include "util/u_math.h"
32 
33 #include <array>
34 #include <cassert>
35 #include <cstddef>
36 #include <functional>
37 #include <iterator>
38 #include <map>
39 #include <type_traits>
40 #include <unordered_map>
41 #include <vector>
42 
43 namespace aco {
44 
45 /*! \brief      Definition of a span object
46  *
47  *   \details    A "span" is an "array view" type for holding a view of contiguous
48  *               data. The "span" object does not own the data itself.
49  */
50 template <typename T> class span {
51 public:
52    using value_type = T;
53    using pointer = value_type*;
54    using const_pointer = const value_type*;
55    using reference = value_type&;
56    using const_reference = const value_type&;
57    using iterator = pointer;
58    using const_iterator = const_pointer;
59    using reverse_iterator = std::reverse_iterator<iterator>;
60    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
61    using size_type = uint16_t;
62    using difference_type = std::ptrdiff_t;
63 
64    /*! \brief                  Compiler generated default constructor
65     */
66    constexpr span() = default;
67 
68    /*! \brief                 Constructor taking a pointer and the length of the span
69     *  \param[in]   data      Pointer to the underlying data array
70     *  \param[in]   length    The size of the span
71     */
span(uint16_t offset_,const size_type length_)72    constexpr span(uint16_t offset_, const size_type length_) : offset{offset_}, length{length_} {}
73 
74    /*! \brief                 Returns an iterator to the begin of the span
75     *  \return                data
76     */
begin()77    constexpr iterator begin() noexcept { return (pointer)((uintptr_t)this + offset); }
78 
79    /*! \brief                 Returns a const_iterator to the begin of the span
80     *  \return                data
81     */
begin()82    constexpr const_iterator begin() const noexcept
83    {
84       return (const_pointer)((uintptr_t)this + offset);
85    }
86 
87    /*! \brief                 Returns an iterator to the end of the span
88     *  \return                data + length
89     */
end()90    constexpr iterator end() noexcept { return std::next(begin(), length); }
91 
92    /*! \brief                 Returns a const_iterator to the end of the span
93     *  \return                data + length
94     */
end()95    constexpr const_iterator end() const noexcept { return std::next(begin(), length); }
96 
97    /*! \brief                 Returns a const_iterator to the begin of the span
98     *  \return                data
99     */
cbegin()100    constexpr const_iterator cbegin() const noexcept { return begin(); }
101 
102    /*! \brief                 Returns a const_iterator to the end of the span
103     *  \return                data + length
104     */
cend()105    constexpr const_iterator cend() const noexcept { return std::next(begin(), length); }
106 
107    /*! \brief                 Returns a reverse_iterator to the end of the span
108     *  \return                reverse_iterator(end())
109     */
rbegin()110    constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
111 
112    /*! \brief                 Returns a const_reverse_iterator to the end of the span
113     *  \return                reverse_iterator(end())
114     */
rbegin()115    constexpr const_reverse_iterator rbegin() const noexcept
116    {
117       return const_reverse_iterator(end());
118    }
119 
120    /*! \brief                 Returns a reverse_iterator to the begin of the span
121     *   \return                reverse_iterator(begin())
122     */
rend()123    constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
124 
125    /*! \brief                 Returns a const_reverse_iterator to the begin of the span
126     *  \return                reverse_iterator(begin())
127     */
rend()128    constexpr const_reverse_iterator rend() const noexcept
129    {
130       return const_reverse_iterator(begin());
131    }
132 
133    /*! \brief                 Returns a const_reverse_iterator to the end of the span
134     *  \return                rbegin()
135     */
crbegin()136    constexpr const_reverse_iterator crbegin() const noexcept
137    {
138       return const_reverse_iterator(cend());
139    }
140 
141    /*! \brief                 Returns a const_reverse_iterator to the begin of the span
142     *  \return                rend()
143     */
crend()144    constexpr const_reverse_iterator crend() const noexcept
145    {
146       return const_reverse_iterator(cbegin());
147    }
148 
149    /*! \brief                 Unchecked access operator
150     *  \param[in] index       Index of the element we want to access
151     *  \return                *(std::next(data, index))
152     */
153    constexpr reference operator[](const size_type index) noexcept
154    {
155       assert(length > index);
156       return *(std::next(begin(), index));
157    }
158 
159    /*! \brief                 Unchecked const access operator
160     *  \param[in] index       Index of the element we want to access
161     *  \return                *(std::next(data, index))
162     */
163    constexpr const_reference operator[](const size_type index) const noexcept
164    {
165       assert(length > index);
166       return *(std::next(begin(), index));
167    }
168 
169    /*! \brief                 Returns a reference to the last element of the span
170     *  \return                *(std::next(data, length - 1))
171     */
back()172    constexpr reference back() noexcept
173    {
174       assert(length > 0);
175       return *(std::next(begin(), length - 1));
176    }
177 
178    /*! \brief                 Returns a const_reference to the last element of the span
179     *  \return                *(std::next(data, length - 1))
180     */
back()181    constexpr const_reference back() const noexcept
182    {
183       assert(length > 0);
184       return *(std::next(begin(), length - 1));
185    }
186 
187    /*! \brief                 Returns a reference to the first element of the span
188     *  \return                *begin()
189     */
front()190    constexpr reference front() noexcept
191    {
192       assert(length > 0);
193       return *begin();
194    }
195 
196    /*! \brief                 Returns a const_reference to the first element of the span
197     *  \return                *cbegin()
198     */
front()199    constexpr const_reference front() const noexcept
200    {
201       assert(length > 0);
202       return *cbegin();
203    }
204 
205    /*! \brief                 Returns true if the span is empty
206     *  \return                length == 0
207     */
empty()208    constexpr bool empty() const noexcept { return length == 0; }
209 
210    /*! \brief                 Returns the size of the span
211     *  \return                length == 0
212     */
size()213    constexpr size_type size() const noexcept { return length; }
214 
215    /*! \brief                 Decreases the size of the span by 1
216     */
pop_back()217    constexpr void pop_back() noexcept
218    {
219       assert(length > 0);
220       --length;
221    }
222 
223    /*! \brief                 Adds an element to the end of the span
224     */
push_back(const_reference val)225    constexpr void push_back(const_reference val) noexcept { *std::next(begin(), length++) = val; }
226 
227    /*! \brief                 Clears the span
228     */
clear()229    constexpr void clear() noexcept
230    {
231       offset = 0;
232       length = 0;
233    }
234 
235 private:
236    uint16_t offset{0};  //!> Byte offset from span to data
237    size_type length{0}; //!> Size of the span
238 };
239 
240 /*
241  * Cache-friendly set of 32-bit IDs with fast insert/erase/lookup and
242  * the ability to efficiently iterate over contained elements.
243  *
244  * Internally implemented as a map of fixed-size bit vectors: If the set contains an ID, the
245  * corresponding bit in the appropriate bit vector is set. It doesn't use std::vector<bool> since
246  * we then couldn't efficiently iterate over the elements.
247  *
248  * The interface resembles a subset of std::set/std::unordered_set.
249  */
250 struct IDSet {
251    static const uint32_t block_size = 1024u;
252    using block_t = std::array<uint64_t, block_size / 64>;
253 
254    struct Iterator {
255       const IDSet* set;
256       std::map<uint32_t, block_t>::const_iterator block;
257       uint32_t id;
258 
259       Iterator& operator++();
260 
261       bool operator!=(const Iterator& other) const;
262 
263       uint32_t operator*() const;
264    };
265 
countIDSet266    size_t count(uint32_t id) const { return find(id) != end(); }
267 
findIDSet268    Iterator find(uint32_t id) const
269    {
270       uint32_t block_index = id / block_size;
271       auto it = words.find(block_index);
272       if (it == words.end())
273          return end();
274 
275       const block_t& block = it->second;
276       uint32_t sub_id = id % block_size;
277 
278       if (block[sub_id / 64u] & (1ull << (sub_id % 64u)))
279          return Iterator{this, it, id};
280       else
281          return end();
282    }
283 
insertIDSet284    std::pair<Iterator, bool> insert(uint32_t id)
285    {
286       uint32_t block_index = id / block_size;
287       auto it = words.try_emplace(block_index).first;
288       block_t& block = it->second;
289       uint32_t sub_id = id % block_size;
290 
291       uint64_t* word = &block[sub_id / 64u];
292       uint64_t mask = 1ull << (sub_id % 64u);
293       if (*word & mask)
294          return std::make_pair(Iterator{this, it, id}, false);
295 
296       *word |= mask;
297       return std::make_pair(Iterator{this, it, id}, true);
298    }
299 
insertIDSet300    bool insert(const IDSet other)
301    {
302       bool inserted = false;
303 
304       for (auto it = other.words.begin(); it != other.words.end(); ++it) {
305          block_t& dst = words[it->first];
306          const block_t& src = it->second;
307 
308          for (unsigned j = 0; j < src.size(); j++) {
309             uint64_t new_bits = src[j] & ~dst[j];
310             if (new_bits) {
311                inserted = true;
312                dst[j] |= new_bits;
313             }
314          }
315       }
316       return inserted;
317    }
318 
eraseIDSet319    size_t erase(uint32_t id)
320    {
321       uint32_t block_index = id / block_size;
322       auto it = words.find(block_index);
323       if (it == words.end())
324          return 0;
325 
326       block_t& block = it->second;
327       uint32_t sub_id = id % block_size;
328 
329       uint64_t* word = &block[sub_id / 64u];
330       uint64_t mask = 1ull << (sub_id % 64u);
331       if (!(*word & mask))
332          return 0;
333 
334       *word ^= mask;
335       return 1;
336    }
337 
cbeginIDSet338    Iterator cbegin() const
339    {
340       Iterator res;
341       res.set = this;
342 
343       for (auto it = words.begin(); it != words.end(); ++it) {
344          uint32_t first = get_first_set(it->second);
345          if (first != UINT32_MAX) {
346             res.block = it;
347             res.id = it->first * block_size + first;
348             return res;
349          }
350       }
351 
352       return cend();
353    }
354 
cendIDSet355    Iterator cend() const { return Iterator{this, words.end(), UINT32_MAX}; }
356 
beginIDSet357    Iterator begin() const { return cbegin(); }
358 
endIDSet359    Iterator end() const { return cend(); }
360 
sizeIDSet361    size_t size() const
362    {
363       size_t bits_set = 0;
364       for (auto block : words) {
365          for (uint64_t word : block.second)
366             bits_set += util_bitcount64(word);
367       }
368       return bits_set;
369    }
370 
emptyIDSet371    bool empty() const { return !size(); }
372 
373 private:
get_first_setIDSet374    static uint32_t get_first_set(const block_t& words)
375    {
376       for (size_t i = 0; i < words.size(); i++) {
377          if (words[i])
378             return i * 64u + (ffsll(words[i]) - 1);
379       }
380       return UINT32_MAX;
381    }
382 
383    std::map<uint32_t, block_t> words;
384 };
385 
386 inline IDSet::Iterator&
387 IDSet::Iterator::operator++()
388 {
389    uint32_t block_index = id / block_size;
390    const block_t& block_words = block->second;
391    uint32_t sub_id = id % block_size;
392 
393    uint64_t m = block_words[sub_id / 64u];
394    uint32_t bit = sub_id % 64u;
395    m = (m >> bit) >> 1;
396    if (m) {
397       id += ffsll(m);
398       return *this;
399    }
400 
401    for (uint32_t i = sub_id / 64u + 1; i < block_words.size(); i++) {
402       if (block_words[i]) {
403          id = block_index * block_size + i * 64u + ffsll(block_words[i]) - 1;
404          return *this;
405       }
406    }
407 
408    for (++block; block != set->words.end(); ++block) {
409       uint32_t first = get_first_set(block->second);
410       if (first != UINT32_MAX) {
411          id = block->first * block_size + first;
412          return *this;
413       }
414    }
415 
416    id = UINT32_MAX;
417    return *this;
418 }
419 
420 inline bool
421 IDSet::Iterator::operator!=(const IDSet::Iterator& other) const
422 {
423    assert(set == other.set);
424    assert(id != other.id || block == other.block);
425    return id != other.id;
426 }
427 
428 inline uint32_t
429 IDSet::Iterator::operator*() const
430 {
431    return id;
432 }
433 
434 /*
435  * Light-weight memory resource which allows to sequentially allocate from
436  * a buffer. Both, the release() method and the destructor release all managed
437  * memory.
438  *
439  * The memory resource is not thread-safe.
440  * This class mimics std::pmr::monotonic_buffer_resource
441  */
442 class monotonic_buffer_resource final {
443 public:
444    explicit monotonic_buffer_resource(size_t size = initial_size)
445    {
446       /* The size parameter refers to the total size of the buffer.
447        * The usable data_size is size - sizeof(Buffer).
448        */
449       size = MAX2(size, minimum_size);
450       buffer = (Buffer*)malloc(size);
451       buffer->next = nullptr;
452       buffer->data_size = size - sizeof(Buffer);
453       buffer->current_idx = 0;
454    }
455 
~monotonic_buffer_resource()456    ~monotonic_buffer_resource()
457    {
458       release();
459       free(buffer);
460    }
461 
462    /* Delete copy-constructor and -assignment to avoid double free() */
463    monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
464    monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
465 
allocate(size_t size,size_t alignment)466    void* allocate(size_t size, size_t alignment)
467    {
468       buffer->current_idx = align(buffer->current_idx, alignment);
469       if (buffer->current_idx + size <= buffer->data_size) {
470          uint8_t* ptr = &buffer->data[buffer->current_idx];
471          buffer->current_idx += size;
472          return ptr;
473       }
474 
475       /* create new larger buffer */
476       uint32_t total_size = buffer->data_size + sizeof(Buffer);
477       do {
478          total_size *= 2;
479       } while (total_size - sizeof(Buffer) < size);
480       Buffer* next = buffer;
481       buffer = (Buffer*)malloc(total_size);
482       buffer->next = next;
483       buffer->data_size = total_size - sizeof(Buffer);
484       buffer->current_idx = 0;
485 
486       return allocate(size, alignment);
487    }
488 
release()489    void release()
490    {
491       while (buffer->next) {
492          Buffer* next = buffer->next;
493          free(buffer);
494          buffer = next;
495       }
496       buffer->current_idx = 0;
497    }
498 
499    bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; }
500 
501 private:
502    struct Buffer {
503       Buffer* next;
504       uint32_t current_idx;
505       uint32_t data_size;
506       uint8_t data[];
507    };
508 
509    Buffer* buffer;
510    static constexpr size_t initial_size = 4096;
511    static constexpr size_t minimum_size = 128;
512    static_assert(minimum_size > sizeof(Buffer));
513 };
514 
515 /*
516  * Small memory allocator which wraps monotonic_buffer_resource
517  * in order to implement <allocator_traits>.
518  *
519  * This class mimics std::pmr::polymorphic_allocator with monotonic_buffer_resource
520  * as memory resource. The advantage of this specialization is the absence of
521  * virtual function calls and the propagation on swap, copy- and move assignment.
522  */
523 template <typename T> class monotonic_allocator {
524 public:
525    monotonic_allocator() = delete;
monotonic_allocator(monotonic_buffer_resource & m)526    monotonic_allocator(monotonic_buffer_resource& m) : memory_resource(m) {}
527    template <typename U>
monotonic_allocator(const monotonic_allocator<U> & rhs)528    explicit monotonic_allocator(const monotonic_allocator<U>& rhs)
529        : memory_resource(rhs.memory_resource)
530    {}
531 
532    /* Memory Allocation */
allocate(size_t size)533    T* allocate(size_t size)
534    {
535       uint32_t bytes = sizeof(T) * size;
536       return (T*)memory_resource.get().allocate(bytes, alignof(T));
537    }
538 
539    /* Memory will be freed on destruction of memory_resource */
deallocate(T * ptr,size_t size)540    void deallocate(T* ptr, size_t size) {}
541 
542    /* Implement <allocator_traits> */
543    using value_type = T;
544    template <class U> struct rebind {
545       using other = monotonic_allocator<U>;
546    };
547 
548    typedef std::true_type propagate_on_container_copy_assignment;
549    typedef std::true_type propagate_on_container_move_assignment;
550    typedef std::true_type propagate_on_container_swap;
551 
552    template <typename> friend class monotonic_allocator;
553    template <typename X, typename Y>
554    friend bool operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
555    template <typename X, typename Y>
556    friend bool operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b);
557 
558 private:
559    std::reference_wrapper<monotonic_buffer_resource> memory_resource;
560 };
561 
562 /* Necessary for <allocator_traits>. */
563 template <typename X, typename Y>
564 inline bool
565 operator==(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
566 {
567    return a.memory_resource.get() == b.memory_resource.get();
568 }
569 template <typename X, typename Y>
570 inline bool
571 operator!=(monotonic_allocator<X> const& a, monotonic_allocator<Y> const& b)
572 {
573    return !(a == b);
574 }
575 
576 /*
577  * aco::map - alias for std::map with monotonic_allocator
578  *
579  * This template specialization mimics std::pmr::map.
580  */
581 template <class Key, class T, class Compare = std::less<Key>>
582 using map = std::map<Key, T, Compare, aco::monotonic_allocator<std::pair<const Key, T>>>;
583 
584 /*
585  * aco::unordered_map - alias for std::unordered_map with monotonic_allocator
586  *
587  * This template specialization mimics std::pmr::unordered_map.
588  */
589 template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>>
590 using unordered_map =
591    std::unordered_map<Key, T, Hash, Pred, aco::monotonic_allocator<std::pair<const Key, T>>>;
592 
593 /*
594  * Helper class for a integer/bool (access_type) packed into
595  * a bigger integer (data_type) with an offset and size.
596  * It can be implicitly converted to access_type and supports
597  * all arithmetic assignment operators.
598  *
599  * When used together with a union, this allows storing
600  * multiple fields packed into a single integer.
601  *
602  * Example usage:
603  * union {
604  *    bitfield_uint<uint32_t, 0,  5,  uint8_t> int5;
605  *    bitfield_uint<uint32_t, 5,  26, uint32_t> int26;
606  *    bitfield_uint<uint32_t, 31, 1,  bool> bool1;
607  * };
608  *
609  */
610 template <typename data_type, unsigned offset, unsigned size, typename access_type>
611 class bitfield_uint {
612 public:
613    static_assert(sizeof(data_type) >= sizeof(access_type), "");
614    static_assert(std::is_unsigned<access_type>::value, "");
615    static_assert(std::is_unsigned<data_type>::value, "");
616    static_assert(sizeof(data_type) * 8 >= offset + size, "");
617    static_assert(sizeof(access_type) * 8 >= size, "");
618    static_assert(size > 0, "");
619    static_assert(!std::is_same_v<access_type, bool> || size == 1, "");
620 
621    bitfield_uint() = default;
622 
bitfield_uint(const access_type & value)623    constexpr bitfield_uint(const access_type& value) { *this = value; }
624 
access_type()625    constexpr operator access_type() const { return (storage >> offset) & mask; }
626 
627    constexpr bitfield_uint& operator=(const access_type& value)
628    {
629       storage &= ~(mask << offset);
630       storage |= data_type(value & mask) << offset;
631       return *this;
632    }
633 
634    constexpr bitfield_uint& operator=(const bitfield_uint& value)
635    {
636       return *this = access_type(value);
637    }
638 
639    constexpr bitfield_uint& operator|=(const access_type& value)
640    {
641       storage |= data_type(value & mask) << offset;
642       return *this;
643    }
644 
645    constexpr bitfield_uint& operator^=(const access_type& value)
646    {
647       storage ^= data_type(value & mask) << offset;
648       return *this;
649    }
650 
651    constexpr bitfield_uint& operator&=(const access_type& value)
652    {
653       storage &= (data_type(value & mask) << offset) | ~(mask << offset);
654       return *this;
655    }
656 
657    constexpr bitfield_uint& operator<<=(const access_type& shift)
658    {
659       static_assert(!std::is_same_v<access_type, bool>, "");
660       assert(shift < size);
661       return *this = access_type(*this) << shift;
662    }
663 
664    constexpr bitfield_uint& operator>>=(const access_type& shift)
665    {
666       static_assert(!std::is_same_v<access_type, bool>, "");
667       assert(shift < size);
668       return *this = access_type(*this) >> shift;
669    }
670 
671    constexpr bitfield_uint& operator*=(const access_type& op)
672    {
673       static_assert(!std::is_same_v<access_type, bool>, "");
674       return *this = access_type(*this) * op;
675    }
676 
677    constexpr bitfield_uint& operator/=(const access_type& op)
678    {
679       static_assert(!std::is_same_v<access_type, bool>, "");
680       return *this = access_type(*this) / op;
681    }
682 
683    constexpr bitfield_uint& operator%=(const access_type& op)
684    {
685       static_assert(!std::is_same_v<access_type, bool>, "");
686       return *this = access_type(*this) % op;
687    }
688 
689    constexpr bitfield_uint& operator+=(const access_type& op)
690    {
691       static_assert(!std::is_same_v<access_type, bool>, "");
692       return *this = access_type(*this) + op;
693    }
694 
695    constexpr bitfield_uint& operator-=(const access_type& op)
696    {
697       static_assert(!std::is_same_v<access_type, bool>, "");
698       return *this = access_type(*this) - op;
699    }
700 
701    constexpr bitfield_uint& operator++()
702    {
703       static_assert(!std::is_same_v<access_type, bool>, "");
704       return *this += 1;
705    }
706 
707    constexpr access_type operator++(int)
708    {
709       static_assert(!std::is_same_v<access_type, bool>, "");
710       access_type temp = *this;
711       ++*this;
712       return temp;
713    }
714 
715    constexpr bitfield_uint& operator--()
716    {
717       static_assert(!std::is_same_v<access_type, bool>, "");
718       return *this -= 1;
719    }
720 
721    constexpr access_type operator--(int)
722    {
723       static_assert(!std::is_same_v<access_type, bool>, "");
724       access_type temp = *this;
725       --*this;
726       return temp;
727    }
728 
swap(access_type & other)729    constexpr void swap(access_type& other)
730    {
731       access_type tmp = *this;
732       *this = other;
733       other = tmp;
734    }
735 
736    template <typename other_dt, unsigned other_off, unsigned other_s>
swap(bitfield_uint<other_dt,other_off,other_s,access_type> & other)737    constexpr void swap(bitfield_uint<other_dt, other_off, other_s, access_type>& other)
738    {
739       access_type tmp = *this;
740       *this = other;
741       other = tmp;
742    }
743 
744 protected:
745    static const data_type mask = BITFIELD64_MASK(size);
746 
747    data_type storage;
748 };
749 
750 /*
751  * Reference to a single bit in an integer that can be converted to a bool
752  * and supports bool (bitwise) assignment operators.
753  */
754 template <typename T> struct bit_reference {
bit_referencebit_reference755    constexpr bit_reference(T& s, unsigned b) : storage(s), bit(b) {}
756 
757    constexpr bit_reference& operator=(const bit_reference& other) { return *this = (bool)other; }
758 
759    constexpr bit_reference& operator=(bool val)
760    {
761       storage &= ~(T(0x1) << bit);
762       storage |= T(val) << bit;
763       return *this;
764    }
765 
766    constexpr bit_reference& operator^=(bool val)
767    {
768       storage ^= T(val) << bit;
769       return *this;
770    }
771 
772    constexpr bit_reference& operator|=(bool val)
773    {
774       storage |= T(val) << bit;
775       return *this;
776    }
777 
778    constexpr bit_reference& operator&=(bool val)
779    {
780       storage &= T(val) << bit;
781       return *this;
782    }
783 
784    constexpr operator bool() const { return (storage >> bit) & 0x1; }
785 
swapbit_reference786    constexpr void swap(bool& other)
787    {
788       bool tmp = (bool)*this;
789       *this = other;
790       other = tmp;
791    }
792 
swapbit_reference793    template <typename other_T> constexpr void swap(bit_reference<other_T> other)
794    {
795       bool tmp = (bool)*this;
796       *this = (bool)other;
797       other = tmp;
798    }
799 
800    T& storage;
801    unsigned bit;
802 };
803 
804 /*
805  * Base template for (const) bit iterators over an integer.
806  * Only intended to be used with the two specializations
807  * bitfield_array::iterator and bitfield_array::const_iterator.
808  */
809 template <typename T, typename refT, typename ptrT> struct bitfield_iterator {
810    using difference_type = int;
811    using value_type = bool;
812    using iterator_category = std::random_access_iterator_tag;
813    using reference = refT;
814    using const_reference = bool;
815    using pointer = ptrT;
816    using iterator = bitfield_iterator<T, refT, ptrT>;
817    using ncT = std::remove_const_t<T>;
818 
bitfield_iteratorbitfield_iterator819    constexpr bitfield_iterator() : bf(nullptr), index(0) {}
bitfield_iteratorbitfield_iterator820    constexpr bitfield_iterator(T* p, unsigned i) : bf(p), index(i) {}
821 
822    /* const iterator must be constructable from iterator */
bitfield_iteratorbitfield_iterator823    constexpr bitfield_iterator(
824       const bitfield_iterator<ncT, bit_reference<ncT>, bit_reference<ncT>*>& x)
825        : bf(x.bf), index(x.index)
826    {}
827 
828    constexpr bool operator==(const bitfield_iterator& other) const
829    {
830       return bf == other.bf && index == other.index;
831    }
832 
833    constexpr bool operator<(const bitfield_iterator& other) const { return index < other.index; }
834 
835    constexpr bool operator!=(const bitfield_iterator& other) const { return !(*this == other); }
836 
837    constexpr bool operator>(const bitfield_iterator& other) const { return other < *this; }
838 
839    constexpr bool operator<=(const bitfield_iterator& other) const { return !(other < *this); }
840 
841    constexpr bool operator>=(const bitfield_iterator& other) const { return !(*this < other); }
842 
843    constexpr reference operator*() const { return bit_reference<T>(*bf, index); }
844 
845    constexpr iterator& operator++()
846    {
847       index++;
848       return *this;
849    }
850 
851    constexpr iterator operator++(int)
852    {
853       iterator tmp = *this;
854       index++;
855       return tmp;
856    }
857 
858    constexpr iterator& operator--()
859    {
860       index--;
861       return *this;
862    }
863 
864    constexpr iterator operator--(int)
865    {
866       iterator tmp = *this;
867       index--;
868       return tmp;
869    }
870 
871    constexpr iterator& operator+=(difference_type value)
872    {
873       index += value;
874       return *this;
875    }
876 
877    constexpr iterator& operator-=(difference_type value)
878    {
879       *this += -value;
880       return *this;
881    }
882 
883    constexpr iterator operator+(difference_type value) const
884    {
885       iterator tmp = *this;
886       return tmp += value;
887    }
888 
889    constexpr iterator operator-(difference_type value) const
890    {
891       iterator tmp = *this;
892       return tmp -= value;
893    }
894 
895    constexpr reference operator[](difference_type value) const { return *(*this + value); }
896 
897    T* bf;
898    unsigned index;
899 };
900 
901 template <typename T, typename refT, typename ptrT>
902 constexpr inline bitfield_iterator<T, refT, ptrT>
903 operator+(int n, const bitfield_iterator<T, refT, ptrT>& x)
904 {
905    return x + n;
906 }
907 
908 template <typename T, typename refT, typename ptrT>
909 constexpr inline int
910 operator-(const bitfield_iterator<T, refT, ptrT> x, const bitfield_iterator<T, refT, ptrT>& y)
911 {
912    return x.index - y.index;
913 }
914 
915 /*
916  * Extends bitfield_uint with operator[] and iterators that
917  * allow accessing single bits within the uint. Can be used
918  * as a more compact version of bool arrays that also still
919  * allows accessing the whole array as an integer.
920  */
921 template <typename data_type, unsigned offset, unsigned size, typename access_type>
922 class bitfield_array : public bitfield_uint<data_type, offset, size, access_type> {
923 public:
924    using value_type = bool;
925    using size_type = unsigned;
926    using difference_type = int;
927    using reference = bit_reference<data_type>;
928    using const_reference = bool;
929    using pointer = bit_reference<data_type>*;
930    using const_pointer = const bool*;
931    using iterator =
932       bitfield_iterator<data_type, bit_reference<data_type>, bit_reference<data_type>*>;
933    using const_iterator = bitfield_iterator<const data_type, bool, const bool*>;
934    using reverse_iterator = std::reverse_iterator<iterator>;
935    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
936 
937    bitfield_array() = default;
938 
bitfield_array(const access_type & value)939    constexpr bitfield_array(const access_type& value) { *this = value; }
940 
941    constexpr bitfield_array& operator=(const access_type& value)
942    {
943       storage &= ~(mask << offset);
944       storage |= data_type(value & mask) << offset;
945       return *this;
946    }
947 
948    constexpr bitfield_array& operator=(const bitfield_array& value)
949    {
950       return *this = access_type(value);
951    }
952 
953    constexpr reference operator[](unsigned index)
954    {
955       assert(index < size);
956       return reference(storage, offset + index);
957    }
958 
959    constexpr bool operator[](unsigned index) const
960    {
961       assert(index < size);
962       return (storage >> (offset + index)) & 0x1;
963    }
964 
begin()965    constexpr iterator begin() noexcept { return iterator(&storage, offset); }
966 
end()967    constexpr iterator end() noexcept { return std::next(begin(), size); }
968 
begin()969    constexpr const_iterator begin() const noexcept { return const_iterator(&storage, offset); }
970 
end()971    constexpr const_iterator end() const noexcept { return std::next(begin(), size); }
972 
cbegin()973    constexpr const_iterator cbegin() const noexcept { return begin(); }
974 
cend()975    constexpr const_iterator cend() const noexcept { return std::next(begin(), size); }
976 
rbegin()977    constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
978 
rend()979    constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
980 
rbegin()981    constexpr const_reverse_iterator rbegin() const noexcept
982    {
983       return const_reverse_iterator(end());
984    }
985 
rend()986    constexpr const_reverse_iterator rend() const noexcept
987    {
988       return const_reverse_iterator(begin());
989    }
990 
crbegin()991    constexpr const_reverse_iterator crbegin() const noexcept
992    {
993       return const_reverse_iterator(cend());
994    }
995 
crend()996    constexpr const_reverse_iterator crend() const noexcept
997    {
998       return const_reverse_iterator(cbegin());
999    }
1000 
1001 private:
1002    using bitfield_uint<data_type, offset, size, access_type>::storage;
1003    using bitfield_uint<data_type, offset, size, access_type>::mask;
1004 };
1005 
1006 template <typename T, unsigned offset> using bitfield_bool = bitfield_uint<T, offset, 1, bool>;
1007 
1008 template <typename T, unsigned offset, unsigned size>
1009 using bitfield_uint8 = bitfield_uint<T, offset, size, uint8_t>;
1010 
1011 template <typename T, unsigned offset, unsigned size>
1012 using bitfield_uint16 = bitfield_uint<T, offset, size, uint16_t>;
1013 
1014 template <typename T, unsigned offset, unsigned size>
1015 using bitfield_uint32 = bitfield_uint<T, offset, size, uint32_t>;
1016 
1017 template <typename T, unsigned offset, unsigned size>
1018 using bitfield_uint64 = bitfield_uint<T, offset, size, uint64_t>;
1019 
1020 template <typename T, unsigned offset, unsigned size>
1021 using bitfield_array8 = bitfield_array<T, offset, size, uint8_t>;
1022 
1023 template <typename T, unsigned offset, unsigned size>
1024 using bitfield_array16 = bitfield_array<T, offset, size, uint16_t>;
1025 
1026 template <typename T, unsigned offset, unsigned size>
1027 using bitfield_array32 = bitfield_array<T, offset, size, uint32_t>;
1028 
1029 template <typename T, unsigned offset, unsigned size>
1030 using bitfield_array64 = bitfield_array<T, offset, size, uint64_t>;
1031 
1032 using bitarray8 = bitfield_array<uint8_t, 0, 8, uint8_t>;
1033 
1034 } // namespace aco
1035 
1036 #endif // ACO_UTIL_H
1037