C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
nonuniform_grid_buffer.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <algorithm>
26#include <array>
27#include <concepts>
28#include <cstddef>
29#include <numeric>
30#include <span>
31#include <type_traits>
32#include <utility>
33
34namespace essence {
41 template <typename T, std::size_t Rows, std::size_t... ComponentCells>
43 public:
44 static constexpr std::array component_cells{ComponentCells...};
45 static constexpr std::size_t row_count = Rows;
46 static constexpr std::size_t row_cell_count = (ComponentCells + ...);
47 static constexpr std::size_t byte_stride = row_cell_count * sizeof(T);
48
49 template <std::size_t I, template <typename> typename Decorator = std::type_identity>
50 requires(I < component_cells.size())
51 using component_span = std::span<typename Decorator<T>::type, std::get<I>(component_cells)>;
52
53 template <std::size_t I, template <typename> typename Decorator = std::type_identity>
54 requires(I < component_cells.size())
55 using component_byte_span =
56 std::span<typename Decorator<std::byte>::type, std::get<I>(component_cells) * sizeof(T)>;
57
58 nonuniform_grid_buffer() : buffer_{} {}
59
66 template <std::size_t Row, std::size_t I>
67 requires(Row < Rows && I < component_cells.size())
68 auto get_component() noexcept {
69 auto iter = get_component_iter<Row, I, false>(*this);
70
71 return component_span<I>{iter, iter + component_span<I>::extent};
72 }
73
80 template <std::size_t Row, std::size_t I>
81 requires(Row < Rows && I < component_cells.size())
82 auto get_component() const noexcept {
83 auto iter = get_component_iter<Row, I, false>(*this);
84
85 return component_span<I, std::add_const>{iter, iter + component_span<I, std::add_const>::extent};
86 }
87
94 template <std::size_t Row, std::size_t I>
95 requires(Row < Rows && I < component_cells.size())
96 void set_component(component_byte_span<I, std::add_const> data) noexcept {
97 auto iter = get_component_iter<Row, I, true>(*this);
98
99 std::ranges::copy(data.data(), data.data() + data.size(), iter);
100 }
101
108 template <std::size_t Row, std::size_t I>
109 requires(Row < Rows && I < component_cells.size())
110 void set_component(component_span<I, std::add_const> data) noexcept {
111 set_component<Row, I>(std::as_bytes(data));
112 }
113
118 std::span<std::byte, byte_stride * Rows> underlying_buffer() noexcept {
119 return std::as_writable_bytes(std::span{buffer_});
120 }
121
126 std::span<const std::byte, byte_stride * Rows> underlying_buffer() const noexcept {
127 return std::as_bytes(std::span{buffer_});
128 }
129
130 private:
131 template <std::size_t Row, std::size_t I, bool AsBytes, typename Self>
132 requires(
133 Row < Rows && I < component_cells.size() && std::same_as<std::decay_t<Self>, nonuniform_grid_buffer>)
134 static auto get_component_iter(Self&& self) noexcept {
135 // Calculates the byte offset of the component.
136 static constexpr std::size_t offset =
137 std::accumulate(component_cells.begin(), component_cells.begin() + I, 0U) + Row * row_cell_count;
138
139 auto component_data = std::forward<Self>(self).buffer_.data() + offset;
140
141 if constexpr (AsBytes) {
142 // Simulates deducing this in C++23.
143 if constexpr (std::is_const_v<std::remove_reference_t<Self>>) {
144 return reinterpret_cast<const std::byte*>(component_data);
145 } else {
146 return reinterpret_cast<std::byte*>(component_data);
147 }
148 } else {
149 return component_data;
150 }
151 }
152
153 std::array<T, row_cell_count * Rows> buffer_;
154 };
155} // namespace essence
A fixed memory buffer, in which data are arranged within nonuniform grid cells.
Definition nonuniform_grid_buffer.hpp:42
std::span< std::byte, byte_stride *Rows > underlying_buffer() noexcept
Gets the underlying buffer as a mutable byte span.
Definition nonuniform_grid_buffer.hpp:118
auto get_component() noexcept
Gets the component as a mutable cell span.
Definition nonuniform_grid_buffer.hpp:68
std::span< const std::byte, byte_stride *Rows > underlying_buffer() const noexcept
Gets the underlying buffer as a const byte span.
Definition nonuniform_grid_buffer.hpp:126
void set_component(component_byte_span< I, std::add_const > data) noexcept
Sets the data of a component.
Definition nonuniform_grid_buffer.hpp:96