#pragma once
|
|
#include <vector>
|
|
#include <array>
|
|
|
|
template<typename T, size_t chunk_size = 16>
|
|
struct cube {
|
|
struct chunk_elem_t {
|
|
size_t coord;
|
|
T elem;
|
|
};
|
|
|
|
struct chunk_t {
|
|
std::array<std::array<std::vector<chunk_elem_t>, chunk_size>, chunk_size> data;
|
|
};
|
|
|
|
struct row_t {
|
|
size_t coord;
|
|
std::shared_ptr<chunk_t> value;
|
|
};
|
|
|
|
struct column_t {
|
|
size_t coord;
|
|
std::vector<row_t> value;
|
|
};
|
|
|
|
std::vector<column_t> chunks;
|
|
|
|
std::optional<T> at(size_t x, size_t y, size_t z) {
|
|
auto column = std::ranges::find_if(chunks, [&](const column_t& col) {
|
|
return col.coord == y/chunk_size;
|
|
});
|
|
if(column == chunks.end()) return std::nullopt;
|
|
auto row = std::ranges::find_if(column->value, [&](const row_t& row) {
|
|
return row.coord == x/chunk_size;
|
|
});
|
|
if(column->value.end() == row) return std::nullopt;
|
|
auto& chunk_segment = row->value->data.at(x%chunk_size).at(y%chunk_size);
|
|
auto position = std::ranges::find_if(chunk_segment, [&](const chunk_elem_t& item) {
|
|
return item.coord == z;
|
|
});
|
|
if(position == chunk_segment.end()) return std::nullopt;
|
|
return position->elem;
|
|
}
|
|
|
|
void set(size_t x, size_t y, size_t z, T&& value) {
|
|
auto column = std::ranges::find_if(chunks, [&](const column_t& col) {
|
|
return col.coord == y/chunk_size;
|
|
});
|
|
if(column == chunks.end()) {
|
|
auto chunk = std::make_shared<chunk_t>();
|
|
chunks.push_back(column_t{
|
|
.coord = y / chunk_size,
|
|
.value = {
|
|
row_t{
|
|
.coord = x/chunk_size,
|
|
.value = chunk
|
|
}
|
|
}
|
|
});
|
|
chunk->data.at(x%chunk_size).at(y%chunk_size).push_back(chunk_elem_t{
|
|
.coord = z,
|
|
.elem = std::move(value)
|
|
});
|
|
return;
|
|
}
|
|
auto row = std::ranges::find_if(column->value, [&](const row_t& row) {
|
|
return row.coord == x/chunk_size;
|
|
});
|
|
if(column->value.end() == row) {
|
|
auto chunk = std::make_shared<chunk_t>();
|
|
column->value.push_back(
|
|
row_t{
|
|
.coord = x/chunk_size,
|
|
.value = chunk
|
|
}
|
|
);
|
|
chunk->data.at(x%chunk_size).at(y%chunk_size).push_back(chunk_elem_t{
|
|
.coord = z,
|
|
.elem = std::move(value)
|
|
});
|
|
return;
|
|
}
|
|
auto& chunk_segment = row->value->data.at(x%chunk_size).at(y%chunk_size);
|
|
auto position = std::ranges::find_if(chunk_segment, [&](const chunk_elem_t& item) {
|
|
return item.coord == z;
|
|
});
|
|
if(position == chunk_segment.end()) {
|
|
chunk_segment.push_back(chunk_elem_t{
|
|
.coord = z,
|
|
.elem = std::move(value)
|
|
});
|
|
return;
|
|
}
|
|
position->elem = std::move(value);
|
|
}
|
|
};
|