artdaq_core  v3_06_01
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() { return 5; } // proper version for templates
77 #endif
78 
79 namespace artdaq {
80 
86 QUICKVEC_TEMPLATE
87 struct QuickVec
88 {
89  typedef TT_* iterator;
90  typedef const TT_* const_iterator;
91  typedef TT_& reference;
92  typedef const TT_& const_reference;
93  typedef TT_ value_type;
94  typedef ptrdiff_t difference_type;
95  typedef size_t size_type;
96 
101  QuickVec(size_t sz);
102 
108  QuickVec(size_t sz, TT_ val);
109 
113  virtual ~QuickVec() noexcept;
114 
119  QuickVec(std::vector<TT_>& other)
120  : size_(other.size())
121  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
122  , capacity_(other.capacity())
123  {
124  TRACEN("QuickVec", 10, "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
125  memcpy(data_, (void*)&other[0], size_ * sizeof(TT_)); // NOLINT
126  }
127 
131  void clear() { size_ = 0; }
132 
133  //: size_(other.size_), data_(new TT_[other.capacity_]), capacity_(other.capacity_)
138  QuickVec(const QuickVec& other) //= delete; // non construction-copyable
139  : size_(other.size_)
140  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
141  , capacity_(other.capacity_)
142  {
143  TRACEN("QuickVec", 10, "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
144  memcpy(data_, other.data_, size_ * sizeof(TT_));
145  }
146 
152  QUICKVEC& operator=(const QuickVec& other) //= delete; // non copyable
153  {
154  TRACEN("QuickVec", 10, "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
155  resize(other.size_);
156  memcpy(data_, other.data_, size_ * sizeof(TT_));
157  return *this;
158  }
159 #if NOT_OLD_CXXSTD
160 
164  QuickVec(QuickVec&& other) noexcept // construction-movable
165  : size_(other.size_)
166  , data_(std::move(other.data_))
167  , capacity_(other.capacity_)
168  {
169  TRACEN("QuickVec", 10, "QuickVec move ctor this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
170  other.data_ = nullptr;
171  }
172 
178  QUICKVEC& operator=(QuickVec&& other) noexcept // assign movable
179  {
180  TRACEN("QuickVec", 10, "QuickVec move assign this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
181  size_ = other.size_;
182  //delete [] data_;
183  free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
184  data_ = std::move(other.data_);
185  capacity_ = other.capacity_;
186  other.data_ = nullptr;
187  return *this;
188  }
189 #endif
190 
196  TT_& operator[](int idx);
197 
203  const TT_& operator[](int idx) const;
204 
209  size_t size() const;
210 
219  size_t capacity() const;
220 
225  iterator begin();
226 
231  const_iterator begin() const;
232 
237  iterator end();
238 
243  const_iterator end() const;
244 
252  void reserve(size_t size);
253 
262  void resize(size_t size);
263 
274  void resizeWithCushion(size_t size, double growthFactor = 1.3);
275 
281  void resize(size_t size, TT_ val);
282 
294  iterator insert(const_iterator position, size_t nn, const TT_& val);
295 
308 
320 
325  void swap(QuickVec& other) noexcept;
326 
331  void push_back(const value_type& val);
332 
333  QUICKVEC_VERSION
334 
335 private:
336  // Root needs the size_ member first. It must be of type int.
337  // Root then needs the [size_] comment after data_.
338  // Note: NO SPACE between "//" and "[size_]"
339  unsigned size_;
340  TT_* data_; //[size_]
341  unsigned capacity_;
342 };
343 
344 QUICKVEC_TEMPLATE
345 inline QUICKVEC::QuickVec(size_t sz)
346  : size_(sz)
347  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
348  , capacity_(sz)
349 {
350  TRACEN("QuickVec", 15, "QuickVec %p ctor sz=%d data_=%p", (void*)this, size_, (void*)data_); // NOLINT
351 }
352 
353 QUICKVEC_TEMPLATE
354 inline QUICKVEC::QuickVec(size_t sz, TT_ val)
355  : size_(sz)
356  , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
357  , capacity_(sz)
358 {
359  TRACEN("QuickVec", 15, "QuickVec %p ctor sz=%d/v data_=%p", (void*)this, size_, (void*)data_); // NOLINT
360  for (iterator ii = begin(); ii != end(); ++ii) *ii = val;
361  //bzero( &data_[0], (sz<4)?(sz*sizeof(TT_)):(4*sizeof(TT_)) );
362 }
363 
364 QUICKVEC_TEMPLATE
365 inline QUICKVEC::~QuickVec() noexcept
366 {
367  TRACEN("QuickVec", 15, "QuickVec %p dtor start data_=%p size_=%d", (void*)this, (void*)data_, size_); // NOLINT
368 
369  free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
370 
371  TRACEN("QuickVec", 15, "QuickVec %p dtor return", (void*)this); // NOLINT
372 }
373 
374 QUICKVEC_TEMPLATE
375 inline TT_& QUICKVEC::operator[](int idx)
376 {
377  assert(idx < (int)size_);
378  return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
379 }
380 
381 QUICKVEC_TEMPLATE
382 inline const TT_& QUICKVEC::operator[](int idx) const
383 {
384  assert(idx < (int)size_);
385  return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
386 }
387 
388 QUICKVEC_TEMPLATE
389 inline size_t QUICKVEC::size() const { return size_; }
390 
391 QUICKVEC_TEMPLATE
392 inline size_t QUICKVEC::capacity() const { return capacity_; }
393 
394 QUICKVEC_TEMPLATE
395 inline QUICKVEC_TN::iterator QUICKVEC::begin() { return iterator(data_); }
396 
397 QUICKVEC_TEMPLATE
398 inline QUICKVEC_TN::const_iterator QUICKVEC::begin() const { return iterator(data_); }
399 
400 QUICKVEC_TEMPLATE
401 inline QUICKVEC_TN::iterator QUICKVEC::end()
402 {
403  return iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
404 }
405 
406 QUICKVEC_TEMPLATE
407 inline QUICKVEC_TN::const_iterator QUICKVEC::end() const
408 {
409  return const_iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
410 }
411 
412 QUICKVEC_TEMPLATE
413 inline void QUICKVEC::reserve(size_t size)
414 {
415  if (size > capacity_) // reallocation if true
416  {
417  TT_* old = data_;
418  //data_ = new TT_[size];
419  data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
420  memcpy(data_, old, size_ * sizeof(TT_));
421  TRACEN("QuickVec", 13, "QUICKVEC::reserve after memcpy this=%p old=%p data_=%p capacity=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT
422 
423  free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
424  capacity_ = size;
425  }
426 }
427 
428 QUICKVEC_TEMPLATE
429 inline void QUICKVEC::resize(size_t size)
430 {
431  if (size < size_)
432  size_ = size; // decrease
433  else if (size <= capacity_)
434  size_ = size;
435  else // increase/reallocate
436  {
437  TT_* old = data_;
438  data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
439  memcpy(data_, old, size_ * sizeof(TT_));
440  TRACEN("QuickVec", 13, "QUICKVEC::resize after memcpy this=%p old=%p data_=%p size=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT
441 
442  free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439
443  size_ = capacity_ = size;
444  }
445 }
446 
447 QUICKVEC_TEMPLATE
448 inline void QUICKVEC::resizeWithCushion(size_t size, double growthFactor)
449 {
450  if (size > capacity_)
451  {
452  size_t new_size = std::round(capacity_ * growthFactor);
453  if (new_size < size) { new_size = size; }
454  if (new_size < 512) { new_size = 512; }
455  else if (new_size < 2048)
456  {
457  new_size = 2048;
458  }
459  else if (new_size < 4096)
460  {
461  new_size = 4096;
462  }
463  else if (new_size < 8192)
464  {
465  new_size = 8192;
466  }
467  reserve(new_size);
468  }
469  resize(size);
470 }
471 
472 QUICKVEC_TEMPLATE
473 inline void QUICKVEC::resize(size_type size, TT_ val)
474 {
475  size_type old_size = size;
476  resize(size);
477  if (size > old_size)
478  {
479  TRACEN("QuickVec", 13, "QUICKVEC::resize initializing %zu elements", size - old_size); // NOLINT
480  for (iterator ii = begin() + old_size; ii != end(); ++ii) *ii = val;
481  }
482 }
483 
484 QUICKVEC_TEMPLATE
485 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, size_t nn, const TT_& val)
486 {
487  assert(position <= end()); // the current end
488  size_t offset = position - begin();
489  reserve(size_ + nn); // may reallocate and invalidate "position"
490 
491  iterator dst = end() + nn; // for shifting existing data after
492  iterator src = end(); // insertion point
493  size_t cnt = end() - (begin() + offset);
494  while (cnt--) *--dst = *--src;
495 
496  dst = begin() + offset;
497  size_ += nn;
498  while (nn--) *dst++ = val;
499  return begin() + offset;
500 }
501 
502 QUICKVEC_TEMPLATE
503 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, const_iterator first, const_iterator last)
504 {
505  assert(position <= end()); // the current end
506  size_t nn = (last - first);
507  size_t offset = position - begin();
508  reserve(size_ + nn); // may reallocate and invalidate "position"
509 
510  iterator dst = end() + nn; // for shifting existing data after
511  iterator src = end(); // insertion point
512  size_t cnt = end() - (begin() + offset);
513  while (cnt--) *--dst = *--src;
514 
515  dst = begin() + offset;
516  size_ += nn;
517  while (nn--) *dst++ = *first++;
518  return begin() + offset;
519 }
520 
521 QUICKVEC_TEMPLATE
522 inline QUICKVEC_TN::iterator QUICKVEC::erase(const_iterator first, const_iterator last)
523 {
524  assert(last <= end()); // the current end
525  size_t nn = (last - first);
526  size_t offset = first - begin();
527 
528  iterator dst = begin() + offset; // for shifting existing data from last
529  iterator src = dst + nn; // to first
530  size_t cnt = end() - src;
531  while (cnt--) *dst++ = *src++;
532 
533  size_ -= nn;
534  return begin() + offset;
535 }
536 
537 QUICKVEC_TEMPLATE
538 inline void QUICKVEC::swap(QuickVec& other) noexcept
539 {
540  TRACEN("QuickVec", 12, "QUICKVEC::swap this=%p enter data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT
541  std::swap(data_, other.data_);
542  std::swap(size_, other.size_);
543  std::swap(capacity_, other.capacity_);
544  TRACEN("QuickVec", 12, "QUICKVEC::swap return data_=%p other.data_=%p", (void*)data_, (void*)other.data_); // NOLINT
545 }
546 
547 QUICKVEC_TEMPLATE
548 inline void QUICKVEC::push_back(const value_type& val)
549 {
550  if (size_ == capacity_)
551  {
552  reserve(size_ + size_ / 10 + 1);
553  }
554  *end() = val;
555  ++size_;
556 }
557 
558 } // namespace artdaq
559 
560 #ifdef UNDEF_TRACE_AT_END
561 #undef TRACEN
562 #undef UNDEF_TRACE_AT_END
563 #endif
564 #endif /* QuickVec_hh */
iterator erase(const_iterator first, const_iterator last)
Erases elements in given range from the QuickVec.
Definition: QuickVec.hh:522
iterator end()
Gets an iterator to the end of the QuickVec.
Definition: QuickVec.hh:401
void clear()
Sets the size to 0. QuickVec does not reinitialize memory, so no further action will be taken...
Definition: QuickVec.hh:131
void reserve(size_t size)
Allocates memory for the QuickVec so that its capacity is at least size.
Definition: QuickVec.hh:413
void resize(size_t size)
Resizes the QuickVec.
Definition: QuickVec.hh:429
TT_ & operator[](int idx)
Returns a reference to a given element.
Definition: QuickVec.hh:375
size_t size_type
size_type is size_t
Definition: QuickVec.hh:95
TT_ value_type
value_type is member type
Definition: QuickVec.hh:93
size_t size() const
Accesses the current size of the QuickVec.
Definition: QuickVec.hh:389
TT_ * iterator
Iterator is pointer-to-member type.
Definition: QuickVec.hh:89
ptrdiff_t difference_type
difference_type is ptrdiff_t
Definition: QuickVec.hh:94
size_t capacity() const
Accesses the current capacity of the QuickVec.
Definition: QuickVec.hh:392
void swap(QuickVec &other) noexcept
Exchanges references to two QuickVec objects.
Definition: QuickVec.hh:538
void resizeWithCushion(size_t size, double growthFactor=1.3)
Resizes the QuickVec and requests additional capacity.
Definition: QuickVec.hh:448
iterator insert(const_iterator position, size_t nn, const TT_ &val)
Inserts an element into the QuickVec.
Definition: QuickVec.hh:485
void push_back(const value_type &val)
Adds a value to the QuickVec, resizing if necessary (adds 10% capacity)
Definition: QuickVec.hh:548
A QuickVec behaves like a std::vector, but does no initialization of its data, making it faster at th...
Definition: QuickVec.hh:87
QuickVec(size_t sz)
Allocates a QuickVec object, doing no initialization of allocated memory.
Definition: QuickVec.hh:345
const TT_ * const_iterator
const_iterator is const-pointer-to-member type
Definition: QuickVec.hh:90
const TT_ & const_reference
const_reference is const-reference-to-member type
Definition: QuickVec.hh:92
iterator begin()
Gets an iterator to the beginning of the QuickVec.
Definition: QuickVec.hh:395
QuickVec< TT_ > & operator=(const QuickVec &other)
Copy assignment operator.
Definition: QuickVec.hh:152
virtual ~QuickVec() noexcept
Destructor calls free on data.
Definition: QuickVec.hh:365
TT_ & reference
reference is reference-to-member tpye
Definition: QuickVec.hh:91
QuickVec(const QuickVec &other)
Copy Constructor.
Definition: QuickVec.hh:138