aco/util: add small_vec

Signed-off-by: Rhys Perry <pendingchaos02@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27984>
This commit is contained in:
Rhys Perry
2023-06-14 18:46:28 +01:00
committed by Marge Bot
parent 4564ca313b
commit 5cbd7689be
+147
View File
@@ -1031,6 +1031,153 @@ using bitfield_array64 = bitfield_array<T, offset, size, uint64_t>;
using bitarray8 = bitfield_array<uint8_t, 0, 8, uint8_t>;
/*
* Resizable array optimized for small lengths. If it's smaller than Size, the elements will be
* inlined into the object.
*/
template <typename T, uint32_t Size> class small_vec {
public:
static_assert(std::is_trivially_copyable<T>::value);
static_assert(std::is_trivially_destructible<T>::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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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 <typename... Args> 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