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