diff --git a/src/amd/compiler/aco_util.h b/src/amd/compiler/aco_util.h index 9659f5a98f6..7fdab9d6f06 100644 --- a/src/amd/compiler/aco_util.h +++ b/src/amd/compiler/aco_util.h @@ -1031,6 +1031,153 @@ using bitfield_array64 = bitfield_array; using bitarray8 = bitfield_array; +/* + * Resizable array optimized for small lengths. If it's smaller than Size, the elements will be + * inlined into the object. + */ +template class small_vec { +public: + static_assert(std::is_trivially_copyable::value); + static_assert(std::is_trivially_destructible::value); + + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = uint16_t; + using difference_type = std::ptrdiff_t; + + constexpr small_vec() = default; + constexpr small_vec(const small_vec&) = delete; + + ~small_vec() + { + if (capacity > Size) + free(data); + } + + constexpr small_vec& operator=(const small_vec&) = delete; + + constexpr iterator begin() noexcept { return capacity > Size ? data : inline_data; } + + constexpr const_iterator begin() const noexcept { return capacity > Size ? data : inline_data; } + + constexpr iterator end() noexcept { return std::next(begin(), length); } + + constexpr const_iterator end() const noexcept { return std::next(begin(), length); } + + constexpr const_iterator cbegin() const noexcept { return begin(); } + + constexpr const_iterator cend() const noexcept { return std::next(begin(), length); } + + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + + constexpr const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + + constexpr const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + + constexpr const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + constexpr const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + constexpr reference operator[](const size_type index) noexcept + { + assert(length > index); + return *(std::next(begin(), index)); + } + + constexpr const_reference operator[](const size_type index) const noexcept + { + assert(length > index); + return *(std::next(begin(), index)); + } + + constexpr reference back() noexcept + { + assert(length > 0); + return *(std::next(begin(), length - 1)); + } + + constexpr const_reference back() const noexcept + { + assert(length > 0); + return *(std::next(begin(), length - 1)); + } + + constexpr reference front() noexcept + { + assert(length > 0); + return *begin(); + } + + constexpr const_reference front() const noexcept + { + assert(length > 0); + return *cbegin(); + } + + constexpr bool empty() const noexcept { return length == 0; } + + constexpr size_type size() const noexcept { return length; } + + constexpr void pop_back() noexcept + { + assert(length > 0); + --length; + } + + template constexpr void emplace_back(Args... args) noexcept + { + if (length == capacity) { + if (capacity > Size) { + capacity *= 2; + data = (T*)realloc(data, sizeof(T) * capacity); + } else { + capacity *= 2; + T* ptr = (T*)malloc(sizeof(T) * capacity); + memcpy(ptr, inline_data, sizeof(T) * length); + data = ptr; + } + } + *std::next(begin(), length++) = T(args...); + } + + constexpr void clear() noexcept + { + if (capacity > Size) + free(data); + length = 0; + capacity = 0; + } + +private: + uint32_t length = 0; + uint32_t capacity = Size; + union { + T* data = NULL; + T inline_data[Size]; + }; +}; + } // namespace aco #endif // ACO_UTIL_H