Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ringfilecache.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39
40#include <ringfilecache.H>
41
42#include <atomic>
43#include <chrono>
44#include <cstring>
45#include <filesystem>
46#include <random>
47#include <string>
48#include <vector>
49#if defined(_WIN32)
50# include <process.h>
51#else
52# include <unistd.h>
53#endif
54
55using namespace Aleph;
56using namespace std;
57namespace fs = std::filesystem;
58
59namespace {
60
61struct TempPaths
62{
63 fs::path pars;
64 fs::path cache;
65};
66
68long long process_id() noexcept
69{
70#if defined(_WIN32)
71 return static_cast<long long>(_getpid());
72#else
73 return static_cast<long long>(getpid());
74#endif
75}
76
77TempPaths make_temp_paths()
78{
79 // A steady_clock tick plus a per-process counter is unique *within* a
80 // process, but not across the several processes that actually run
81 // this suite: each TEST() here becomes its own ctest process
82 // (gtest_discover_tests), CI runs ctest with --parallel, and every
83 // process's counter restarts at 0 -- so if two processes' first call
84 // to this function lands in the same clock tick (observed in
85 // practice, not just theoretical), they produce the identical id and
86 // race on the same file. Mixing in the process id closes that gap
87 // regardless of clock resolution.
88 static std::atomic<unsigned long long> counter{0};
89 const auto now = std::chrono::steady_clock::now().time_since_epoch().count();
90 const auto id = std::to_string(now) + "_" + std::to_string(process_id()) +
91 "_" + std::to_string(counter++);
92
93 const fs::path dir = fs::temp_directory_path() / "aleph_ringcache_tests";
94 fs::create_directories(dir);
95 return {dir / (id + ".pars"), dir / (id + ".cache")};
96}
97
98struct TempFiles
99{
100 TempPaths paths;
101 explicit TempFiles(TempPaths p) : paths(std::move(p)) {}
102 ~TempFiles()
103 {
104 std::error_code ec;
105 fs::remove(paths.pars, ec);
106 fs::remove(paths.cache, ec);
107 }
108};
109
110template <typename T>
111std::vector<T> to_vector(const Array<T> &arr)
112{
113 std::vector<T> out;
114 for (size_t i = 0; i < arr.size(); ++i)
115 out.push_back(arr[i]);
116 return out;
117}
118
120{
121 TempFiles tmp(make_temp_paths());
122 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
123 ASSERT_TRUE(RingFileCache<int>::test(tmp.paths.pars.string()));
124
125 RingFileCache<int> cache(tmp.paths.pars.string());
126 EXPECT_TRUE(cache.is_initialized());
127 EXPECT_EQ(cache.capacity(), 4u);
128 EXPECT_EQ(cache.size(), 0u);
129 EXPECT_TRUE(cache.read_all().is_empty());
130
131 EXPECT_TRUE(cache.put(1));
132 EXPECT_TRUE(cache.put(2));
133 EXPECT_TRUE(cache.put(3));
134 EXPECT_TRUE(cache.put(4));
135 EXPECT_FALSE(cache.put(5)); // full
136 EXPECT_EQ(cache.size(), 4u);
137
138 int buf[4] = {0, 0, 0, 0};
139 EXPECT_TRUE(cache.read(buf, 4));
140 EXPECT_EQ(std::vector<int>(buf, buf + 4), std::vector<int>({1, 2, 3, 4}));
141 EXPECT_EQ(cache.read_first(), 1);
142 EXPECT_EQ(cache.read_last(), 4);
143 EXPECT_EQ(cache.oldest(), 1);
144 EXPECT_EQ(cache.oldest(2), 3);
145
146 EXPECT_TRUE(cache.get(2));
147 EXPECT_EQ(cache.size(), 2u);
148 EXPECT_EQ(cache.read_first(), 3);
149 EXPECT_EQ(cache.read_last(), 4);
150 EXPECT_TRUE(cache.get(2));
151 EXPECT_TRUE(cache.is_empty());
152
153 EXPECT_THROW(cache.read_first(), std::underflow_error);
154 EXPECT_THROW(cache.read_last(), std::underflow_error);
155 EXPECT_FALSE(cache.get(1)); // cannot extract if empty
156 EXPECT_FALSE(cache.read(buf, 1)); // cannot read if empty
157}
158
160{
161 TempFiles tmp(make_temp_paths());
162 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 5);
163 RingFileCache<int> cache(tmp.paths.pars.string());
164
165 for (int v : {10, 20, 30, 40})
166 ASSERT_TRUE(cache.put(v));
167
168 auto sub = cache.read_from(1, 2);
169 EXPECT_EQ(to_vector(sub), std::vector<int>({20, 30}));
170
171 RingFileCache<int>::Pointer ptr(cache); // at head (10)
172 ptr += 2; // points to 30
173 auto sub_ptr = cache.read_from(ptr, 3); // should stop at available items
174 EXPECT_EQ(to_vector(sub_ptr), std::vector<int>({30, 40}));
175
176 std::vector<int> iterated;
177 for (auto it = cache.get_it(); it.has_curr(); it.next_ne())
178 iterated.push_back(it.get_curr_ne());
179 EXPECT_EQ(iterated, std::vector<int>({10, 20, 30, 40}));
180}
181
183{
184 TempPaths paths = make_temp_paths();
185 TempFiles tmp(paths);
186 {
187 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 6);
188 RingFileCache<int> cache(tmp.paths.pars.string());
189 for (int v : {1, 2, 3})
190 ASSERT_TRUE(cache.put(v));
191 cache.flush();
192 }
193
194 RingFileCache<int> reopened(tmp.paths.pars.string());
195 EXPECT_EQ(reopened.size(), 3u);
196 EXPECT_EQ(reopened.read_first(), 1);
197 EXPECT_EQ(reopened.read_last(), 3);
198 auto all = reopened.read_all();
199 EXPECT_EQ(to_vector(all), std::vector<int>({1, 2, 3}));
200 reopened.get(2);
201 EXPECT_EQ(reopened.size(), 1u);
202 EXPECT_EQ(reopened.read_first(), 3);
203}
204
206{
207 TempFiles tmp(make_temp_paths());
208 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 2);
209 RingFileCache<int> cache(tmp.paths.pars.string());
210
211 cache.put(7);
212 cache.put(8);
213 EXPECT_EQ(cache.capacity(), 2u);
214 cache.resize(5);
215 EXPECT_EQ(cache.capacity(), 5u);
216 EXPECT_TRUE(cache.put(9));
217 EXPECT_TRUE(cache.put(10));
218 EXPECT_TRUE(cache.put(11));
219
220 auto all = cache.read_all();
221 EXPECT_EQ(to_vector(all), std::vector<int>({7, 8, 9, 10, 11}));
222}
223
225{
226 TempFiles tmp(make_temp_paths());
227 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 3);
228 RingFileCache<int> cache(tmp.paths.pars.string());
229
230 auto all = cache.read_all();
231 EXPECT_TRUE(all.is_empty());
232}
233
235{
236 TempFiles tmp(make_temp_paths());
237 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 3);
238 RingFileCache<int> cache(tmp.paths.pars.string());
239
240 cache.put(1);
241 cache.put(2);
242 cache.put(3);
243
244 RingFileCache<int>::Pointer ptr(cache); // at head
245 EXPECT_EQ(ptr.get_pos_respect_to_head(), 0u);
246
247 auto first_two = cache.read_from(ptr, 2);
248 EXPECT_EQ(to_vector(first_two), std::vector<int>({1, 2}));
249
250 ptr += 1;
251 EXPECT_EQ(ptr.get_pos_respect_to_head(), 1u);
252
253 ptr += 5; // wraps around dimension 3
254 EXPECT_EQ(ptr.get_pos_respect_to_head(), 0u);
255
256 cache.get(2); // remove 1 and 2
257 cache.put(4);
258 cache.put(5);
259
260 RingFileCache<int>::Pointer head_ptr(cache);
261 auto wrapped = cache.read_from(head_ptr, 3);
262 EXPECT_EQ(to_vector(wrapped), std::vector<int>({3, 4, 5}));
263
264 std::vector<int> iterated;
265 for (auto it = cache.get_it(); it.has_curr(); it.next_ne())
266 iterated.push_back(it.get_curr_ne());
267 EXPECT_EQ(iterated, std::vector<int>({3, 4, 5}));
268}
269
271{
272 TempPaths paths = make_temp_paths();
273 TempFiles tmp(paths);
274
275 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
276 RingFileCache<int> cache;
277 cache.init(tmp.paths.pars.string());
279 cache.put(42);
280 cache.close();
281 cache.close(); // should be a no-op
282
283 RingFileCache<int> reopened(tmp.paths.pars.string());
284 EXPECT_EQ(reopened.size(), 1u);
285 EXPECT_EQ(reopened.read_first(), 42);
286}
287
289{
290 TempFiles tmp(make_temp_paths());
291 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 3);
292 RingFileCache<int> cache(tmp.paths.pars.string());
293
294 EXPECT_FALSE(cache.is_full());
295 EXPECT_TRUE(cache.is_empty());
296
297 cache.put(1);
298 EXPECT_FALSE(cache.is_full());
299 EXPECT_FALSE(cache.is_empty());
300
301 cache.put(2);
302 cache.put(3);
303 EXPECT_TRUE(cache.is_full());
304 EXPECT_FALSE(cache.is_empty());
305
306 cache.get(1);
307 EXPECT_FALSE(cache.is_full());
308}
309
311{
312 TempFiles tmp(make_temp_paths());
313 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
314 RingFileCache<int> cache(tmp.paths.pars.string());
315
316 // Fill, empty, refill multiple cycles to stress wraparound
317 for (int cycle = 0; cycle < 5; ++cycle)
318 {
319 // Fill completely
320 for (int i = 0; i < 4; ++i)
321 ASSERT_TRUE(cache.put(cycle * 10 + i));
322 EXPECT_TRUE(cache.is_full());
323
324 // Verify contents
325 for (int i = 0; i < 4; ++i)
326 EXPECT_EQ(cache.oldest(i), cycle * 10 + i);
327
328 // Empty completely
329 EXPECT_TRUE(cache.get(4));
330 EXPECT_TRUE(cache.is_empty());
331 }
332
333 // Partial fill/empty cycles
334 for (int cycle = 0; cycle < 10; ++cycle)
335 {
336 cache.put(cycle);
337 cache.put(cycle + 100);
338 EXPECT_EQ(cache.size(), 2u);
339 EXPECT_EQ(cache.read_first(), cycle);
340 EXPECT_EQ(cache.read_last(), cycle + 100);
341 cache.get(2);
342 }
343}
344
346{
347 TempFiles tmp(make_temp_paths());
348 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
349 RingFileCache<int> cache(tmp.paths.pars.string());
350
351 // Create wraparound: fill, remove some, add more
352 cache.put(1);
353 cache.put(2);
354 cache.put(3);
355 cache.put(4);
356 cache.get(2); // remove 1, 2 -> head moves forward
357 cache.put(5);
358 cache.put(6); // now data wraps: [5, 6, 3, 4] with head at index 2
359
360 EXPECT_EQ(cache.size(), 4u);
361 auto before = cache.read_all();
362 EXPECT_EQ(to_vector(before), std::vector<int>({3, 4, 5, 6}));
363
364 // Resize while wrapped
365 cache.resize(8);
366 EXPECT_EQ(cache.capacity(), 8u);
367 EXPECT_EQ(cache.size(), 4u);
368
369 // Data should still be correct after resize
370 auto after = cache.read_all();
371 EXPECT_EQ(to_vector(after), std::vector<int>({3, 4, 5, 6}));
372
373 // Can add more now
374 EXPECT_TRUE(cache.put(7));
375 EXPECT_TRUE(cache.put(8));
376 EXPECT_TRUE(cache.put(9));
377 EXPECT_TRUE(cache.put(10));
378 EXPECT_EQ(cache.size(), 8u);
379 EXPECT_TRUE(cache.is_full());
380}
381
383{
384 TempFiles tmp(make_temp_paths());
385 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
386 RingFileCache<int> cache(tmp.paths.pars.string());
387
388 // Resize empty cache
389 cache.resize(6);
390 EXPECT_EQ(cache.capacity(), 6u);
391 EXPECT_EQ(cache.size(), 0u);
392
393 // Resize to same size should be no-op (but allowed)
394 cache.put(1);
395 cache.resize(6);
396 EXPECT_EQ(cache.capacity(), 6u);
397 EXPECT_EQ(cache.size(), 1u);
398 EXPECT_EQ(cache.read_first(), 1);
399}
400
402{
403 TempFiles tmp(make_temp_paths());
404 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 3);
405 RingFileCache<int> cache(tmp.paths.pars.string());
406
407 cache.put(1);
408 cache.put(2);
409
410 auto it = cache.get_it();
411 EXPECT_TRUE(it.has_curr());
412 EXPECT_EQ(it.get_curr(), 1);
413 it.next();
414 EXPECT_EQ(it.get_curr(), 2);
415 it.next();
416 EXPECT_FALSE(it.has_curr());
417
418 // get_curr() should throw when exhausted
419 EXPECT_THROW(it.get_curr(), std::overflow_error);
420 // next() should throw when exhausted
421 EXPECT_THROW(it.next(), std::overflow_error);
422}
423
425{
426 TempFiles tmp(make_temp_paths());
427 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 5);
428 RingFileCache<int> cache(tmp.paths.pars.string());
429
430 cache.put(10);
431 cache.put(20);
432 cache.put(30);
433
434 EXPECT_EQ(cache.oldest(0), 10);
435 EXPECT_EQ(cache.oldest(1), 20);
436 EXPECT_EQ(cache.oldest(2), 30);
437
438 // Out of bounds should throw
439 EXPECT_THROW(cache.oldest(3), std::overflow_error);
440 EXPECT_THROW(cache.oldest(100), std::overflow_error);
441}
442
444{
445 TempFiles tmp(make_temp_paths());
446 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
447
448 RingFileCache<int> cache;
449 cache.init(tmp.paths.pars.string());
451
452 // Second init should throw
453 EXPECT_THROW(cache.init(tmp.paths.pars.string()), std::domain_error);
454}
455
457{
458 TempFiles tmp(make_temp_paths());
459 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 5);
460 RingFileCache<int> cache(tmp.paths.pars.string());
461
462 for (int i = 0; i < 5; ++i)
463 cache.put(i * 10);
464
465 RingFileCache<int>::Pointer ptr(cache, 2); // points to entry with value 20
466 EXPECT_EQ(cache.read(ptr), 20);
467
468 ptr -= 1;
469 EXPECT_EQ(cache.read(ptr), 10);
470
471 ptr -= 1;
472 EXPECT_EQ(cache.read(ptr), 0);
473
474 // Wraparound backward
475 ptr -= 1;
476 EXPECT_EQ(cache.read(ptr), 40); // wraps to last entry
477
478 ptr -= 2;
479 EXPECT_EQ(cache.read(ptr), 20);
480
481 // Large negative offset
482 ptr -= 7; // 7 % 5 = 2 steps back from 20 -> 0
483 EXPECT_EQ(cache.read(ptr), 0);
484}
485
487{
488 TempFiles tmp(make_temp_paths());
489 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
490 RingFileCache<int> cache(tmp.paths.pars.string());
491
492 for (int i = 0; i < 4; ++i)
493 cache.put(i);
494
495 RingFileCache<int>::Pointer ptr(cache, 2); // at value 2
496 EXPECT_EQ(cache.read(ptr), 2);
497
498 auto ptr2 = ptr + (-1); // should go back 1
499 EXPECT_EQ(cache.read(ptr2), 1);
500
501 ptr2 = ptr + (-3); // should wrap to value 3
502 EXPECT_EQ(cache.read(ptr2), 3);
503}
504
505// Test with a non-int trivially copyable type
506struct TestRecord
507{
508 int id;
509 double value;
510 char tag[8];
511
512 bool operator==(const TestRecord &other) const
513 {
514 return id == other.id && value == other.value &&
515 std::strncmp(tag, other.tag, 8) == 0;
516 }
517};
518
520{
521 TempFiles tmp(make_temp_paths());
522 RingFileCache<TestRecord>::create(tmp.paths.pars.string(),
523 tmp.paths.cache.string(), 3);
524 RingFileCache<TestRecord> cache(tmp.paths.pars.string());
525
526 TestRecord r1{1, 3.14, "alpha"};
527 TestRecord r2{2, 2.71, "beta"};
528 TestRecord r3{3, 1.41, "gamma"};
529
530 EXPECT_TRUE(cache.put(r1));
531 EXPECT_TRUE(cache.put(r2));
532 EXPECT_TRUE(cache.put(r3));
533 EXPECT_TRUE(cache.is_full());
534
535 EXPECT_EQ(cache.read_first(), r1);
536 EXPECT_EQ(cache.read_last(), r3);
537 EXPECT_EQ(cache.oldest(1), r2);
538
539 cache.get(1);
540 EXPECT_EQ(cache.read_first(), r2);
541}
542
544{
545 TempFiles tmp(make_temp_paths());
546 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 5);
547 RingFileCache<int> cache(tmp.paths.pars.string());
548
549 EXPECT_TRUE(cache.is_empty());
550 EXPECT_FALSE(cache.is_full());
551 EXPECT_EQ(cache.size(), 0u);
552 EXPECT_EQ(cache.avail(), 5u);
553
554 // These should return false, not throw
555 EXPECT_FALSE(cache.get(1));
556 int buf[1];
557 EXPECT_FALSE(cache.read(buf, 1));
558
559 // read_all on empty returns empty array
560 auto all = cache.read_all();
561 EXPECT_TRUE(all.is_empty());
562
563 // Iterator on empty cache
564 auto it = cache.get_it();
565 EXPECT_FALSE(it.has_curr());
566}
567
569{
570 TempFiles tmp(make_temp_paths());
571 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 10);
572 RingFileCache<int> cache(tmp.paths.pars.string());
573
574 cache.put(1);
575 cache.put(2);
576 cache.put(3);
577
578 // read_from with pos beyond size should return partial or empty
579 auto result = cache.read_from(5, 3); // pos=5 but only 3 items exist
580 EXPECT_TRUE(result.is_empty());
581
582 // read_from with large m should stop at available items
583 auto result2 = cache.read_from(1, 100); // start at 1, request 100, only 2 available
584 EXPECT_EQ(to_vector(result2), std::vector<int>({2, 3}));
585}
586
588{
589 TempPaths paths = make_temp_paths();
590 TempFiles tmp(paths);
591
592 {
593 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 4);
594 RingFileCache<int> cache(tmp.paths.pars.string());
595
596 // Create wraparound state
597 cache.put(1);
598 cache.put(2);
599 cache.put(3);
600 cache.put(4);
601 cache.get(2); // remove 1, 2
602 cache.put(5);
603 cache.put(6);
604 // State: [5, 6, 3, 4] with head at 2
605
606 cache.flush();
607 }
608
609 // Reopen and verify wraparound state persisted correctly
610 RingFileCache<int> reopened(tmp.paths.pars.string());
611 EXPECT_EQ(reopened.size(), 4u);
612 auto all = reopened.read_all();
613 EXPECT_EQ(to_vector(all), std::vector<int>({3, 4, 5, 6}));
614}
615
617{
618 TempFiles tmp(make_temp_paths());
619 RingFileCache<int>::create(tmp.paths.pars.string(), tmp.paths.cache.string(), 5);
620 RingFileCache<int> cache(tmp.paths.pars.string());
621
622 // Test 1: clear on populated cache
623 cache.put(10);
624 cache.put(20);
625 cache.put(30);
626 EXPECT_EQ(cache.size(), 3u);
627 EXPECT_FALSE(cache.is_empty());
628
629 cache.clear(); // Exercises clear()
630 EXPECT_EQ(cache.size(), 0u);
631 EXPECT_TRUE(cache.is_empty());
632 EXPECT_TRUE(cache.read_all().is_empty());
633
634 // Test 2: empty on populated cache (for comparison)
635 cache.put(40);
636 cache.put(50);
637 EXPECT_EQ(cache.size(), 2u);
638 cache.empty(); // Exercises empty()
639 EXPECT_EQ(cache.size(), 0u);
640 EXPECT_TRUE(cache.is_empty());
641
642 // Test 3: clear on already-empty cache (no-op)
643 EXPECT_TRUE(cache.is_empty());
644 cache.clear();
645 EXPECT_EQ(cache.size(), 0u);
646 EXPECT_TRUE(cache.is_empty());
647
648 // Test 4: empty on already-empty cache (no-op)
649 cache.empty();
650 EXPECT_EQ(cache.size(), 0u);
651 EXPECT_TRUE(cache.is_empty());
652}
653
654} // namespace
bool operator==(const Time &l, const Time &r)
Definition ah-time.H:133
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
Defines a pointer to a specific location in the cache.
Persistent ring buffer cache with file-backed storage.
T read(const Pointer &ptr)
Read the entry pointed to by ptr
T read_first()
Read the oldest entry in the cache.
Array< T > read_all()
Read all entries in insertion order.
bool is_empty() const noexcept
Returns true if the cache is empty.
Iterator get_it()
Returns a forward iterator starting at the oldest entry.
void clear() noexcept
Removes all entries from the cache.
bool put(const T &item)
Insert an item into the cache.
void init(const std::string &pars_fname)
Initialize a cache constructed with the default constructor.
size_t size() const noexcept
Returns the number of entries stored in the cache.
void empty() noexcept
Empties the cache; all entries are logically deleted.
size_t capacity() const noexcept
Returns the maximum capacity.
bool is_full() const noexcept
Returns true if the cache is full (no more entries can be inserted)
bool is_initialized() const
True if the cache has been initialized with a valid parameters file.
Array< T > read_from(const size_t pos, const size_t m)
Read up to m entries starting from the pos-th oldest position.
bool get(const size_t m=1) noexcept
Extracts (deletes) from the cache the m oldest inserted items.
void flush()
Flushes the current cache state to disk.
void close()
Flushes state and closes the underlying streams.
static void create(const std::string &pars_file_name, const std::string &cache_file_name, const size_t num_entries)
Create a brand new on-disk ring cache.
void resize(const size_t sz)
Resize the maximum capacity of the cache.
size_t avail() const noexcept
Returns the number of available entries.
T oldest()
Alias for read_first().
T read_last()
Read the youngest (most recently inserted) entry in the cache.
#define TEST(name)
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
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
std::vector< typename C::Item_Type > to_vector(const C &c)
Convert a container to a std::vector.
Definition ah-convert.H:238
double sub(double a, double b)
STL namespace.
File-backed ring buffer cache for persistent storage.
static long counter
Definition test-splice.C:40