27 # ifndef RINGFILECACHE_H 28 # define RINGFILECACHE_H 30 # include <sys/time.h> 40 # include <tpl_array.H> 44 extern const size_t Ring_Max_Name_Size;
62 size_t size_cache_file = 0;
63 char cache_file_name[0];
65 string to_string()
const 68 s <<dim <<
" " << n <<
" " << tail <<
" " << head <<
" " 73 friend ostream & operator << (ostream & out,
const Pars & pars)
75 return out << pars.to_string();
81 bool initialized =
false;
82 string pars_file_name;
83 string cache_file_name;
93 void test_and_set_tail_pointer()
95 cache_stream.seekp(tail*
sizeof(T));
98 bool is_valid_offset(
const size_t offset)
const noexcept
103 bool is_valid_position(
const size_t pos)
const noexcept
105 return pos >= head and pos < tail;
108 void test_and_set_head_pointer(
const size_t num_entries = 0)
110 const size_t pos = (head + num_entries) % dim;
111 cache_stream.seekg(pos*
sizeof(T));
118 cache_stream.read((
char*) &ret,
sizeof ret);
124 T read_entry(
const size_t pos)
129 s <<
"read_entry(" << pos <<
"): cache has " << n <<
" items";
130 throw range_error(s.str());
133 const size_t real_pos = (head + pos) % dim;
136 cache_stream.seekg(real_pos*
sizeof(ret));
137 cache_stream.read((
char*) &ret,
sizeof ret);
141 void write_entry(
const T & item)
143 cache_stream.write((
char*) &item,
sizeof item);
146 void validate_absolute_position(
const size_t pos)
const 152 s <<
"position " << pos <<
" is greater than dim " << dim;
153 throw out_of_range(s.str());
156 T read_absolute(
const size_t pos)
158 validate_absolute_position(pos);
160 cache_stream.seekg(pos*
sizeof(T));
161 cache_stream.read((
char*) &ret,
sizeof ret);
165 void write_absolute(
const size_t pos,
const T & item)
167 validate_absolute_position(pos);
168 cache_stream.seekp(pos*
sizeof(T));
169 cache_stream.write((
char*) &item,
sizeof item);
174 string to_string()
const 176 const size_t tg =
const_cast<fstream&
>(cache_stream).tellg()/
sizeof(T);
177 const size_t tp =
const_cast<fstream&
>(cache_stream).tellp()/
sizeof(T);
179 s <<
"Cache pars" << endl
180 <<
"capacity = " << capacity() << endl
181 <<
"size = " << size() << endl
182 <<
"sizeof T = " <<
sizeof(T) << endl
183 <<
"head pos = " << head_pos() << endl
184 <<
"tail pos = " << tail_pos() << endl
185 <<
"tellg/T = " << tg << endl
186 <<
"tellp/T = " << tp << endl;
190 friend ostream & operator << (ostream & out,
const RingFileCache & cache)
192 return out << cache.to_string();
219 static void create(
const string & pars_file_name,
220 const string & cache_file_name,
221 const size_t num_entries)
223 static_assert(std::is_default_constructible<T>::value,
224 "T type has not default constructor");
228 fstream pars_stream(pars_file_name, ios::binary | ios::out);
229 if ((not pars_stream.is_open()) or (not pars_stream.good()))
231 s <<
"cannot open " << pars_file_name;
232 throw std::domain_error(s.str());
235 fstream cache_stream(cache_file_name, ios::binary | ios::out);
236 if ((not cache_stream.is_open()) or (not cache_stream.good()))
238 s <<
"cannot open " << cache_file_name;
239 throw domain_error(s.str());
242 const size_t pars_size =
sizeof(Pars) + cache_file_name.size() + 1;
243 shared_ptr<Pars> pars_ptr((Pars*) malloc(pars_size), free);
244 if (pars_ptr ==
nullptr)
247 pars_ptr->dim = num_entries;
248 pars_ptr->n = pars_ptr->head = pars_ptr->tail = 0;
249 pars_ptr->size_cache_file = cache_file_name.size() + 1;
250 strcpy(pars_ptr->cache_file_name, cache_file_name.c_str());
251 pars_stream.write((
char*) pars_ptr.get(), pars_size);
254 memset(&init, 0,
sizeof(T));
255 for (
size_t i = 0; i < num_entries; ++i)
256 cache_stream.write((
char*) &init,
sizeof(init));
261 static string state(fstream & ss)
264 auto state = ss.rdstate();
265 if (state & ios::goodbit)
266 s <<
" goodbit = true " << endl;
268 s <<
" goodbit = false " << endl;
269 if (state & ios::badbit)
270 s <<
" badbit = true " << endl;
272 s <<
" badbit = false " << endl;
273 if (state & ios::failbit)
274 s <<
" failbit = true " << endl;
276 s <<
" failbit = false " << endl;
277 if (state & ios::eofbit)
278 s <<
" eofbit = true " << endl;
280 s <<
" eofbit = false " << endl;
285 void read_pars(
const string & pars_file_name)
288 pars_stream.open(pars_file_name, ios::binary | ios::out | ios::in);
289 if ((not pars_stream.is_open()) or (not pars_stream.good()))
291 s <<
"cannot open " << pars_file_name;
292 throw domain_error(s.str());
296 pars_stream.read((
char*) &pars,
sizeof pars);
304 const size_t name_size = min(Ring_Max_Name_Size, pars.size_cache_file);
305 shared_ptr<char> name((
char*) malloc(name_size), free);
306 pars_stream.read(name.get(), name_size);
307 cache_file_name = name.get();
309 cache_stream.open(cache_file_name, ios::binary | ios::out | ios::in);
310 if ((not cache_stream.is_open()) or (not cache_stream.good()))
312 s <<
"cannot open " << cache_file_name;
313 throw domain_error(s.str());
316 pars_stream.seekp(0);
318 cache_stream.seekg(head*
sizeof(T));
319 cache_stream.seekp(tail*
sizeof(T));
322 assert(pars_stream.good());
323 assert(cache_stream.good());
340 void validate_position(
const size_t pos)
const 342 if (pos < cache_ptr->dim)
346 s <<
"position " << pos <<
" is outside of maximum " << cache_ptr->dim;
347 throw std::out_of_range(s.str());
350 void increase_pos(
const long n = 1) noexcept
360 pos = pos % cache_ptr->dim;
363 void decrease_pos(
const long n = 1) noexcept
374 size_t m = n % cache_ptr->dim;
376 pos = cache_ptr->dim - (m - pos);
395 pos(cache.
head_pos() + __pos), end_pos(cache.dim) {}
397 Pointer operator ++ () noexcept
403 Pointer operator ++ (
int) noexcept
410 Pointer operator -- () noexcept
416 Pointer operator -- (
int) noexcept
423 Pointer & operator += (
const long val) noexcept
429 Pointer & operator -= (
const long val) noexcept
435 Pointer operator + (
const long val)
const noexcept
442 Pointer operator - (
const long val)
const noexcept
449 size_t get_pos_respect_to_head()
const noexcept
451 auto head = cache_ptr->head;
455 return cache_ptr->dim - head + pos;
458 size_t get_pos()
const noexcept
460 return get_pos_respect_to_head();
466 if (ptr.cache_ptr !=
this)
467 throw domain_error(
"RingFileCache::read(const Pointer&): invalid ptr");
469 return read_absolute(ptr.pos);
472 void write(
const Pointer & ptr,
const T & item)
474 if (ptr.cache_ptr !=
this)
475 throw domain_error(
"RingFileCache::write(const Pointer&): invalid ptr");
477 return write_absolute(ptr.pos, item);
480 bool is_initialized()
const {
return initialized; }
483 size_t size() const noexcept {
return n; }
489 size_t avail() const noexcept {
return dim - n; }
516 read_pars(pars_file_name);
535 static bool test(
const string & pars_fname)
537 ifstream pars_stream(pars_fname, ios::binary);
538 if (not pars_stream.good())
542 pars_stream.read((
char*) &pars,
sizeof pars);
546 const size_t name_size = min(Ring_Max_Name_Size, pars.size_cache_file);
547 shared_ptr<char> name((
char*) malloc(name_size), free);
548 pars_stream.read(name.get(), name_size);
549 const char * cache_file_name = name.get();
551 ifstream cache_stream(cache_file_name, ios::binary);
552 if (not cache_stream.good())
567 void init(
const string & pars_fname)
569 if (pars_stream.is_open())
570 throw std::domain_error(
"this cache has already an opened pars file");
593 test_and_set_tail_pointer();
595 assert(cache_stream.tellp() == tail*
sizeof(T));
601 cache_stream.seekp(0);
602 assert(cache_stream.good());
606 assert(cache_stream.good());
607 assert(cache_stream.tellp() == tail*
sizeof(T));
635 bool read(T entries[],
const size_t m = 1)
640 test_and_set_head_pointer();
642 assert(cache_stream.good());
645 const size_t n_avail_until_eof = dim - head;
646 if (m <= n_avail_until_eof)
647 cache_stream.read((
char*) entries, m*
sizeof(T));
650 cache_stream.read((
char*) entries, n_avail_until_eof*
sizeof(T));
651 cache_stream.seekg(0);
652 cache_stream.read((
char*) &entries[n_avail_until_eof],
653 (m - n_avail_until_eof)*
sizeof(T));
654 assert(cache_stream.gcount() == (m - n_avail_until_eof)*
sizeof(T));
657 assert(cache_stream.good());
666 throw underflow_error(
"read_first(): cache is empty");
668 test_and_set_head_pointer();
678 throw underflow_error(
"read_last(): cache is empty");
681 cache_stream.seekg((dim - 1)*
sizeof(T));
683 cache_stream.seekg((tail - 1)*
sizeof(T));
697 s <<
"youngest(" << i <<
") but the cache has " << n <<
" entries";
698 throw overflow_error(s.str());
715 read(&ret.
base(), n);
728 Iterator it(*
this, pos);
729 for (
size_t i = 0; i < m and it.has_curr(); ++i, it.next_ne())
730 ret.
append(it.get_curr_ne());
745 for (
size_t i = 0; i < m; ++i)
756 bool get(
const size_t m = 1) noexcept
761 head = (head + m) % dim;
778 assert(pars_stream.tellp() == 0);
784 pars.size_cache_file = cache_file_name.size() + 1;
785 pars_stream.write((
char*) &pars,
sizeof(pars));
787 pars_stream.seekp(0);
789 cache_stream.flush();
797 cache_stream.close();
815 throw domain_error(
"RingFileCache::resize(): file truncation is not " 816 "implemented (yet?)");
819 cache_stream.seekp(dim*
sizeof(T));
820 for (
size_t i = 0, n = sz - dim; i < n; ++i)
838 void set_curr_pointer()
840 cache_ptr->cache_stream.seekg(curr_pos*
sizeof(T));
846 if (++curr_pos == cache_ptr->dim)
853 curr = cache_ptr->read_entry();
858 size_t get_pos()
const noexcept {
return pos; }
860 bool has_curr()
const {
return pos < cache_ptr->n; }
870 pos(offset), curr_pos((cache_ptr->head + offset) % cache.dim)
875 if (not cache_ptr->is_valid_offset(pos))
881 T get_curr_ne()
const noexcept {
return curr; }
886 throw overflow_error(
"RingFileCache::Iterator::get_curr()");
887 return get_curr_ne();
890 void next_ne() noexcept
900 throw overflow_error(
"RingFileCache::Iterator::next()");
905 auto get_it() {
return Iterator(*
this); }
908 # endif // RINGFILECACHE_H size_t capacity() const noexcept
Returns the maximum capacity.
Definition: ringfilecache.H:486
T read_last()
Read the youngest entry in the set.
Definition: ringfilecache.H:675
void putn(const size_t n)
Definition: tpl_array.H:170
bool put(const T &item)
Definition: ringfilecache.H:586
Definition: ringfilecache.H:332
Pointer(const RingFileCache &cache, const size_t __pos=0)
Definition: ringfilecache.H:393
RingFileCache(const string &pars_fname)
Definition: ringfilecache.H:514
Array< T > read_from(const Pointer &ptr, const size_t m)
Definition: ringfilecache.H:741
void flush()
Definition: ringfilecache.H:776
RingFileCache()
Definition: ringfilecache.H:527
T & base() const noexcept
Return a modifiable reference to first element of array.
Definition: tpl_array.H:180
static bool test(const string &pars_fname)
Definition: ringfilecache.H:535
bool is_empty() const noexcept
Returns true if the cache is empty.
Definition: ringfilecache.H:498
T read_first()
Read the oldest entry in the set.
Definition: ringfilecache.H:663
size_t avail() const noexcept
Returns the number of available entries.
Definition: ringfilecache.H:489
void resize(const size_t sz)
Definition: ringfilecache.H:812
Definition: ringfilecache.H:51
T & append(const T &data)
Definition: tpl_array.H:109
static void create(const string &pars_file_name, const string &cache_file_name, const size_t num_entries)
Definition: ringfilecache.H:219
Definition: tpl_array.H:54
bool read(T entries[], const size_t m=1)
Definition: ringfilecache.H:635
void init(const string &pars_fname)
Definition: ringfilecache.H:567
size_t tail_pos() const noexcept
return the current tail position
Definition: ringfilecache.H:495
void empty()
empties the cache; all the entries are deleted
Definition: ringfilecache.H:768
size_t capacity() const noexcept
Return the internal capacity.
Definition: tpl_array.H:192
size_t head_pos() const noexcept
Returns the current head position.
Definition: ringfilecache.H:492
Array< T > read_all()
Definition: ringfilecache.H:710
size_t size() const noexcept
Returns the number of entries stored in the cache.
Definition: ringfilecache.H:483
Array< T > read_from(const size_t pos, const size_t m)
Definition: ringfilecache.H:725