Project
Loading...
Searching...
No Matches
PageParser.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef ALGORITHM_PAGEPARSER_H
13#define ALGORITHM_PAGEPARSER_H
14
19
20#include <functional>
21#include <vector>
22#include <cassert>
23#include <type_traits>
24#include <stdexcept>
25
26namespace o2
27{
28
29namespace algorithm
30{
31
32namespace pageparser
33{
34// a function to extract the number of elements from the group type
35// this is the version for all but integral types
36template <typename T>
37typename std::enable_if<std::is_void<T>::value, size_t>::type
39{
40 return 0;
41}
42
43// the specialization for integral types
44template <typename T>
45typename std::enable_if<std::is_integral<T>::value, T>::type
47{
48 return *v;
49}
50
51template <typename GroupT>
52using DefaultGetNElementsFctT = size_t (*)(const GroupT*);
53
54// the default function to extract the number of elements in a group
55// where the group header is a single integral type holding number of
56// elements
57auto defaultGetNElementsFct = [](const auto* groupdata) {
58 using ReturnType = size_t;
59 using T = typename std::remove_pointer<decltype(groupdata)>::type;
60 // this default function is only for integral types
61 static_assert(std::is_integral<T>::value || std::is_void<T>::value,
62 "A function for extracting the number of elements from the "
63 "group header must be specified for non-trivial types");
64 // the default function for trivial integral types means there
65 // is exactly one number holding the size
66 return static_cast<ReturnType>(extractNElements(groupdata));
67};
68
69template <typename T>
71{
72 return new T;
73}
74
75template <>
77{
78 return nullptr;
79}
80
81template <typename T>
82void free(T* ptr)
83{
84 if (ptr) {
85 delete ptr;
86 }
87}
88
89template <>
90void free<void>(void*)
91{
92}
93
94template <typename T>
96{
97 return sizeof(T);
98}
99
100template <>
102{
103 return 0;
104}
105
106template <typename T>
107void set(T* h, size_t v)
108{
109 *h = v;
110}
111
112template <>
113void set<void>(void*, size_t)
114{
115}
116} // namespace pageparser
117
158template <typename PageHeaderT,
159 size_t PageSize,
160 typename ElementT,
161 typename GroupT = void,
162 typename GetNElementsFctT = pageparser::DefaultGetNElementsFctT<GroupT>>
164{
165 public:
166 using PageHeaderType = PageHeaderT;
167 using BufferType = unsigned char;
168 using value_type = ElementT;
169 using GroupType = GroupT;
170 using GetNElements = GetNElementsFctT;
171 static const size_t page_size = PageSize;
172
173 // at the moment an object can only be split among two pages
174 static_assert(PageSize >= sizeof(PageHeaderType) + sizeof(value_type),
175 "Page Header and at least one element have to fit into page");
176
177 // switches for the copy method, used to skip ill-formed expressions
178 using TargetInPageBuffer = std::true_type;
179 using SourceInPageBuffer = std::false_type;
180
181 PageParser() = delete;
182 template <typename T>
185 : mBuffer(nullptr), mBufferIsConst(std::is_const<T>::value), mSize(size), mGetNElementsFct(getNElementsFct), mNPages(size > 0 ? ((size - 1) / page_size) + 1 : 0), mGroupHeader(pageparser::alloc<GroupType>())
186 {
187 static_assert(sizeof(T) == sizeof(BufferType),
188 "buffer required to be byte-type");
189
190 // the buffer pointer is stored non-const, a runtime check ensures
191 // that iterator write works only for non-const buffers
192 mBuffer = const_cast<BufferType*>(buffer);
193 }
195 {
196 pageparser::free(mGroupHeader);
197 }
198
199 template <typename T>
201 {
202 public:
205 using iterator_category = std::forward_iterator_tag;
206 using value_type = T;
207 using reference = T&;
208 using pointer = T*;
209 using difference_type = std::ptrdiff_t;
210 using ElementType = typename std::remove_const<value_type>::type;
211
212 Iterator() = delete;
213
214 Iterator(ParentType const* parent, size_t position = 0)
215 : mParent(parent)
216 {
217 mPosition = position;
218 size_t argument = mPosition;
219 if (!mParent->getElement(argument, mElement)) {
220 // eof, both mPosition and mNextPosition point to buffer end
221 mPosition = argument;
222 }
223 mNextPosition = argument;
224 backup();
225 }
227 {
228 sync();
229 }
230
231 // prefix increment
233 {
234 sync();
235 mPosition = mNextPosition;
236 size_t argument = mPosition;
237 if (!mParent->getElement(argument, mElement)) {
238 // eof, both mPosition and mNextPosition point to buffer end
239 mPosition = argument;
240 }
241 mNextPosition = argument;
242 backup();
243 return *this;
244 }
245 // postfix increment
246 SelfType operator++(int /*unused*/)
247 {
248 SelfType copy(*this);
249 operator++();
250 return copy;
251 }
252 // return reference
254 {
255 return mElement;
256 }
257 // comparison
258 bool operator==(const SelfType& rh) const
259 {
260 return mPosition == rh.mPosition;
261 }
262 // comparison
263 bool operator!=(const SelfType& rh) const
264 {
265 return mPosition != rh.mPosition;
266 }
267
269 {
270 return mParent->getGroupHeader();
271 }
272
273 private:
274 // sync method for non-const iterator
275 template <typename U = void>
276 typename std::enable_if<!std::is_const<value_type>::value, U>::type sync()
277 {
278 if (std::memcmp(&mElement, &mBackup, sizeof(value_type)) != 0) {
279 // mElement is changed, sync to buffer
280 mParent->setElement(mPosition, mElement);
281 }
282 }
283
284 // overload for const_iterator, empty function body
285 template <typename U = void>
286 typename std::enable_if<std::is_const<value_type>::value, U>::type sync()
287 {
288 }
289
290 // backup for non-const iterator
291 template <typename U = void>
292 typename std::enable_if<!std::is_const<value_type>::value, U>::type backup()
293 {
294 mBackup = mElement;
295 }
296
297 // overload for const_iterator, empty function body
298 template <typename U = void>
299 typename std::enable_if<std::is_const<value_type>::value, U>::type backup()
300 {
301 }
302
303 int mPosition;
304 int mNextPosition;
305 ParentType const* mParent;
306 ElementType mElement;
307 ElementType mBackup;
308 };
309
311 size_t setElement(size_t position, const value_type& element) const
312 {
313 // write functionality not yet implemented for grouped elements
314 assert(std::is_void<GroupType>::value);
315 // check if we are at the end
316 if (position >= mSize) {
317 assert(position == mSize);
318 return mSize;
319 }
320
321 // check if there is space for one element
322 if (position + sizeof(value_type) > mSize) {
323 // format error, probably throw exception
324 return mSize;
325 }
326
327 auto source = reinterpret_cast<const BufferType*>(&element);
328 auto target = mBuffer + position;
329 return position + copy<TargetInPageBuffer>(source, target, page_size - (position % page_size));
330 }
331
332 template <typename T>
333 size_t readGroupHeader(size_t position, T* groupHeader) const
334 {
335 assert((position % page_size) == sizeof(PageHeaderType));
336 if (std::is_void<T>::value) {
337 return 0;
338 }
339
340 memcpy(groupHeader, mBuffer + position, pageparser::sizeofGroupHeader<T>());
341 return mGetNElementsFct(groupHeader);
342 }
343
345 bool getElement(size_t& position, value_type& element) const
346 {
347 // check if we are at the end
348 if (position >= mSize) {
349 assert(position == mSize);
350 position = mSize;
351 return false;
352 }
353
354 // handle group if defined
355 if (!std::is_void<GroupType>::value) {
356 if (mNGroupElements == 0) {
357 // new group has to be read from the buffer
358 do {
359 if ((position % page_size) == 0) {
360 position += sizeof(PageHeaderType);
361 }
362 if ((position % page_size) != sizeof(PageHeaderType)) {
363 // forward to the next page
364 position += page_size - (position % page_size) + sizeof(PageHeaderType);
365 if (position > mSize) {
366 //this is probably a valid condition as the group header can just
367 //indicate zero clusters
368 //throw std::runtime_error("");
369 position = mSize;
370 return false;
371 }
372 }
373 const_cast<PageParser*>(this)->mNGroupElements = readGroupHeader(position, mGroupHeader);
374 position += pageparser::sizeofGroupHeader<GroupType>();
375 } while (mNGroupElements == 0);
376
377 size_t nPages = 0;
378 size_t required = pageparser::sizeofGroupHeader<GroupType>() + mNGroupElements * sizeof(value_type);
379 do {
380 // the block of elements can go beyond the current page, find out
381 // how many additional pages are required
382 required += sizeof(PageHeaderType);
383 ++nPages;
384 } while (required > nPages * page_size);
385 required -= sizeof(PageHeaderType) + pageparser::sizeofGroupHeader<GroupType>();
386 if (position + required > mSize) {
387 throw std::runtime_error(
388 "format error: the number of group elements "
389 "does not fit into the remaining buffer");
390 }
391 }
392 // now we will read one element
393 const_cast<PageParser*>(this)->mNGroupElements -= 1;
394 ;
395 }
396
397 // check if there is space for one element
398 if (position + sizeof(value_type) > mSize) {
399 // FIXME: not sure if this is considered an error condition if
400 // no groups are used, i.e. the buffer should have the correct size
401 // and no extra space after the last element
402 position = mSize;
403 return false;
404 }
405
406 auto source = mBuffer + position;
407 auto target = reinterpret_cast<BufferType*>(&element);
408 position += copy<SourceInPageBuffer>(source, target, page_size - (position % page_size));
409 return true;
410 }
411
412 // copy data, depending on compile time switch, either source or target
413 // pointer are treated as pointer in the raw page, i.e. can be additionally
414 // incremented by the page header
415 template <typename SwitchT>
416 size_t copy(const BufferType* source, BufferType* target, size_t pageCapacity) const
417 {
418 size_t position = 0;
419 auto copySize = sizeof(value_type);
420 // choose which of the pointers needs additional PageHeader offsets
421 auto pageOffsetTarget = SwitchT::value ? &target : const_cast<BufferType**>(&source);
422 if (pageCapacity == page_size) {
423 // skip the page header at beginning of page
424 position += sizeof(PageHeaderType);
425 pageCapacity -= sizeof(PageHeaderType);
426 *pageOffsetTarget += sizeof(PageHeaderType);
427 }
428 if (copySize > pageCapacity) {
429 // object is split at the page boundary, copy the part
430 // in the current page first
431 copySize = pageCapacity;
432 }
433 if (copySize > 0) {
434 memcpy(target, source, copySize);
435 position += copySize;
436 source += copySize;
437 target += copySize;
438 }
439 copySize = sizeof(value_type) - copySize;
440 if (copySize > 0) {
441 // skip page header at beginning of new page and copy
442 // remaining part of the element
443 position += sizeof(PageHeaderType);
444 *pageOffsetTarget += sizeof(PageHeaderType);
445 memcpy(target, source, copySize);
446 position += copySize;
447 }
448 return position;
449 }
450
452 {
453 return mGroupHeader;
454 }
455
458
460 {
461 return const_iterator(this, 0);
462 }
463
465 {
466 return const_iterator(this, mSize);
467 }
468
470 {
471 if (mBufferIsConst) {
472 // did not find a way to do this at compile time in the constructor,
473 // probably one needs to make the buffer type a template parameter
474 // to the class
475 throw std::runtime_error("the underlying buffer is not writeable");
476 }
477 return iterator(this, 0);
478 }
479
481 {
482 return iterator(this, mSize);
483 }
484
485 private:
486 BufferType* mBuffer = nullptr;
487 bool mBufferIsConst = false;
488 size_t mSize = 0;
489 GetNElements mGetNElementsFct = nullptr;
490 size_t mNPages = 0;
491 GroupType* mGroupHeader = nullptr;
492 size_t mNGroupElements = 0;
493};
494
495} // namespace algorithm
496} // namespace o2
497
498#endif
TBranch * ptr
Class for time synchronization of RawReader instances.
const GroupType * getGroupHeader() const
Definition PageParser.h:268
bool operator==(const SelfType &rh) const
Definition PageParser.h:258
bool operator!=(const SelfType &rh) const
Definition PageParser.h:263
Iterator(ParentType const *parent, size_t position=0)
Definition PageParser.h:214
typename std::remove_const< value_type >::type ElementType
Definition PageParser.h:210
std::forward_iterator_tag iterator_category
Definition PageParser.h:205
static const size_t page_size
Definition PageParser.h:171
Iterator< value_type > iterator
Definition PageParser.h:456
const_iterator begin() const
Definition PageParser.h:459
const GroupType getGroupHeader() const
Definition PageParser.h:451
size_t copy(const BufferType *source, BufferType *target, size_t pageCapacity) const
Definition PageParser.h:416
bool getElement(size_t &position, value_type &element) const
retrieve an object at position
Definition PageParser.h:345
GetNElementsFctT GetNElements
Definition PageParser.h:170
Iterator< const value_type > const_iterator
Definition PageParser.h:457
PageParser(T *buffer, size_t size, GetNElements getNElementsFct=pageparser::defaultGetNElementsFct)
Definition PageParser.h:183
const_iterator end() const
Definition PageParser.h:464
size_t readGroupHeader(size_t position, T *groupHeader) const
Definition PageParser.h:333
size_t setElement(size_t position, const value_type &element) const
set an object at position
Definition PageParser.h:311
std::true_type TargetInPageBuffer
Definition PageParser.h:178
std::false_type SourceInPageBuffer
Definition PageParser.h:179
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
std::enable_if< std::is_void< T >::value, size_t >::type extractNElements(T *v)
Definition PageParser.h:38
void set< void >(void *, size_t)
Definition PageParser.h:113
void free< void >(void *)
Definition PageParser.h:90
size_t(*)(const GroupT *) DefaultGetNElementsFctT
Definition PageParser.h:52
void set(T *h, size_t v)
Definition PageParser.h:107
constexpr size_t PageSize
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.