$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_06_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // This file (QuickVec.hh) was created by Ron Rechenmacher <ron@fnal.gov> on 00002 // Sep 3, 2014. "TERMS AND CONDITIONS" governing this file are in the README 00003 // or COPYING file. If you do not have such a file, one can be obtained by 00004 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000. 00005 // $RCSfile: QuickVec.hh,v $ 00006 // rev="$Revision: 1.8 $$Date: 2014/09/05 19:21:11 $"; 00007 #ifndef QuickVec_hh 00008 #define QuickVec_hh 00009 00010 //extern "C" { 00011 //#include <stdint.h> 00012 //} 00013 00014 #include <cstring> // memcpy 00015 //#include <strings.h> // bzero 00016 //#include <stdlib.h> // posix_memalign 00017 #include <cstddef> // ptrdiff_t 00018 //#include <utility> // std::swap 00019 //#include <memory> // unique_ptr 00021 #include <cassert> 00022 #include <cmath> 00023 #include <vector> 00026 //#include "trace.h" // TRACE 00027 #ifndef TRACEN 00028 #define TRACEN(nam, lvl, ...) 00029 #define UNDEF_TRACE_AT_END 00030 #endif 00031 00032 #define QV_ALIGN 512 // 512 byte align to support _possible_ direct I/O - see artdaq/artdaq/ArtModules/BinaryFileOutput_module.cc and artdaq issue #24437 00033 00040 static inline void* QV_MEMALIGN(size_t boundary, size_t size) 00041 { 00042 void* retadr = nullptr; 00043 posix_memalign(&retadr, boundary, size); // allows calling with 512-byte align to support _possible_ direct I/O. Ref. issue #24437 00044 return retadr; 00045 } 00046 00047 #ifndef QUICKVEC_DO_TEMPLATE 00048 #define QUICKVEC_DO_TEMPLATE 1 00049 #endif 00050 00051 #undef NOT_OLD_CXXSTD 00052 #if !defined(__GCCXML__) && defined(__GXX_EXPERIMENTAL_CXX0X__) 00053 #define NOT_OLD_CXXSTD 1 00054 #endif 00055 00056 #if QUICKVEC_DO_TEMPLATE == 0 00057 #ifndef QUICKVEC_TT 00058 #define QUICKVEC_TT unsigned long long 00059 #endif 00060 #define TT_ QUICKVEC_TT 00061 #define QUICKVEC_TEMPLATE 00062 #define QUICKVEC QuickVec 00063 #define QUICKVEC_TN QuickVec 00064 #define QUICKVEC_VERSION 00065 #else 00066 #define QUICKVEC_TEMPLATE template<typename TT_> 00067 #define QUICKVEC QuickVec<TT_> 00068 #define QUICKVEC_TN typename QuickVec<TT_> 00069 #define QUICKVEC_VERSION \ 00070 \ 00076 static short Class_Version() { return 5; } // proper version for templates 00077 #endif 00078 00079 namespace artdaq { 00080 00086 QUICKVEC_TEMPLATE 00087 struct QuickVec 00088 { 00089 typedef TT_* iterator; 00090 typedef const TT_* const_iterator; 00091 typedef TT_& reference; 00092 typedef const TT_& const_reference; 00093 typedef TT_ value_type; 00094 typedef ptrdiff_t difference_type; 00095 typedef size_t size_type; 00096 00101 QuickVec(size_t sz); 00102 00108 QuickVec(size_t sz, TT_ val); 00109 00113 virtual ~QuickVec() noexcept; 00114 00119 QuickVec(std::vector<TT_>& other) 00120 : size_(other.size()) 00121 , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00122 , capacity_(other.capacity()) 00123 { 00124 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 00125 memcpy(data_, (void*)&other[0], size_ * sizeof(TT_)); // NOLINT 00126 } 00127 00131 void clear() { size_ = 0; } 00132 00133 //: size_(other.size_), data_(new TT_[other.capacity_]), capacity_(other.capacity_) 00138 QuickVec(const QuickVec& other) //= delete; // non construction-copyable 00139 : size_(other.size_) 00140 , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, other.capacity() * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00141 , capacity_(other.capacity_) 00142 { 00143 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 00144 memcpy(data_, other.data_, size_ * sizeof(TT_)); 00145 } 00146 00152 QUICKVEC& operator=(const QuickVec& other) //= delete; // non copyable 00153 { 00154 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 00155 resize(other.size_); 00156 memcpy(data_, other.data_, size_ * sizeof(TT_)); 00157 return *this; 00158 } 00159 #if NOT_OLD_CXXSTD 00160 00164 QuickVec(QuickVec&& other) noexcept // construction-movable 00165 : size_(other.size_) 00166 , data_(std::move(other.data_)) 00167 , capacity_(other.capacity_) 00168 { 00169 TRACEN("QuickVec", 10, "QuickVec move ctor this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT 00170 other.data_ = nullptr; 00171 } 00172 00178 QUICKVEC& operator=(QuickVec&& other) noexcept // assign movable 00179 { 00180 TRACEN("QuickVec", 10, "QuickVec move assign this=%p data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT 00181 size_ = other.size_; 00182 //delete [] data_; 00183 free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439 00184 data_ = std::move(other.data_); 00185 capacity_ = other.capacity_; 00186 other.data_ = nullptr; 00187 return *this; 00188 } 00189 #endif 00190 00196 TT_& operator[](int idx); 00197 00203 const TT_& operator[](int idx) const; 00204 00209 size_t size() const; 00210 00219 size_t capacity() const; 00220 00225 iterator begin(); 00226 00231 const_iterator begin() const; 00232 00237 iterator end(); 00238 00243 const_iterator end() const; 00244 00252 void reserve(size_t size); 00253 00262 void resize(size_t size); 00263 00274 void resizeWithCushion(size_t size, double growthFactor = 1.3); 00275 00281 void resize(size_t size, TT_ val); 00282 00294 iterator insert(const_iterator position, size_t nn, const TT_& val); 00295 00307 iterator insert(const_iterator position, const_iterator first, const_iterator last); 00308 00319 iterator erase(const_iterator first, const_iterator last); 00320 00325 void swap(QuickVec& other) noexcept; 00326 00331 void push_back(const value_type& val); 00332 00333 QUICKVEC_VERSION 00334 00335 private: 00336 // Root needs the size_ member first. It must be of type int. 00337 // Root then needs the [size_] comment after data_. 00338 // Note: NO SPACE between "//" and "[size_]" 00339 unsigned size_; 00340 TT_* data_; //[size_] 00341 unsigned capacity_; 00342 }; 00343 00344 QUICKVEC_TEMPLATE 00345 inline QUICKVEC::QuickVec(size_t sz) 00346 : size_(sz) 00347 , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00348 , capacity_(sz) 00349 { 00350 TRACEN("QuickVec", 15, "QuickVec %p ctor sz=%d data_=%p", (void*)this, size_, (void*)data_); // NOLINT 00351 } 00352 00353 QUICKVEC_TEMPLATE 00354 inline QUICKVEC::QuickVec(size_t sz, TT_ val) 00355 : size_(sz) 00356 , data_(reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, sz * sizeof(TT_)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00357 , capacity_(sz) 00358 { 00359 TRACEN("QuickVec", 15, "QuickVec %p ctor sz=%d/v data_=%p", (void*)this, size_, (void*)data_); // NOLINT 00360 for (iterator ii = begin(); ii != end(); ++ii) *ii = val; 00361 //bzero( &data_[0], (sz<4)?(sz*sizeof(TT_)):(4*sizeof(TT_)) ); 00362 } 00363 00364 QUICKVEC_TEMPLATE 00365 inline QUICKVEC::~QuickVec() noexcept 00366 { 00367 TRACEN("QuickVec", 15, "QuickVec %p dtor start data_=%p size_=%d", (void*)this, (void*)data_, size_); // NOLINT 00368 00369 free(data_); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439 00370 00371 TRACEN("QuickVec", 15, "QuickVec %p dtor return", (void*)this); // NOLINT 00372 } 00373 00374 QUICKVEC_TEMPLATE 00375 inline TT_& QUICKVEC::operator[](int idx) 00376 { 00377 assert(idx < (int)size_); 00378 return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 00379 } 00380 00381 QUICKVEC_TEMPLATE 00382 inline const TT_& QUICKVEC::operator[](int idx) const 00383 { 00384 assert(idx < (int)size_); 00385 return data_[idx]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 00386 } 00387 00388 QUICKVEC_TEMPLATE 00389 inline size_t QUICKVEC::size() const { return size_; } 00390 00391 QUICKVEC_TEMPLATE 00392 inline size_t QUICKVEC::capacity() const { return capacity_; } 00393 00394 QUICKVEC_TEMPLATE 00395 inline QUICKVEC_TN::iterator QUICKVEC::begin() { return iterator(data_); } 00396 00397 QUICKVEC_TEMPLATE 00398 inline QUICKVEC_TN::const_iterator QUICKVEC::begin() const { return iterator(data_); } 00399 00400 QUICKVEC_TEMPLATE 00401 inline QUICKVEC_TN::iterator QUICKVEC::end() 00402 { 00403 return iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 00404 } 00405 00406 QUICKVEC_TEMPLATE 00407 inline QUICKVEC_TN::const_iterator QUICKVEC::end() const 00408 { 00409 return const_iterator(data_ + size_); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 00410 } 00411 00412 QUICKVEC_TEMPLATE 00413 inline void QUICKVEC::reserve(size_t size) 00414 { 00415 if (size > capacity_) // reallocation if true 00416 { 00417 TT_* old = data_; 00418 //data_ = new TT_[size]; 00419 data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00420 memcpy(data_, old, size_ * sizeof(TT_)); 00421 TRACEN("QuickVec", 13, "QUICKVEC::reserve after memcpy this=%p old=%p data_=%p capacity=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT 00422 00423 free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439 00424 capacity_ = size; 00425 } 00426 } 00427 00428 QUICKVEC_TEMPLATE 00429 inline void QUICKVEC::resize(size_t size) 00430 { 00431 if (size < size_) 00432 size_ = size; // decrease 00433 else if (size <= capacity_) 00434 size_ = size; 00435 else // increase/reallocate 00436 { 00437 TT_* old = data_; 00438 data_ = reinterpret_cast<TT_*>(QV_MEMALIGN(QV_ALIGN, size * sizeof(TT_))); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00439 memcpy(data_, old, size_ * sizeof(TT_)); 00440 TRACEN("QuickVec", 13, "QUICKVEC::resize after memcpy this=%p old=%p data_=%p size=%d", (void*)this, (void*)old, (void*)data_, (int)size); // NOLINT 00441 00442 free(old); // NOLINT(cppcoreguidelines-no-malloc) TODO: #24439 00443 size_ = capacity_ = size; 00444 } 00445 } 00446 00447 QUICKVEC_TEMPLATE 00448 inline void QUICKVEC::resizeWithCushion(size_t size, double growthFactor) 00449 { 00450 if (size > capacity_) 00451 { 00452 size_t new_size = std::round(capacity_ * growthFactor); 00453 if (new_size < size) { new_size = size; } 00454 if (new_size < 512) { new_size = 512; } 00455 else if (new_size < 2048) 00456 { 00457 new_size = 2048; 00458 } 00459 else if (new_size < 4096) 00460 { 00461 new_size = 4096; 00462 } 00463 else if (new_size < 8192) 00464 { 00465 new_size = 8192; 00466 } 00467 reserve(new_size); 00468 } 00469 resize(size); 00470 } 00471 00472 QUICKVEC_TEMPLATE 00473 inline void QUICKVEC::resize(size_type size, TT_ val) 00474 { 00475 size_type old_size = size; 00476 resize(size); 00477 if (size > old_size) 00478 { 00479 TRACEN("QuickVec", 13, "QUICKVEC::resize initializing %zu elements", size - old_size); // NOLINT 00480 for (iterator ii = begin() + old_size; ii != end(); ++ii) *ii = val; 00481 } 00482 } 00483 00484 QUICKVEC_TEMPLATE 00485 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, size_t nn, const TT_& val) 00486 { 00487 assert(position <= end()); // the current end 00488 size_t offset = position - begin(); 00489 reserve(size_ + nn); // may reallocate and invalidate "position" 00490 00491 iterator dst = end() + nn; // for shifting existing data after 00492 iterator src = end(); // insertion point 00493 size_t cnt = end() - (begin() + offset); 00494 while (cnt--) *--dst = *--src; 00495 00496 dst = begin() + offset; 00497 size_ += nn; 00498 while (nn--) *dst++ = val; 00499 return begin() + offset; 00500 } 00501 00502 QUICKVEC_TEMPLATE 00503 inline QUICKVEC_TN::iterator QUICKVEC::insert(const_iterator position, const_iterator first, const_iterator last) 00504 { 00505 assert(position <= end()); // the current end 00506 size_t nn = (last - first); 00507 size_t offset = position - begin(); 00508 reserve(size_ + nn); // may reallocate and invalidate "position" 00509 00510 iterator dst = end() + nn; // for shifting existing data after 00511 iterator src = end(); // insertion point 00512 size_t cnt = end() - (begin() + offset); 00513 while (cnt--) *--dst = *--src; 00514 00515 dst = begin() + offset; 00516 size_ += nn; 00517 while (nn--) *dst++ = *first++; 00518 return begin() + offset; 00519 } 00520 00521 QUICKVEC_TEMPLATE 00522 inline QUICKVEC_TN::iterator QUICKVEC::erase(const_iterator first, const_iterator last) 00523 { 00524 assert(last <= end()); // the current end 00525 size_t nn = (last - first); 00526 size_t offset = first - begin(); 00527 00528 iterator dst = begin() + offset; // for shifting existing data from last 00529 iterator src = dst + nn; // to first 00530 size_t cnt = end() - src; 00531 while (cnt--) *dst++ = *src++; 00532 00533 size_ -= nn; 00534 return begin() + offset; 00535 } 00536 00537 QUICKVEC_TEMPLATE 00538 inline void QUICKVEC::swap(QuickVec& other) noexcept 00539 { 00540 TRACEN("QuickVec", 12, "QUICKVEC::swap this=%p enter data_=%p other.data_=%p", (void*)this, (void*)data_, (void*)other.data_); // NOLINT 00541 std::swap(data_, other.data_); 00542 std::swap(size_, other.size_); 00543 std::swap(capacity_, other.capacity_); 00544 TRACEN("QuickVec", 12, "QUICKVEC::swap return data_=%p other.data_=%p", (void*)data_, (void*)other.data_); // NOLINT 00545 } 00546 00547 QUICKVEC_TEMPLATE 00548 inline void QUICKVEC::push_back(const value_type& val) 00549 { 00550 if (size_ == capacity_) 00551 { 00552 reserve(size_ + size_ / 10 + 1); 00553 } 00554 *end() = val; 00555 ++size_; 00556 } 00557 00558 } // namespace artdaq 00559 00560 #ifdef UNDEF_TRACE_AT_END 00561 #undef TRACEN 00562 #undef UNDEF_TRACE_AT_END 00563 #endif 00564 #endif /* QuickVec_hh */