77# ifndef RINGFILECACHE_H
78# define RINGFILECACHE_H
90# include <type_traits>
133 static_assert(std::is_trivially_copyable<T>::value,
134 "RingFileCache requires trivially copyable types");
135 static_assert(std::is_default_constructible<T>::value,
136 "T must be default constructible");
150 std::ostringstream s;
151 s <<
dim <<
" " <<
n <<
" " <<
tail <<
" " <<
head <<
" "
216 <<
"read_entry(" << pos <<
"): cache has " <<
n <<
" items";
229 cache_stream.write(
reinterpret_cast<const char *
>(&item),
sizeof item);
256 cache_stream.write(
reinterpret_cast<const char *
>(&item),
sizeof item);
265 std::ostringstream s;
266 s <<
"Cache pars" << std::endl
267 <<
"capacity = " <<
capacity() << std::endl
268 <<
"size = " <<
size() << std::endl
269 <<
"sizeof T = " <<
sizeof(
T) << std::endl
270 <<
"head pos = " <<
head_pos() << std::endl
271 <<
"tail pos = " <<
tail_pos() << std::endl
272 <<
"tellg/T = " <<
tg << std::endl
273 <<
"tellp/T = " << tp << std::endl;
307 std::ostringstream s;
341 std::ostringstream s;
342 const auto state =
ss.rdstate();
343 if (
state & std::ios::goodbit)
344 s <<
" goodbit = true " << std::endl;
346 s <<
" goodbit = false " << std::endl;
347 if (
state & std::ios::badbit)
348 s <<
" badbit = true " << std::endl;
350 s <<
" badbit = false " << std::endl;
351 if (
state & std::ios::failbit)
352 s <<
" failbit = true " << std::endl;
354 s <<
" failbit = false " << std::endl;
355 if (
state & std::ios::eofbit)
356 s <<
" eofbit = true " << std::endl;
358 s <<
" eofbit = false " << std::endl;
372 pars_stream.read(
reinterpret_cast<char *
>(&pars),
sizeof pars);
417 std::ostringstream s;
418 s <<
"position " <<
pos <<
" is outside of maximum " <<
cache_ptr->
dim;
431 pos = (
pos +
static_cast<size_t>(delta)) %
dim;
443 if (
const size_t decr =
static_cast<size_t>(delta) %
dim;
pos >=
decr)
541 <<
"RingFileCache::read(const Pointer&): invalid ptr";
550 <<
"RingFileCache::write(const Pointer&): invalid ptr";
649 <<
"this cache has already an opened pars file";
712 bool read(
T entries[],
const size_t m = 1)
724 cache_stream.read(
reinterpret_cast<char *
>(entries), m *
sizeof(
T));
795 <<
"oldest(" << i <<
") but the cache has " <<
n <<
" entries";
885 pars_stream.write(
reinterpret_cast<const char *
>(&pars),
sizeof(pars));
921 <<
"RingFileCache::resize(): file truncation is not implemented (yet?)";
949 for (
size_t pos =
fill_start; pos < sz; ++pos)
1029 <<
"RingFileCache::Iterator::get_curr(): iterator exhausted";
1048 <<
"RingFileCache::Iterator::next(): iterator exhausted";
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.
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
#define ah_bad_alloc_if(C)
Throws std::bad_alloc if condition holds.
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
#define ah_out_of_range_error()
Throws std::out_of_range unconditionally.
Simple dynamic array with automatic resizing and functional operations.
T & append(const T &item)
Append a new item by copy.
size_t size() const noexcept
Count the number of elements of the list.
LocateFunctions< Container, Type > * base() const
Iterator(const RingFileCache< T > &cache, const size_t offset=0)
Construct an iterator positioned offset entries forward from the oldest cache entry.
RingFileCache< T > * cache_ptr
T get_curr_ne() const noexcept
Return the current element (no bounds check). Undefined if exhausted.
bool has_curr() const
True if the iterator currently refers to a valid element.
void next()
Advance to the next element.
size_t get_pos() const noexcept
Logical offset from the head (number of elements already visited)
T get_curr() const
Return the current element.
void next_ne() noexcept
Advance to the next element without checking bounds. Safe to call when exhausted.
Defines a pointer to a specific location in the cache.
size_t get_pos() const noexcept
Alias of get_pos_respect_to_head()
RingFileCache * cache_ptr
Pointer operator--() noexcept
Prefix decrement: move back one position (with wraparound)
Pointer operator++() noexcept
Prefix increment: advance one position (with wraparound)
Pointer & operator-=(const long val) noexcept
Move back by val positions (with wraparound)
size_t get_pos_respect_to_head() const noexcept
Offset of this pointer relative to the current head of the cache.
void decrease_pos(const long delta=1) noexcept
Pointer(const RingFileCache &cache, const size_t __pos=0)
Construct a pointer to the current head (oldest item in the cache)
void validate_position(const size_t pos) const
Pointer operator+(const long val) const noexcept
Return a new Pointer advanced by val positions.
void increase_pos(const long delta=1) noexcept
Pointer & operator+=(const long val) noexcept
Advance by val positions (with wraparound)
Pointer operator-(const long val) const noexcept
Return a new Pointer moved back by val positions.
Persistent ring buffer cache with file-backed storage.
T read(const Pointer &ptr)
Read the entry pointed to by ptr
std::string pars_file_name
T oldest(size_t i)
Read the i-th oldest element without removing it.
T read_first()
Read the oldest entry in the cache.
RingFileCache(const std::string &pars_fname)
Initialize a cache previously built.
Array< T > read_all()
Read all entries in insertion order.
bool is_empty() const noexcept
Returns true if the cache is empty.
Array< T > read_from(const Pointer &ptr, const size_t m)
Read up to m entries starting from the position designated by ptr.
Iterator get_it()
Returns a forward iterator starting at the oldest entry.
void test_and_set_head_pointer(const size_t num_entries=0)
Position the read pointer at head + num_entries (with wraparound)
T read_entry(const size_t pos)
Read the entry at logical position pos from head (with bounds check)
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 test_and_set_tail_pointer()
Position the writing pointer at the current tail.
void empty() noexcept
Empties the cache; all entries are logically deleted.
size_t capacity() const noexcept
Returns the maximum capacity.
RingFileCache()=default
Default constructor.
bool is_full() const noexcept
Returns true if the cache is full (no more entries can be inserted)
std::fstream cache_stream
bool is_initialized() const
True if the cache has been initialized with a valid parameters file.
T read_entry()
Load an entry from the current stream position. WARNING: stream pointer not set here.
T youngest()
Alias for read_last().
bool read(T entries[], const size_t m=1)
Read the m the oldest entries and load them in a contiguous array.
static std::string state(std::fstream &ss)
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.
std::string to_string() const
Human-readable dump of the cache internal state (debugging)
void flush()
Flushes the current cache state to disk.
bool is_valid_offset(const size_t offset) const noexcept
True if offset is a valid logical offset from the head (0 <= offset < n)
void close()
Flushes state and closes the underlying streams.
size_t head_pos() const noexcept
Returns the current head position.
std::string cache_file_name
bool is_valid_position(const size_t pos) const noexcept
True if pos is a valid absolute position within the stored entries.
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 validate_absolute_position(const size_t pos) const
Throw out_of_range if pos >= dim.
T read_absolute(const size_t pos)
Read entry at absolute file position (with bounds check)
static bool test(const std::string &pars_fname)
Tests if pars and cache files have been created.
void resize(const size_t sz)
Resize the maximum capacity of the cache.
size_t avail() const noexcept
Returns the number of available entries.
void read_pars(const std::string &pars_file_name)
void write(const Pointer &ptr, const T &item)
Write item at an absolute position designated by ptr.
friend std::ostream & operator<<(std::ostream &out, const RingFileCache &cache)
T oldest()
Alias for read_first().
void write_entry(const T &item)
Write an entry at the current stream position.
size_t tail_pos() const noexcept
return the current tail position
void write_absolute(const size_t pos, const T &item)
Write entry at absolute file position (with bounds check)
T read_last()
Read the youngest (most recently inserted) entry in the cache.
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
std::decay_t< typename HeadC::Item_Type > T
DynList< T > maps(const C &c, Op op)
Classic map operation.
constexpr size_t Ring_Max_Name_Size
Maximum length for cache filename in parameter file.
friend std::ostream & operator<<(std::ostream &out, const Pars &pars)
std::string to_string() const
Dynamic array container with automatic resizing.