Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca-streaming-storage.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
71#ifndef CA_STREAMING_STORAGE_H
72#define CA_STREAMING_STORAGE_H
73
74#include <array>
75#include <cstddef>
76#include <cstdint>
77#include <cstring>
78#include <filesystem>
79#include <fstream>
80#include <list>
81#include <string>
82#include <type_traits>
83#include <unordered_map>
84#include <utility>
85#include <vector>
86
87#include <ah-errors.H>
88
89#include <ca-traits.H>
90
91namespace Aleph {
92namespace CA {
93
94namespace ca_stream_detail {
95
97[[nodiscard]] inline constexpr std::uint64_t tile_key(const std::uint32_t row,
98 const std::uint32_t col) noexcept
99{
100 return (static_cast<std::uint64_t>(row) << 32) | static_cast<std::uint64_t>(col);
101}
102
103} // namespace ca_stream_detail
104
113{
114 std::uint64_t hits = 0;
115 std::uint64_t misses = 0;
116 std::uint64_t evictions = 0;
117 std::uint64_t writes = 0;
118 std::uint64_t reads = 0;
119};
120
132template <typename State, std::size_t TileSide>
134{
135 static_assert(std::is_trivially_copyable_v<State>,
136 "Tile_Cache requires a trivially copyable State");
137 static_assert(TileSide >= 1, "Tile_Cache requires TileSide >= 1");
138
139public:
141 using state_type = State;
143 static constexpr std::size_t tile_side = TileSide;
145 static constexpr std::size_t tile_cells = TileSide * TileSide;
146
147private:
148 using tile_buffer = std::array<State, tile_cells>;
149
151 {
152 std::uint32_t row;
153 std::uint32_t col;
155 bool dirty = false;
156 };
157
158 using lru_list = std::list<Tile_Entry>;
159 using lru_iter = typename lru_list::iterator;
160 using key_map = std::unordered_map<std::uint64_t, lru_iter>;
161
166 std::filesystem::path dir_;
167 std::size_t capacity_ = 0;
171
172 [[nodiscard]] std::filesystem::path tile_path(std::uint32_t row, std::uint32_t col) const
173 {
174 return dir_
175 / ("tile_" + std::to_string(row) + "_" + std::to_string(col) + ".bin");
176 }
177
180 void read_tile_from_disk(std::uint32_t row, std::uint32_t col, tile_buffer &buf)
181 {
182 const auto path = tile_path(row, col);
183 if (not std::filesystem::exists(path))
184 {
185 buf.fill(State{});
186 return;
187 }
188 std::ifstream in(path, std::ios::binary);
190 << "Tile_Cache: cannot read tile (" << row << "," << col << ") from '"
191 << path.string() << "'";
192 in.read(reinterpret_cast<char *>(buf.data()),
193 static_cast<std::streamsize>(tile_cells * sizeof(State)));
194 ah_runtime_error_if(in.gcount() != static_cast<std::streamsize>(tile_cells * sizeof(State)))
195 << "Tile_Cache: short read of tile (" << row << "," << col << ")";
196 ++stats_.reads;
197 }
198
201 {
202 const auto path = tile_path(entry.row, entry.col);
203 std::ofstream out(path, std::ios::binary | std::ios::trunc);
205 << "Tile_Cache: cannot write tile (" << entry.row << "," << entry.col
206 << ") to '" << path.string() << "'";
207 out.write(reinterpret_cast<const char *>(entry.data.data()),
208 static_cast<std::streamsize>(tile_cells * sizeof(State)));
210 << "Tile_Cache: stream error while writing tile (" << entry.row << ","
211 << entry.col << ")";
212 ++stats_.writes;
213 }
214
217 {
218 if (it != cache_.begin())
219 cache_.splice(cache_.begin(), cache_, it);
220 }
221
223 lru_iter page_in(std::uint32_t row, std::uint32_t col)
224 {
225 if (cache_.size() >= capacity_)
226 {
227 Tile_Entry &victim = cache_.back();
228 if (victim.dirty)
231 cache_.pop_back();
233 }
234 Tile_Entry entry;
235 entry.row = row;
236 entry.col = col;
238 cache_.push_front(std::move(entry));
239 const auto it = cache_.begin();
241 return it;
242 }
243
246 {
247 const std::uint32_t tr = static_cast<std::uint32_t>(r / TileSide);
248 const std::uint32_t tc = static_cast<std::uint32_t>(c / TileSide);
249 const auto key = ca_stream_detail::tile_key(tr, tc);
250 if (auto map_it = index_.find(key); map_it != index_.end())
251 {
252 ++stats_.hits;
253 touch(map_it->second);
254 return map_it->second;
255 }
256 ++stats_.misses;
257 return page_in(tr, tc);
258 }
259
260 static std::size_t local_index(ca_size_t r, ca_size_t c) noexcept
261 {
262 const std::size_t lr = r % TileSide;
263 const std::size_t lc = c % TileSide;
264 return lr * TileSide + lc;
265 }
266
267public:
282 Tile_Cache(const std::array<ca_size_t, 2> &extents,
283 std::filesystem::path dir,
284 const std::size_t capacity)
285 : rows_(extents[0]), cols_(extents[1]), dir_(std::move(dir)), capacity_(capacity)
286 {
288 << "Tile_Cache: capacity must be >= 1";
290 << "Tile_Cache: extents must be positive";
292 << "Tile_Cache: extents (" << rows_ << "," << cols_
293 << ") must be multiples of TileSide=" << TileSide;
296 if (not std::filesystem::exists(dir_))
297 std::filesystem::create_directories(dir_);
298 }
299
301 [[nodiscard]] std::array<ca_size_t, 2> extents() const noexcept
302 {
303 return {rows_, cols_};
304 }
305
311 [[nodiscard]] std::size_t capacity() const noexcept { return capacity_; }
313 [[nodiscard]] std::size_t resident() const noexcept { return cache_.size(); }
316
328 {
330 << "Tile_Cache::at: (" << r << "," << c << ") outside ("
331 << rows_ << "," << cols_ << ")";
332 auto it = resolve(r, c);
333 return it->data[local_index(r, c)];
334 }
335
343 void set(ca_size_t r, ca_size_t c, const State &v)
344 {
346 << "Tile_Cache::set: (" << r << "," << c << ") outside ("
347 << rows_ << "," << cols_ << ")";
348 auto it = resolve(r, c);
349 it->data[local_index(r, c)] = v;
350 it->dirty = true;
351 }
352
362 void flush()
363 {
364 for (auto &entry : cache_)
365 if (entry.dirty)
366 {
367 write_tile_to_disk(entry);
368 entry.dirty = false;
369 }
370 }
371};
372
373} // namespace CA
374} // namespace Aleph
375
376#endif // CA_STREAMING_STORAGE_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t row
Definition ca-c-api.h:115
size_t size_t col
Definition ca-c-api.h:116
Common typedefs and tag types for the Cellular Automata module.
Out-of-core 2D tile cache with LRU eviction.
typename lru_list::iterator lru_iter
static std::size_t local_index(ca_size_t r, ca_size_t c) noexcept
std::list< Tile_Entry > lru_list
void touch(lru_iter it)
Move it to the front of the LRU list (mark as most-recent).
std::size_t capacity() const noexcept
lru_iter resolve(ca_size_t r, ca_size_t c)
Locate the tile that owns (r, c), paging it in if absent.
std::array< State, tile_cells > tile_buffer
std::array< ca_size_t, 2 > extents() const noexcept
static constexpr std::size_t tile_cells
Number of cells per tile.
std::filesystem::path tile_path(std::uint32_t row, std::uint32_t col) const
std::filesystem::path dir_
ca_size_t tiles_cols() const noexcept
State state_type
Cell value type.
std::unordered_map< std::uint64_t, lru_iter > key_map
Tile_Cache_Stats stats() const noexcept
void write_tile_to_disk(const Tile_Entry &entry)
Persist tile to disk.
Tile_Cache(const std::array< ca_size_t, 2 > &extents, std::filesystem::path dir, const std::size_t capacity)
Build a tile cache.
static constexpr std::size_t tile_side
Tile side length (in cells).
State at(ca_size_t r, ca_size_t c)
Read the cell at (r, c).
std::size_t resident() const noexcept
ca_size_t tiles_rows() const noexcept
void read_tile_from_disk(std::uint32_t row, std::uint32_t col, tile_buffer &buf)
Read tile from disk into buf.
void flush()
Persist every dirty resident tile to disk and clear the dirty flag.
void set(ca_size_t r, ca_size_t c, const State &v)
Write the cell at (r, c) and mark its tile dirty.
lru_iter page_in(std::uint32_t row, std::uint32_t col)
Page a tile in, evicting the LRU when full.
Shape (per-axis sizes) of an mdspan, mixing compile-time and run-time extents.
Definition ah-mdspan.H:303
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
constexpr std::uint64_t tile_key(const std::uint32_t row, const std::uint32_t col) noexcept
Pack (row, col) into a stable 64-bit key for the tile map.
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
STL namespace.
bool dirty
std::uint32_t col
tile_buffer data
std::uint32_t row
Statistics surfaced by Tile_Cache::stats().
std::uint64_t misses
accesses that paged a tile in
std::uint64_t reads
tile reads from disk (load on miss)
std::uint64_t hits
accesses served from RAM
std::uint64_t evictions
tiles evicted to disk to make room
std::uint64_t writes
tile writes to disk (eviction or flush)
gsl_rng * r