artdaq_core  3.09.13
QuickVec.hh
1 // This file (QuickVec.hh) was created by Ron Rechenmacher <ron@fnal.gov> on
2 // Sep 3, 2014. "TERMS AND CONDITIONS" governing this file are in the README
3 // or COPYING file. If you do not have such a file, one can be obtained by
4 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
5 // $RCSfile: QuickVec.hh,v $
6 // rev="$Revision: 1.8 $$Date: 2014/09/05 19:21:11 $";
7 #ifndef QuickVec_hh
8 #define QuickVec_hh
9 
10 // extern "C" {
11 // #include <stdint.h>
12 // }
13 
14 #include <cstring> // memcpy
15 // #include <strings.h> // bzero
16 // #include <stdlib.h> // posix_memalign
17 #include <cstddef> // ptrdiff_t
18 // #include <utility> // std::swap
19 // #include <memory> // unique_ptr
21 #include <cassert>
22 #include <cmath>
23 #include <vector>
26 // #include "trace.h" // TRACE
27 #ifndef TRACEN
28 #define TRACEN(nam, lvl, ...)
29 #define UNDEF_TRACE_AT_END
30 #endif
31 
32 #define QV_ALIGN 512 // 512 byte align to support _possible_ direct I/O - see artdaq/artdaq/ArtModules/BinaryFileOutput_module.cc and artdaq issue #24437
33 
40 static inline void* QV_MEMALIGN(size_t boundary, size_t size)
41 {
42  void* retadr = nullptr;
43  posix_memalign(&retadr, boundary, size); // allows calling with 512-byte align to support _possible_ direct I/O. Ref. issue #24437
44  return retadr;
45 }
46 
47 #ifndef QUICKVEC_DO_TEMPLATE
48 #define QUICKVEC_DO_TEMPLATE 1
49 #endif
50 
51 #undef NOT_OLD_CXXSTD
52 #if !defined(__GCCXML__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
53 #define NOT_OLD_CXXSTD 1
54 #endif
55 
56 #if QUICKVEC_DO_TEMPLATE == 0
57 #ifndef QUICKVEC_TT
58 #define QUICKVEC_TT unsigned long long
59 #endif
60 #define TT_ QUICKVEC_TT
61 #define QUICKVEC_TEMPLATE
62 #define QUICKVEC QuickVec
63 #define QUICKVEC_TN QuickVec
64 #define QUICKVEC_VERSION
65 #else
66 #define QUICKVEC_TEMPLATE template<typename TT_>
67 #define QUICKVEC QuickVec<TT_>
68 #define QUICKVEC_TN typename QuickVec<TT_>
69 #define QUICKVEC_VERSION \
70  \
76  static short Class_Version() \
77  { \
78  return 5; \
79  } // proper version for templates
80 #endif
81 
82 namespace artdaq {
83 
89 QUICKVEC_TEMPLATE
90 struct QuickVec
91 {
92  typedef TT_* iterator;
93  typedef const TT_* const_iterator;
94  typedef TT_& reference;
95  typedef const TT_& const_reference;
96  typedef TT_ value_type;
97  typedef ptrdiff_t difference_type;
98  typedef size_t size_type;
99 
104  QuickVec(size_t sz);
105 
111  QuickVec(size_t sz, TT_ val);
112 
116  virtual ~QuickVec() noexcept;
117 
122  QuickVec(std::vector<TT_>& other)
123  : size_(other.size())
124  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
125  , capacity_(other.capacity())
126  {
127  TRACEN("QuickVec", 40, "QuickVec std::vector ctor b4 memcpy this=%p data_=%p &other[0]=%p size_=%d other.size()=%d", (void*)this, (void*)data_, (void*)&other[0], size_, other.size()); // NOLINT
128  memcpy(data_, (void*)&other[0], size_ * sizeof(TT_)); // NOLINT
129  }
130 
134  void clear() { size_ = 0; }
135 
136  //: size_(other.size_), data_(new TT_[other.capacity_]), capacity_(other.capacity_)
141  QuickVec(const QuickVec& other) //= delete; // non construction-copyable
142  : size_(other.size_)
143  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
144  , capacity_(other.capacity_)
145  {
146  TRACEN("QuickVec", 40, "QuickVec copy ctor b4 memcpy this=%p data_=%p other.data_=%p size_=%d other.size_=%d", (void*)this, (void*)data_, (void*)other.data_, size_, other.size_); // NOLINT
147  memcpy(data_, other.data_, size_ * sizeof(TT_));
148  }
149 
155  QUICKVEC& operator=(const QuickVec& other) //= delete; // non copyable
156  {
157  TRACEN("QuickVec", 40, "QuickVec copy assign b4 resize/memcpy this=%p data_=%p other.data_=%p size_=%d other.size_=%d", (void*)this, (void*)data_, (void*)other.data_, size_, other.size_); // NOLINT
158  resize(other.size_);
159  memcpy(data_, other.data_, size_ * sizeof(TT_));
160  return *this;
161  }
162 #if NOT_OLD_CXXSTD
163 
167  QuickVec(QuickVec&& other) noexcept // construction-movable
168  : size_(other.size_)
169  , data_(std::move(other.data_))
170  , capacity_(other.capacity_)
171  {
172  TRACEN("QuickVec", 40, "QuickVec move ctor this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
173  other.data_ = nullptr;
174  }
175 
181  QUICKVEC& operator=(QuickVec&& other) noexcept // assign movable
182  {
183  TRACEN("QuickVec", 40, "QuickVec move assign this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
184  size_ = other.size_;
185  // delete [] data_;
186  free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
187  data_ = std::move(other.data_);
188  capacity_ = other.capacity_;
189  other.data_ = nullptr;
190  return *this;
191  }
192 #endif
193 
199  TT_& operator[](int idx);
200 
206  const TT_& operator[](int idx) const;
207 
212  size_t size() const;
213 
222  size_t capacity() const;
223 
228  iterator begin();
229 
234  const_iterator begin() const;
235 
240  iterator end();
241 
246  const_iterator end() const;
247 
255  void reserve(size_t size);
256 
265  void resize(size_t size);
266 
277  void resizeWithCushion(size_t size, double growthFactor = 1.3);
278 
284  void resize(size_t size, TT_ val);
285 
297  iterator insert(const_iterator position, size_t nn, const TT_& val);
298 
311 
323 
328  void swap(QuickVec& other) noexcept;
329 
334  void push_back(const value_type& val);
335 
336  QUICKVEC_VERSION
337 
338 private:
339  // Root needs the size_ member first. It must be of type int.
340  // Root then needs the [size_] comment after data_.
341  // Note: NO SPACE between "//" and "[size_]"
342  unsigned size_;
343  TT_* data_; //[size_]
344  unsigned capacity_;
345 };
346 
347 QUICKVEC_TEMPLATE
348 inline QUICKVEC::QuickVec(size_t sz)
349  : size_(sz)
350  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
351  , capacity_(sz)
352 {
353  TRACEN("QuickVec", 45, "QuickVec %p ctor sz=%d data_=%p", (void*)this, size_, (void*)data_); // NOLINT
354 }
355 
356 QUICKVEC_TEMPLATE
357 inline QUICKVEC::QuickVec(size_t sz, TT_ val)
358  : size_(sz)
359  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
360  , capacity_(sz)
361 {
362  TRACEN("QuickVec", 45, "QuickVec %p ctor sz=%d/v data_=%p", (void*)this, size_, (void*)data_); // NOLINT
363  for (iterator ii = begin(); ii != end(); ++ii) *ii = val;
364  // bzero( &data_[0], (sz<4)?(sz*sizeof(TT_)):(4*sizeof(TT_)) );
365 }
366 
367 QUICKVEC_TEMPLATE
368 inline QUICKVEC::~QuickVec() noexcept
369 {
370  TRACEN("QuickVec", 45, "QuickVec %p dtor start data_=%p size_=%d", (void*)this, (void*)data_, size_); // NOLINT
371 
372  free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
373 
374  TRACEN("QuickVec", 45, "QuickVec %p dtor return", (void*)this); // NOLINT
375 }
376 
377 QUICKVEC_TEMPLATE
378 inline TT_& QUICKVEC::operator[](int idx)
379 {
380  assert(idx < (int)size_);
381  return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
382 }
383 
384 QUICKVEC_TEMPLATE
385 inline const TT_& QUICKVEC::operator[](int idx) const
386 {
387  assert(idx < (int)size_);
388  return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
389 }
390 
391 QUICKVEC_TEMPLATE
392 inline size_t QUICKVEC::size() const { return size_; }
393 
394 QUICKVEC_TEMPLATE
395 inline size_t QUICKVEC::capacity() const { return capacity_; }
396 
397 QUICKVEC_TEMPLATE
398 inline QUICKVEC_TN::iterator QUICKVEC::begin() { return iterator(data_); }
399 
400 QUICKVEC_TEMPLATE
401 inline QUICKVEC_TN::const_iterator QUICKVEC::begin() const { return iterator(data_); }
402 
403 QUICKVEC_TEMPLATE
404 inline QUICKVEC_TN::iterator QUICKVEC::end()
405 {
406  return iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
407 }
408 
409 QUICKVEC_TEMPLATE
410 inline QUICKVEC_TN::const_iterator QUICKVEC::end() const
411 {
412  return const_iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
413 }
414 
415 QUICKVEC_TEMPLATE
416 inline void QUICKVEC::reserve(size_t size)
417 {
418  if (size > capacity_) // reallocation if true
419  {
420  TT_* old = data_;
421  // data_ = new TT_[size];
422  data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
423  memcpy(data_, old, size_ * sizeof(TT_));
424  TRACEN("QuickVec", 43, "QUICKVEC::reserve after memcpy this=%p old=%p data_=%p capacity=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT
425 
426  free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
427  capacity_ = size;
428  }
429 }
430 
431 QUICKVEC_TEMPLATE
432 inline void QUICKVEC::resize(size_t size)
433 {
434  if (size < size_)
435  size_ = size; // decrease
436  else if (size <= capacity_)
437  size_ = size;
438  else // increase/reallocate
439  {
440  TT_* old = data_;
441  data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
442  memcpy(data_, old, size_ * sizeof(TT_));
443  TRACEN("QuickVec", 43, "QUICKVEC::resize after memcpy this=%p old=%p data_=%p size=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT
444 
445  free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
446  size_ = capacity_ = size;
447  }
448 }
449 
450 QUICKVEC_TEMPLATE
451 inline void QUICKVEC::resizeWithCushion(size_t size, double growthFactor)
452 {
453  if (size > capacity_)
454  {
455  size_t new_size = std::round(capacity_ * growthFactor);
456  if (new_size < size) { new_size = size; }
457  if (new_size < 512) { new_size = 512; }
458  else if (new_size < 2048)
459  {
460  new_size = 2048;
461  }
462  else if (new_size < 4096)
463  {
464  new_size = 4096;
465  }
466  else if (new_size < 8192)
467  {
468  new_size = 8192;
469  }
470  reserve(new_size);
471  }
472  resize(size);
473 }
474 
475 QUICKVEC_TEMPLATE
476 inline void QUICKVEC::resize(size_type size, TT_ val)
477 {
478  size_type old_size = size;
479  resize(size);
480  if (size > old_size)
481  {
482  TRACEN("QuickVec", 43, "QUICKVEC::resize initializing %zu elements", size - old_size); // NOLINT
483  for (iterator ii = begin() + old_size; ii != end(); ++ii) *ii = val;
484  }
485 }
486 
487 QUICKVEC_TEMPLATE
488 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, size_t nn, const TT_& val)
489 {
490  assert(position <= end()); // the current end
491  size_t offset = position - begin();
492  reserve(size_ + nn); // may reallocate and invalidate "position"
493 
494  iterator dst = end() + nn; // for shifting existing data after
495  iterator src = end(); // insertion point
496  size_t cnt = end() - (begin() + offset);
497  while (cnt--) *--dst = *--src;
498 
499  dst = begin() + offset;
500  size_ += nn;
501  while (nn--) *dst++ = val;
502  return begin() + offset;
503 }
504 
505 QUICKVEC_TEMPLATE
506 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, const_iterator first, const_iterator last)
507 {
508  assert(position <= end()); // the current end
509  size_t nn = (last - first);
510  size_t offset = position - begin();
511  reserve(size_ + nn); // may reallocate and invalidate "position"
512 
513  iterator dst = end() + nn; // for shifting existing data after
514  iterator src = end(); // insertion point
515  size_t cnt = end() - (begin() + offset);
516  while (cnt--) *--dst = *--src;
517 
518  dst = begin() + offset;
519  size_ += nn;
520  while (nn--) *dst++ = *first++;
521  return begin() + offset;
522 }
523 
524 QUICKVEC_TEMPLATE
525 inline QUICKVEC_TN::iterator QUICKVEC::erase(const_iterator first, const_iterator last)
526 {
527  assert(last <= end()); // the current end
528  size_t nn = (last - first);
529  size_t offset = first - begin();
530 
531  iterator dst = begin() + offset; // for shifting existing data from last
532  iterator src = dst + nn; // to first
533  size_t cnt = end() - src;
534  while (cnt--) *dst++ = *src++;
535 
536  size_ -= nn;
537  return begin() + offset;
538 }
539 
540 QUICKVEC_TEMPLATE
541 inline void QUICKVEC::swap(QuickVec& other) noexcept
542 {
543  TRACEN("QuickVec", 42, "QUICKVEC::swap this=%p enter data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
544  std::swap(data_, other.data_);
545  std::swap(size_, other.size_);
546  std::swap(capacity_, other.capacity_);
547  TRACEN("QuickVec", 42, "QUICKVEC::swap return data_=%p other.data_=%p", (void*)data_, (void*)other.data_); // NOLINT
548 }
549 
550 QUICKVEC_TEMPLATE
551 inline void QUICKVEC::push_back(const value_type& val)
552 {
553  if (size_ == capacity_)
554  {
555  reserve(size_ + size_ / 10 + 1);
556  }
557  *end() = val;
558  ++size_;
559 }
560 
561 } // namespace artdaq
562 
563 #ifdef UNDEF_TRACE_AT_END
564 #undef TRACEN
565 #undef UNDEF_TRACE_AT_END
566 #endif
567 #endif /* QuickVec_hh */
iterator erase(const_iterator first, const_iterator last)
Erases elements in given range from the QuickVec.
Definition: QuickVec.hh:525
iterator end()
Gets an iterator to the end of the QuickVec.
Definition: QuickVec.hh:404
void clear()
Sets the size to 0. QuickVec does not reinitialize memory, so no further action will be taken...
Definition: QuickVec.hh:134
void reserve(size_t size)
Allocates memory for the QuickVec so that its capacity is at least size.
Definition: QuickVec.hh:416
void resize(size_t size)
Resizes the QuickVec.
Definition: QuickVec.hh:432
TT_ & operator[](int idx)
Returns a reference to a given element.
Definition: QuickVec.hh:378
size_t size_type
size_type is size_t
Definition: QuickVec.hh:98
TT_ value_type
value_type is member type
Definition: QuickVec.hh:96
size_t size() const
Accesses the current size of the QuickVec.
Definition: QuickVec.hh:392
TT_ * iterator
Iterator is pointer-to-member type.
Definition: QuickVec.hh:92
ptrdiff_t difference_type
difference_type is ptrdiff_t
Definition: QuickVec.hh:97
size_t capacity() const
Accesses the current capacity of the QuickVec.
Definition: QuickVec.hh:395
void swap(QuickVec &other) noexcept
Exchanges references to two QuickVec objects.
Definition: QuickVec.hh:541
void resizeWithCushion(size_t size, double growthFactor=1.3)
Resizes the QuickVec and requests additional capacity.
Definition: QuickVec.hh:451
iterator insert(const_iterator position, size_t nn, const TT_ &val)
Inserts an element into the QuickVec.
Definition: QuickVec.hh:488
void push_back(const value_type &val)
Adds a value to the QuickVec, resizing if necessary (adds 10% capacity)
Definition: QuickVec.hh:551
A QuickVec behaves like a std::vector, but does no initialization of its data, making it faster at th...
Definition: QuickVec.hh:90
QuickVec(size_t sz)
Allocates a QuickVec object, doing no initialization of allocated memory.
Definition: QuickVec.hh:348
const TT_ * const_iterator
const_iterator is const-pointer-to-member type
Definition: QuickVec.hh:93
const TT_ & const_reference
const_reference is const-reference-to-member type
Definition: QuickVec.hh:95
iterator begin()
Gets an iterator to the beginning of the QuickVec.
Definition: QuickVec.hh:398
QuickVec< TT_ > & operator=(const QuickVec &other)
Copy assignment operator.
Definition: QuickVec.hh:155
virtual ~QuickVec() noexcept
Destructor calls free on data.
Definition: QuickVec.hh:368
TT_ & reference
reference is reference-to-member tpye
Definition: QuickVec.hh:94
QuickVec(const QuickVec &other)
Copy Constructor.
Definition: QuickVec.hh:141