ADTF File Library
Loading...
Searching...
No Matches
fileringbuffer.h
Go to the documentation of this file.
1
16
17#ifndef DISK_RING_BUFFER_H
18#define DISK_RING_BUFFER_H
19
20#include <a_util/memory.h>
21#include <cstring>
22
23namespace utils5ext
24{
25
40template <typename ADDITIONAL_DATA = uint8_t, uint8_t alignment = 1, uint8_t alignment_fill = 0x00>
42{
43 public:
47 struct Item
48 {
49 Item(): file_pos(-1), size(0) {}
51 size_t size;
52 ADDITIONAL_DATA additional;
53 };
54
59 {
60 public:
67 virtual void onDrop(const Item& dropped_item, const Item& next_item) = 0;
68 };
69
73 struct ItemPiece
74 {
75 const void* data;
76 size_t data_size;
77 };
78
80 typedef std::deque<Item> Items;
82 typedef typename Items::const_iterator const_iterator;
83
84 private:
85 Items _items;
86 File* _file;
87 FilePos _start_offset;
88 FilePos _current_pos;
89 FileSize _current_size;
90 FileSize _max_size;
91 bool _bookkeeping;
92 DropCallback* _callback;
93 a_util::memory::MemoryBuffer _alignment_buffer;
94 Item _rear_item;
95
96 public:
105 FileRingBuffer(File* file, FilePos start_offset = 0,
106 FileSize max_size = 0, DropCallback* drop_callback = nullptr) :
107 _file(file),
108 _start_offset(start_offset),
109 _current_size(0),
110 _max_size(max_size),
111 _bookkeeping(true),
112 _callback(drop_callback)
113 {
114 file->setFilePos(start_offset, File::fp_begin);
115 _current_pos = start_offset;
116
117#ifdef _WIN32
118 __pragma(warning(push))
119 __pragma(warning(disable:4127))
120#endif
121 if (alignment > 1)
122 {
123 _alignment_buffer.allocate(alignment - 1);
124 std::memset(_alignment_buffer.getPtr(), alignment_fill, _alignment_buffer.getSize());
125 }
126#ifdef _WIN32
127 __pragma(warning(pop))
128#endif
130 }
131
137 {
138 return _current_size;
139 }
140
145 {
146 if (!_bookkeeping)
147 {
148 throw std::runtime_error("history already started wrapping around");
149 }
150
151 _max_size = _current_size;
152 }
153
161 void startAppending(Item* rear_data_item = nullptr, Item* last_data_item = nullptr)
162 {
163 if (!_bookkeeping)
164 {
165 throw std::runtime_error("already appending");
166 }
167
168 _max_size = 0;
169 _file->setFilePos(0, File::fp_end);
170 _current_pos = _file->getFilePos();
171 _bookkeeping = false;
172
173 if (_rear_item.file_pos == -1 && !_items.empty())
174 {
175 // we never wrapped around.
176 _rear_item = _items.back();
177 }
178
179 if (rear_data_item)
180 {
181 *rear_data_item = _rear_item;
182 }
183
184 if (last_data_item)
185 {
186 if (!_items.empty())
187 {
188 *last_data_item = _items.back();
189 }
190 else
191 {
192 *last_data_item = Item();
193 }
194 }
195 }
196
204 void appendItem(const void* data, size_t data_size,
205 const ADDITIONAL_DATA& additional, FilePos* file_pos = nullptr)
206 {
207 ItemPiece item;
208 item.data = data;
209 item.dataSize = data_size;
210 appendItem(&item, 1, additional, file_pos);
211 }
212
220 void appendItem(const ItemPiece* pieces, size_t count,
221 const ADDITIONAL_DATA& additional, FilePos* file_pos = nullptr)
222 {
223 size_t data_size = 0;
224 for (size_t piece = 0; piece < count; ++piece)
225 {
226 data_size += pieces[piece].data_size;
227 }
228
229 if (_max_size && !_items.empty())
230 {
231 if (_current_pos + static_cast<FileSize>(data_size) > _max_size)
232 {
233 // in this case we need to wrap around
234 _file->truncate(_current_pos);
235 _current_size = _current_pos;
236
237 _rear_item = _items.back();
238
239 //we need remove all items following this postion
240 while (_items.front().file_pos >= _current_pos)
241 {
242 popFront();
243 }
244
245 _current_pos = _items.front().file_pos; // this should be equal to the data offset
246 _file->setFilePos(_current_pos, File::fp_begin);
247 }
248 }
249
250 if (file_pos)
251 {
252 *file_pos = _current_pos;
253 }
254
255 FilePos write_pos = _current_pos;
256
257 for (size_t piece = 0; piece < count; ++piece)
258 {
259 _file->writeAll(pieces[piece].data, static_cast<int>(pieces[piece].data_size));
260 }
261
262 _current_pos += data_size;
263
265
266 if (_current_pos > _current_size)
267 {
268 _current_size = _current_pos;
269 }
270
271 if (_bookkeeping)
272 {
273 Item item;
274 item.file_pos = write_pos;
275 item.size = data_size;
276 item.additional = additional;
277
278 _items.push_back(item);
279
280 FilePos start = item.file_pos;
281 FilePos end = _current_pos;
282
283 while (_items.size() > 1 &&
284 _items.front().file_pos >= start &&
285 _items.front().file_pos < end)
286 {
287 popFront();
288 }
289
290 if (_rear_item.file_pos != -1)
291 {
292 // we did wrap around at least once
293 // check if this item did overwrite the current rear item
294 if (_rear_item.file_pos < end)
295 {
296 // it has been overwritten by the current one
297 // and was alread removed from the queue in the while loop above
298 // so the current item is the new rear item.
299 _rear_item = _items.back();
300 // make sure that the file ends after the current item
301 _file->truncate(_current_pos);
302 _current_size = _current_pos;
303 }
304 }
305 }
306 }
307
313 {
314 return _items.begin();
315 }
316
322 {
323 return _items.end();
324 }
325
326 protected:
332 {
333 FilePos mod = _current_pos % alignment;
334 if (mod)
335 {
336 FilePos fill = alignment - mod;
337 _file->writeAll(_alignment_buffer.getPtr(),
338 static_cast<size_t>(fill));
339 _current_pos += fill;
340 }
341 }
342
346 void popFront()
347 {
348 if (_callback)
349 {
350 static Item dummy;
351
352 Item& item = _items.front();
353 Item* next = &dummy;
354 if (_items.size() > 1)
355 {
356 next = &_items[1];
357 }
358 _callback->onDrop(item, *next);
359 }
360 _items.pop_front();
361 }
362};
363
364}
365
366#endif
Definition fileringbuffer.h:59
virtual void onDrop(const Item &dropped_item, const Item &next_item)=0
Items::const_iterator const_iterator
An const iterator in the buffer.
Definition fileringbuffer.h:82
void startWrappingAround()
Definition fileringbuffer.h:144
std::deque< Item > Items
Typedef for convienient access.
Definition fileringbuffer.h:80
void appendItem(const ItemPiece *pieces, size_t count, const ADDITIONAL_DATA &additional, FilePos *file_pos=nullptr)
Definition fileringbuffer.h:220
void appendItem(const void *data, size_t data_size, const ADDITIONAL_DATA &additional, FilePos *file_pos=nullptr)
Definition fileringbuffer.h:204
FileRingBuffer(File *file, FilePos start_offset=0, FileSize max_size=0, DropCallback *drop_callback=nullptr)
Definition fileringbuffer.h:105
void startAppending(Item *rear_data_item=nullptr, Item *last_data_item=nullptr)
Definition fileringbuffer.h:161
const_iterator end() const
Definition fileringbuffer.h:321
const FileSize & getCurrentSize()
Definition fileringbuffer.h:136
void popFront()
Definition fileringbuffer.h:346
const_iterator begin() const
Definition fileringbuffer.h:312
void fillForAlignment()
Definition fileringbuffer.h:331
Definition file.h:121
@ fp_end
offsets are measured from the end of the file
Definition file.h:187
@ fp_begin
offsets are measured from the beginning of the file
Definition file.h:181
FilePos setFilePos(FilePos offset, FilePosRef move_mode)
Definition file.h:32
int64_t FilePos
Type for a file position.
Definition file.h:37
FilePos FileSize
Type for the file size.
Definition file.h:41
Definition fileringbuffer.h:74
const void * data
The data of the piece.
Definition fileringbuffer.h:75
size_t data_size
The size of the piece.
Definition fileringbuffer.h:76
Definition fileringbuffer.h:48
ADDITIONAL_DATA additional
additional bookkeeping data
Definition fileringbuffer.h:52
size_t size
The size of the items data.
Definition fileringbuffer.h:51
FilePos file_pos
The file position of the items data.
Definition fileringbuffer.h:50