38 using shape_type =
Shape;
39 using schema_type = Schema;
43 static constexpr std::uint64_t chunk_count = ShapeTraits<Shape>::chunk_count;
44 static constexpr std::uint64_t local_tile_count =
45 ShapeTraits<Shape>::local_tile_count;
46 static constexpr std::size_t field_count = Schema::field_count;
47 static constexpr std::size_t page_byte_size = page_type::byte_size;
48 static constexpr std::size_t storage_byte_size =
49 static_cast<std::size_t
>(chunk_count) * page_byte_size;
51 static_assert(chunk_count <= static_cast<std::uint64_t>(
52 std::numeric_limits<std::size_t>::max()),
53 "AlwaysResident World chunk count must fit std::size_t.");
54 static_assert(page_byte_size <= std::numeric_limits<std::size_t>::max() /
55 static_cast<std::size_t
>(chunk_count),
56 "AlwaysResident World storage bytes must fit std::size_t.");
60 pages_.reserve(
static_cast<std::size_t
>(chunk_count));
61 metadata_.reserve(
static_cast<std::size_t
>(chunk_count));
62 for (std::uint64_t key = 0; key < chunk_count; ++key) {
64 pages_.emplace_back(
chunk, chunk_coord<Shape>(
chunk));
65 metadata_.emplace_back();
67 dirty_flags_.assign(
static_cast<std::size_t
>(chunk_count), 0u);
68 active_flags_.assign(
static_cast<std::size_t
>(chunk_count), 0u);
69 dirty_bounds_.assign(
static_cast<std::size_t
>(chunk_count),
Box3{});
73 [[nodiscard]]
auto chunks() noexcept -> std::span<page_type> {
74 return {pages_.data(), pages_.size()};
78 [[nodiscard]]
auto chunks() const noexcept -> std::span<const page_type> {
79 return {pages_.data(), pages_.size()};
87 TESS_ASSERT(key.value < chunk_count);
88 return pages_[
static_cast<std::size_t
>(key.value)];
92 [[nodiscard]]
auto chunk(
ChunkKey key)
const noexcept ->
const page_type& {
93 TESS_ASSERT(key.value < chunk_count);
94 return pages_[
static_cast<std::size_t
>(key.value)];
102 return chunk(chunk_key<Shape>(coord));
107 ->
const page_type& {
108 return chunk(chunk_key<Shape>(coord));
113 if (key.value >= chunk_count) {
121 ->
const page_type* {
122 if (key.value >= chunk_count) {
130 if (!contains_chunk(coord)) {
133 return &
chunk(coord);
138 ->
const page_type* {
139 if (!contains_chunk(coord)) {
142 return &
chunk(coord);
150 TESS_ASSERT(key.value < chunk_count);
151 return metadata_[
static_cast<std::size_t
>(key.value)];
155 TESS_ASSERT(key.value < chunk_count);
156 return metadata_[
static_cast<std::size_t
>(key.value)];
159 [[nodiscard]]
auto meta(ChunkCoord3 coord)
noexcept -> ChunkMeta& {
160 return meta(chunk_key<Shape>(coord));
163 [[nodiscard]]
auto meta(ChunkCoord3 coord)
const noexcept
164 ->
const ChunkMeta& {
165 return meta(chunk_key<Shape>(coord));
170 if (key.value >= chunk_count) {
177 if (key.value >= chunk_count) {
183 [[nodiscard]]
auto try_meta(ChunkCoord3 coord)
noexcept -> ChunkMeta* {
184 if (!contains_chunk(coord)) {
190 [[nodiscard]]
auto try_meta(ChunkCoord3 coord)
const noexcept
191 ->
const ChunkMeta* {
192 if (!contains_chunk(coord)) {
198 [[nodiscard]]
auto chunk_state(ChunkKey key)
const noexcept -> ChunkState {
199 return meta(key).state;
202 [[nodiscard]]
auto chunk_state(ChunkCoord3 coord)
const noexcept
204 return meta(coord).state;
207 void set_chunk_state(ChunkKey key, ChunkState state)
noexcept {
208 meta(key).state = state;
213 [[nodiscard]]
auto dirty_flags(ChunkKey key)
const noexcept -> std::uint32_t {
214 TESS_ASSERT(key.value < chunk_count);
215 return dirty_flags_[
static_cast<std::size_t
>(key.value)];
218 [[nodiscard]]
auto active_flags(ChunkKey key)
const noexcept
220 TESS_ASSERT(key.value < chunk_count);
221 return active_flags_[
static_cast<std::size_t
>(key.value)];
224 [[nodiscard]]
auto dirty_bounds(ChunkKey key)
const noexcept -> Box3 {
225 TESS_ASSERT(key.value < chunk_count);
226 return dirty_bounds_[
static_cast<std::size_t
>(key.value)];
229 void mark_dirty(ChunkKey key, std::uint32_t flags, Box3 bounds)
noexcept {
230 TESS_ASSERT(key.value < chunk_count);
231 const auto slot =
static_cast<std::size_t
>(key.value);
232 detail::meta_mark_dirty(dirty_flags_[slot], dirty_bounds_[slot], meta(key),
236 void mark_topology_dirty(ChunkKey key, std::uint32_t flags,
237 Box3 bounds)
noexcept {
241 mark_dirty(key, flags, bounds);
242 ++meta(key).topology_version;
245 void mark_topology_rebuilt(ChunkKey key)
noexcept {
246 ++meta(key).topology_version;
249 void clear_dirty(ChunkKey key, std::uint32_t flags)
noexcept {
250 TESS_ASSERT(key.value < chunk_count);
251 const auto slot =
static_cast<std::size_t
>(key.value);
252 detail::meta_clear_dirty(dirty_flags_[slot], dirty_bounds_[slot], flags);
255 [[nodiscard]]
auto observe_dirty(ChunkKey key,
256 std::uint32_t flags)
const noexcept
257 -> DirtyObservation {
258 TESS_ASSERT(key.value < chunk_count);
259 const auto slot =
static_cast<std::size_t
>(key.value);
260 return detail::meta_observe_dirty(dirty_flags_[slot], dirty_bounds_[slot],
268 bool clear_dirty_observed(ChunkKey key, DirtyObservation observed)
noexcept {
269 TESS_ASSERT(key.value < chunk_count);
270 const auto slot =
static_cast<std::size_t
>(key.value);
271 return detail::meta_clear_dirty_observed(
272 dirty_flags_[slot], dirty_bounds_[slot], meta(key), observed);
275 void mark_active(ChunkKey key, std::uint32_t flags)
noexcept {
276 TESS_ASSERT(key.value < chunk_count);
277 const auto slot =
static_cast<std::size_t
>(key.value);
278 detail::meta_mark_active(active_flags_[slot], meta(key), flags);
281 void clear_active(ChunkKey key, std::uint32_t flags)
noexcept {
282 TESS_ASSERT(key.value < chunk_count);
283 const auto slot =
static_cast<std::size_t
>(key.value);
284 detail::meta_clear_active(active_flags_[slot], meta(key), flags);
294 std::vector<ChunkKey>& out)
const {
295 collect_matching_chunks(flags, dirty_flags_, out);
304 std::vector<ChunkKey>& out)
const {
305 collect_matching_chunks(flags, active_flags_, out);
310 -> std::vector<ChunkKey> {
311 std::vector<ChunkKey>
chunks;
318 -> std::vector<ChunkKey> {
319 std::vector<ChunkKey>
chunks;
330 TESS_ASSERT(contains<Shape>(coord));
331 const auto chunk_coord_value = chunk_coord<Shape>(coord);
333 chunk_key<Shape>(chunk_coord_value),
334 local_tile_id<Shape>(local_coord<Shape>(coord)),
340 -> std::optional<ResolvedTile<Shape>> {
341 if (!contains<Shape>(coord)) {
351 template <
typename Tag>
353 -> Schema::template value_type<Tag>& {
354 const auto resolved =
resolve(coord);
355 return chunk(resolved.chunk_key)
360 template <
typename Tag>
362 ->
const Schema::template value_type<Tag>& {
363 const auto resolved =
resolve(coord);
364 return chunk(resolved.chunk_key)
372 template <
typename Tag>
374 -> Schema::template value_type<Tag>* {
376 if (!resolved.has_value()) {
379 return &
chunk(resolved->chunk_key)
380 .template
field<Tag>(resolved->local_tile_id);
384 template <
typename Tag>
386 ->
const Schema::template value_type<Tag>* {
388 if (!resolved.has_value()) {
391 return &
chunk(resolved->chunk_key)
392 .template
field<Tag>(resolved->local_tile_id);
399 template <
typename Tag>
405 template <
typename Tag>
411 static constexpr bool contains_chunk(
ChunkCoord3 coord)
noexcept {
413 return coord.x < Traits::chunk_count_x && coord.y < Traits::chunk_count_y &&
414 coord.z < Traits::chunk_count_z;
419 void collect_matching_chunks(std::uint32_t flags,
420 const std::vector<std::uint32_t>& column,
421 std::vector<ChunkKey>& out)
const {
422 for (std::uint64_t key = 0; key < chunk_count; ++key) {
423 if ((column[
static_cast<std::size_t
>(key)] & flags) != 0) {
424 out.push_back(ChunkKey{key});
429 std::vector<page_type> pages_;
430 std::vector<ChunkMeta> metadata_;
431 std::vector<std::uint32_t> dirty_flags_;
432 std::vector<std::uint32_t> active_flags_;
433 std::vector<Box3> dirty_bounds_;
Definition chunk_page.h:108