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