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