feat(bindless): Backport inplace_vector for constexpr

This commit is contained in:
PancakeTAS 2026-04-25 19:42:42 +02:00
parent 93816ef4ab
commit 602f571c1d
No known key found for this signature in database

View file

@ -0,0 +1,93 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
#include <initializer_list>
#include <new>
#include <stdexcept>
#include <utility>
#include <vector>
namespace lsfgvk::pipeline {
/// C++26 backported inplace_vector
template<typename T, size_t N>
class inplace_vector {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
public:
// Constructors
constexpr inplace_vector() = default;
constexpr inplace_vector(std::initializer_list<T> init) {
if (init.size() > N) throw std::bad_alloc();
for (auto& elem : init)
this->m_data.at(this->m_size++) = elem;
}
constexpr inplace_vector(const std::vector<T>& vec) {
if (vec.size() > N) throw std::bad_alloc();
for (const auto& elem : vec)
this->m_data.at(this->m_size++) = elem;
}
// Appending elements
constexpr void push_back(const T& value) {
if (this->m_size >= N) throw std::bad_alloc();
this->m_data.at(this->m_size++) = value;
}
constexpr void push_back(T&& value) {
if (this->m_size >= N) throw std::bad_alloc();
this->m_data.at(this->m_size++) = std::move(value);
}
template<typename... Args>
constexpr T& emplace_back(Args&&... args) {
if (this->m_size >= N) throw std::bad_alloc();
this->m_data.at(this->m_size) = T(std::forward<Args>(args)...);
return this->m_data.at(this->m_size++);
}
constexpr void clear() { this->m_size = 0; }
// Accessing elements
constexpr T& operator[](size_t idx) { return this->m_data.at(idx); }
constexpr const T& operator[](size_t idx) const { return this->m_data.at(idx); }
[[nodiscard]] constexpr T& at(size_t idx) {
if (idx >= this->m_size) throw std::out_of_range("Index out of range");
return this->m_data.at(idx);
}
[[nodiscard]] constexpr const T& at(size_t idx) const {
if (idx >= this->m_size) throw std::out_of_range("Index out of range");
return this->m_data.at(idx);
}
[[nodiscard]] constexpr T& front() { return this->m_data.front(); }
[[nodiscard]] constexpr const T& front() const { return this->m_data.front(); }
[[nodiscard]] constexpr T& back() { return this->m_data.at(this->m_size - 1); }
[[nodiscard]] constexpr const T& back() const { return this->m_data.at(this->m_size - 1); }
// Iterating elements
[[nodiscard]] constexpr T* begin() { return this->m_data.data(); }
[[nodiscard]] constexpr const T* begin() const { return this->m_data.data(); }
[[nodiscard]] constexpr const T* cbegin() const { return this->m_data.data(); }
[[nodiscard]] constexpr T* end() { return this->m_data.data() + this->m_size; } // NOLINT (pointer arithmetic)
[[nodiscard]] constexpr const T* end() const { return this->m_data.data() + this->m_size; } // NOLINT (pointer arithmetic)
[[nodiscard]] constexpr const T* cend() const { return this->m_data.data() + this->m_size; } // NOLINT (pointer arithmetic)
// Removing elements
constexpr void pop_back() {
if (this->m_size == 0) throw std::out_of_range("Vector is empty");
this->m_size--;
}
// Query capacity
[[nodiscard]] constexpr size_t size() const { return this->m_size; }
[[nodiscard]] constexpr size_t capacity() const { return N; }
[[nodiscard]] constexpr bool empty() const { return this->m_size == 0; }
private:
std::array<T, N> m_data{};
size_t m_size{0};
#pragma clang diagnostic pop
};
}