artdaq_core  v1_07_02
 All Classes Namespaces Functions
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 <string.h> // memcpy
15 //#include <strings.h> // bzero
16 //#include <stdlib.h> // posix_memalign
17 #include <cassert>
18 //#include <cstddef> // ptrdiff_t
19 //#include <utility> // std::swap
20 //#include <memory> // unique_ptr
21 #include <vector>
22 
23 //#include "trace.h" // TRACE
24 #ifndef TRACE
25 # define TRACE( lvl, ... )
26 # define UNDEF_TRACE_AT_END
27 #endif
28 
29 #define USE_UNIQUE_PTR 0
30 #define QV_ALIGN 512
31 static inline void *QV_MEMALIGN(size_t boundary, size_t size) { void *retadr; posix_memalign(&retadr, boundary, size); return retadr; }
32 
33 #ifndef QUICKVEC_DO_TEMPLATE
34 # define QUICKVEC_DO_TEMPLATE 1
35 #endif
36 
37 #undef NOT_OLD_CXXSTD
38 #if !defined(__GCCXML__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
39 # define NOT_OLD_CXXSTD 1
40 #endif
41 
42 #if QUICKVEC_DO_TEMPLATE == 0
43 # ifndef QUICKVEC_TT
44 # define QUICKVEC_TT unsigned long long
45 # endif
46 # define TT_ QUICKVEC_TT
47 # define QUICKVEC_TEMPLATE
48 # define QUICKVEC QuickVec
49 # define QUICKVEC_TN QuickVec
50 # define QUICKVEC_VERSION
51 #else
52 # define QUICKVEC_TEMPLATE template <typename TT_>
53 # define QUICKVEC QuickVec<TT_>
54 # define QUICKVEC_TN typename QuickVec<TT_>
55 // Class_Version() MUST be updated every time private member data change.
56 # define QUICKVEC_VERSION static short Class_Version() { return 5; } // proper version for templates
57 #endif
58 
59 namespace artdaq {
60 
61 QUICKVEC_TEMPLATE
62 struct QuickVec
63 {
64  typedef TT_* iterator;
65  typedef const TT_* const_iterator;
66  typedef TT_& reference;
67  typedef const TT_& const_reference;
68  typedef TT_ value_type;
69  typedef ptrdiff_t difference_type;
70  typedef size_t size_type;
71 
72  QuickVec(size_t sz);
73  QuickVec(size_t sz, TT_ val);
74 # if USE_UNIQUE_PTR == 0
75  virtual ~QuickVec() noexcept;
76 # define PTR_(xx) xx
77 # else
78 # define PTR_(xx) xx.get()
79 # endif
80  QuickVec(std::vector<TT_> & other)
81  //: size_(other.size()), data_(new TT_[other.capacity()]), capacity_(other.capacity())
82  : size_(other.size()), data_((TT_*)QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_))), capacity_(other.capacity())
83  {
84  memcpy(PTR_(data_), (void*)&other[0], size_ * sizeof(TT_));
85  }
86  void clear() { size_ = 0; }
87 
88  QuickVec(const QuickVec & other) //= delete; // non construction-copyable
89  //: size_(other.size_), data_(new TT_[other.capacity_]), capacity_(other.capacity_)
90  : size_(other.size_), data_((TT_*)QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_))), capacity_(other.capacity_)
91  {
92  TRACE(10, "QuickVec copy ctor this=%p data_=%p other.data_=%p size_=%d other.size_=%d"
93  , (void*)this, (void*)PTR_(data_), (void*)PTR_(other.data_), size_, other.size_);
94  memcpy(PTR_(data_), PTR_(other.data_), size_ * sizeof(TT_));
95  }
96  QUICKVEC & operator=(const QuickVec & other) //= delete; // non copyable
97  {
98  TRACE(10, "QuickVec copy assign this=%p data_=%p other.data_=%p size_=%d other.size_=%d"
99  , (void*)this, (void*)PTR_(data_), (void*)PTR_(other.data_), size_, other.size_);
100  resize(other.size_);
101  memcpy(PTR_(data_), PTR_(other.data_), size_ * sizeof(TT_));
102  return *this;
103  }
104 # if NOT_OLD_CXXSTD
105  QuickVec(QuickVec && other) noexcept // construction-movable
106  : size_(other.size_), data_(std::move(other.data_)), capacity_(other.capacity_)
107  {
108  TRACE(10, "QuickVec move ctor this=%p data_=%p other.data_=%p"
109  , (void*)this, (void*)PTR_(data_), (void*)PTR_(other.data_));
110 # if USE_UNIQUE_PTR == 0
111  other.data_ = nullptr;
112 # endif
113  }
114  QUICKVEC & operator=(QuickVec && other) noexcept // assign movable
115  {
116  TRACE(10, "QuickVec move assign this=%p data_=%p other.data_=%p"
117  , (void*)this, (void*)PTR_(data_), (void*)PTR_(other.data_));
118  size_ = other.size_;
119  //delete [] data_;
120  free(data_);
121  data_ = std::move(other.data_);
122  capacity_ = other.capacity_;
123 # if USE_UNIQUE_PTR == 0
124  other.data_ = nullptr;
125 # endif
126  return *this;
127  }
128 # endif
129 
130  TT_& operator[](int idx);
131  const TT_& operator[](int idx) const;
132  size_t size() const;
133  size_t capacity() const;
134  iterator begin();
135  const_iterator begin() const;
136  iterator end();
137  const_iterator end() const;
138  void reserve(size_t size);
139  void resize(size_t size);
140  void resize(size_t size, TT_ val);
141  iterator insert(const_iterator position, size_t nn, const TT_& val);
142  iterator insert(const_iterator position, const_iterator first
143  , const_iterator last);
144  iterator erase(const_iterator first, const_iterator last);
145  void swap(QuickVec& x) noexcept;
146  void push_back(const value_type& val);
147 
148  QUICKVEC_VERSION
149 
150 private:
151  // Root needs the size_ member first. It must be of type int.
152  // Root then needs the [size_] comment after data_.
153  // Note: NO SPACE between "//" and "[size_]"
154  unsigned size_;
155 # if USE_UNIQUE_PTR == 0
156  TT_ * data_; //[size_]
157 # else
158  std::unique_ptr<TT_[]> data_;
159 # endif
160  unsigned capacity_;
161 };
162 
163 QUICKVEC_TEMPLATE
164 inline QUICKVEC::QuickVec(size_t sz)
165 //: size_(sz), data_(new TT_[sz]), capacity_(sz)
166  : size_(sz), data_((TT_*)QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_))), capacity_(sz)
167 {
168  TRACE(15, "QuickVec %p ctor sz=%d data_=%p", (void*)this, size_, (void*)PTR_(data_));
169 }
170 QUICKVEC_TEMPLATE
171 inline QUICKVEC::QuickVec(size_t sz, TT_ val)
172 //: size_(sz), data_(new TT_[sz]), capacity_(sz)
173  : size_(sz), data_((TT_*)QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_))), capacity_(sz)
174 {
175  TRACE(15, "QuickVec %p ctor sz=%d/v data_=%p", (void*)this, size_, (void*)PTR_(data_));
176  for (iterator ii = begin(); ii != end(); ++ii) *ii = val;
177  //bzero( &data_[0], (sz<4)?(sz*sizeof(TT_)):(4*sizeof(TT_)) );
178 }
179 
180 #if USE_UNIQUE_PTR == 0
181 QUICKVEC_TEMPLATE
182 inline QUICKVEC::~QuickVec() noexcept
183 {
184  TRACE(15, "QuickVec %p dtor start data_=%p size_=%d"
185  , (void*)this, (void*)PTR_(data_), size_);
186  //delete [] data_;
187  free(data_);
188  TRACE(15, "QuickVec %p dtor return", (void*)this);
189 }
190 #endif
191 
192 QUICKVEC_TEMPLATE
193 inline TT_& QUICKVEC::operator[](int idx)
194 {
195  assert(idx < (int)size_); return data_[idx];
196 }
197 
198 QUICKVEC_TEMPLATE
199 inline const TT_& QUICKVEC::operator[](int idx) const
200 {
201  assert(idx < (int)size_);
202  return data_[idx];
203 }
204 
205 QUICKVEC_TEMPLATE
206 inline size_t QUICKVEC::size() const { return size_; }
207 QUICKVEC_TEMPLATE
208 inline size_t QUICKVEC::capacity() const { return capacity_; }
209 
210 QUICKVEC_TEMPLATE
211 inline QUICKVEC_TN::iterator QUICKVEC::begin() { return iterator(PTR_(data_)); }
212 QUICKVEC_TEMPLATE
213 inline QUICKVEC_TN::const_iterator QUICKVEC::begin() const { return iterator(PTR_(data_)); }
214 QUICKVEC_TEMPLATE
215 inline QUICKVEC_TN::iterator QUICKVEC::end() { return iterator(PTR_(data_) + size_); }
216 QUICKVEC_TEMPLATE
217 inline QUICKVEC_TN::const_iterator QUICKVEC::end() const { return const_iterator(PTR_(data_) + size_); }
218 
219 QUICKVEC_TEMPLATE
220 inline void QUICKVEC::reserve(size_t size)
221 {
222  if (size > capacity_) // reallocation if true
223  {
224 # if USE_UNIQUE_PTR == 0
225  TT_ * old = data_;
226  //data_ = new TT_[size];
227  data_ = (TT_*)QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_));
228  memcpy(data_, old, size_ * sizeof(TT_));
229  TRACE(13, "QUICKVEC::reserve this=%p old=%p data_=%p"
230  , (void*)this, (void*)old, (void*)data_);
231  //delete [] old;
232  free(old);
233 # else
234  std::unique_ptr<TT_[]> old = std::move(data_);
235  //data_ = std::unique_ptr<TT_[]>(new TT_[size]);
236  data_ = std::unique_ptr<TT_[]>((TT_*)QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_)));
237  memcpy(data_.get(), old.get(), size_ * sizeof(TT_));
238 # endif
239  capacity_ = size;
240  // bye to old(unique_ptr)
241  }
242 }
243 
244 QUICKVEC_TEMPLATE
245 inline void QUICKVEC::resize(size_t size)
246 {
247  if (size < size_) size_ = size; // decrease
248  else if (size <= capacity_) size_ = size;
249  else // increase/reallocate
250  {
251 # if USE_UNIQUE_PTR == 0
252  TT_ * old = data_;
253  //data_ = new TT_[size];
254  data_ = (TT_*)QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_));
255  memcpy(data_, old, size_ * sizeof(TT_));
256  TRACE(13, "QUICKVEC::resize this=%p old=%p data_=%p"
257  , (void*)this, (void*)old, (void*)data_);
258  //delete [] old;
259  free(old);
260 # else
261  std::unique_ptr<TT_[]> old = std::move(data_);
262  //data_ = std::unique_ptr<TT_[]>(new TT_[size]);
263  data_ = std::unique_ptr<TT_[]>((TT_*)QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_)));
264  memcpy(data_.get(), old.get(), size_ * sizeof(TT_));
265 # endif
266  size_ = capacity_ = size;
267  // bye to old(unique_ptr)
268  }
269 }
270 QUICKVEC_TEMPLATE
271 inline void QUICKVEC::resize(size_type size, TT_ val)
272 {
273  size_type old_size = size;
274  resize(size);
275  if (size > old_size)
276  for (iterator ii = begin() + old_size; ii != end(); ++ii) *ii = val;
277 }
278 
279 QUICKVEC_TEMPLATE
280 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position
281  , size_t nn
282  , const TT_& val)
283 {
284  assert(position <= end()); // the current end
285  size_t offset = position - begin();
286  reserve(size_ + nn); // may reallocate and invalidate "position"
287 
288  iterator dst = end() + nn; // for shifting existing data after
289  iterator src = end(); // insertion point
290  size_t cnt = end() - (begin() + offset);
291  while (cnt--) *--dst = *--src;
292 
293  dst = begin() + offset;
294  size_ += nn;
295  while (nn--) *dst++ = val;
296  return begin() + offset;
297 }
298 QUICKVEC_TEMPLATE
299 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position
300  , const_iterator first
301  , const_iterator last)
302 {
303  assert(position <= end()); // the current end
304  size_t nn = (last - first);
305  size_t offset = position - begin();
306  reserve(size_ + nn); // may reallocate and invalidate "position"
307 
308  iterator dst = end() + nn; // for shifting existing data after
309  iterator src = end(); // insertion point
310  size_t cnt = end() - (begin() + offset);
311  while (cnt--) *--dst = *--src;
312 
313  dst = begin() + offset;
314  size_ += nn;
315  while (nn--) *dst++ = *first++;
316  return begin() + offset;
317 }
318 
319 QUICKVEC_TEMPLATE
320 inline QUICKVEC_TN::iterator QUICKVEC::erase(const_iterator first
321  , const_iterator last)
322 {
323  assert(last <= end()); // the current end
324  size_t nn = (last - first);
325  size_t offset = first - begin();
326 
327  iterator dst = begin() + offset; // for shifting existing data from last
328  iterator src = dst + nn; // to first
329  size_t cnt = end() - src;
330  while (cnt--) *dst++ = *src++;
331 
332  size_ -= nn;
333  return begin() + offset;
334 }
335 
336 QUICKVEC_TEMPLATE
337 inline void QUICKVEC::swap(QuickVec& x) noexcept
338 {
339  TRACE(12, "QUICKVEC::swap this=%p enter data_=%p x.data_=%p"
340  , (void*)this, (void*)PTR_(data_), (void*)PTR_(x.data_));
341  std::swap(data_, x.data_);
342  std::swap(size_, x.size_);
343  std::swap(capacity_, x.capacity_);
344  TRACE(12, "QUICKVEC::swap return data_=%p x.data_=%p"
345  , (void*)PTR_(data_), (void*)PTR_(x.data_));
346 }
347 
348 QUICKVEC_TEMPLATE
349 inline void QUICKVEC::push_back(const value_type& val)
350 {
351  if (size_ == capacity_)
352  {
353  reserve(size_ + size_ / 10 + 1);
354  }
355  *end() = val;
356  ++size_;
357 }
358 
359 } // namespace
360 
361 #ifdef UNDEF_TRACE_AT_END
362 # undef TRACE
363 #endif
364 #endif /* QuickVec_hh */