diff --git a/src/util/util_small_vector.h b/src/util/util_small_vector.h new file mode 100644 index 000000000..c313ca4b1 --- /dev/null +++ b/src/util/util_small_vector.h @@ -0,0 +1,133 @@ +#pragma once + +#include + +namespace dxvk { + + template + class small_vector { + using storage = std::aligned_storage_t; + public: + + small_vector() { } + + small_vector (const small_vector&) = delete; + small_vector& operator = (const small_vector&) = delete; + + ~small_vector() { + for (size_t i = 0; i < m_size; i++) + ptr(i)->~T(); + + if (m_capacity > N) + delete[] u.m_ptr; + } + + size_t size() const { + return m_size; + } + + void reserve(size_t n) { + n = pick_capacity(n); + + if (n <= m_capacity) + return; + + storage* data = new storage[n]; + + for (size_t i = 0; i < m_size; i++) { + new (&data[i]) T(std::move(*ptr(i))); + ptr(i)->~T(); + } + + if (m_capacity > N) + delete[] u.m_ptr; + + m_capacity = n; + u.m_ptr = data; + } + + const T* data() const { return ptr(0); } + T* data() { return ptr(0); } + + void resize(size_t n) { + reserve(n); + + for (size_t i = n; i < m_size; i++) + ptr(i)->~T(); + + for (size_t i = m_size; i < n; i++) + new (ptr(i)) T(); + } + + void push_back(const T& object) { + reserve(m_size + 1); + new (ptr(m_size++)) T(object); + } + + void push_back(T&& object) { + reserve(m_size + 1); + new (ptr(m_size++)) T(std::move(object)); + } + + template + void emplace_back(Args... args) { + reserve(m_size + 1); + new (ptr(m_size++)) T(std::forward(args)...); + } + + void erase(size_t idx) { + ptr(idx)->~T(); + + for (size_t i = idx; i < m_size - 1; i++) { + new (ptr(i)) T(std::move(*ptr(i + 1))); + ptr(i + 1)->~T(); + } + } + + void pop_back() { + ptr(--m_size)->~T(); + } + + T& operator [] (size_t idx) { return *ptr(idx); } + const T& operator [] (size_t idx) const { return *ptr(idx); } + + T& front() { return *ptr(0); } + const T& front() const { return *ptr(0); } + + T& back() { return *ptr(m_size - 1); } + const T& back() const { return *ptr(m_size - 1); } + + private: + + size_t m_capacity = N; + size_t m_size = 0; + + union { + storage* m_ptr; + storage m_data[sizeof(T) * N]; + } u; + + size_t pick_capacity(size_t n) { + size_t capacity = m_capacity; + + while (capacity < n) + capacity *= 2; + + return capacity; + } + + T* ptr(size_t idx) { + return m_capacity == N + ? reinterpret_cast(&u.m_data[idx]) + : reinterpret_cast(&u.m_ptr[idx]); + } + + const T* ptr(size_t idx) const { + return m_capacity == N + ? reinterpret_cast(&u.m_data[idx]) + : reinterpret_cast(&u.m_ptr[idx]); + } + + }; + +}