From 602f571c1d72293d773ff9ea9f4a88d2e271dc7d Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Sat, 25 Apr 2026 19:42:42 +0200 Subject: [PATCH] feat(bindless): Backport inplace_vector for constexpr --- .../modules/pipeline/signature/helpers.hpp | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lsfg-vk-backend/src/modules/pipeline/signature/helpers.hpp diff --git a/lsfg-vk-backend/src/modules/pipeline/signature/helpers.hpp b/lsfg-vk-backend/src/modules/pipeline/signature/helpers.hpp new file mode 100644 index 0000000..2674ea5 --- /dev/null +++ b/lsfg-vk-backend/src/modules/pipeline/signature/helpers.hpp @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lsfgvk::pipeline { + + /// C++26 backported inplace_vector + template + 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 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& 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 + 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)...); + 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 m_data{}; + size_t m_size{0}; +#pragma clang diagnostic pop + }; + +}