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