15#ifndef OPENVDB_UTIL_PAGED_ARRAY_HAS_BEEN_INCLUDED
16#define OPENVDB_UTIL_PAGED_ARRAY_HAS_BEEN_INCLUDED
18#include <openvdb/version.h>
26#include <tbb/spin_mutex.h>
27#include <tbb/parallel_for.h>
28#include <tbb/parallel_sort.h>
142template<
typename ValueT,
size_t Log2PageSize = 10UL>
146 static_assert(Log2PageSize > 1UL,
"Expected Log2PageSize > 1");
150 using PageTableT = std::deque<Page*>;
195 const size_t index = mSize.fetch_add(1);
196 if (index >= mCapacity) {
197 mPageTable.push_back(
new Page() );
198 mCapacity += Page::Size;
200 (*mPageTable[index >> Log2PageSize])[index] = value;
207 void shrink_to_fit();
219 return (*mPageTable[i>>Log2PageSize])[i];
232 return (*mPageTable[i>>Log2PageSize])[i];
242 auto op = [&](
const tbb::blocked_range<size_t>& r){
243 for(
size_t i=r.begin(); i!=r.end(); ++i) mPageTable[i]->fill(v);
245 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->pageCount()), op);
257 size_t last_page = count >> Log2PageSize;
258 if (last_page >= this->pageCount())
return false;
259 auto op = [&](
const tbb::blocked_range<size_t>& r){
260 for (
size_t i=r.begin(); i!=r.end(); ++i) {
261 mPageTable[i]->copy(p+i*Page::Size, Page::Size);
264 if (
size_t m = count & Page::Mask) {
265 tbb::parallel_for(tbb::blocked_range<size_t>(0, last_page, 32), op);
266 mPageTable[last_page]->copy(p+last_page*Page::Size, m);
268 tbb::parallel_for(tbb::blocked_range<size_t>(0, last_page+1, 32), op);
291 if (size > mCapacity) {
294 this->shrink_to_fit();
320 size_t size()
const {
return mSize; }
342 return sizeof(*this) + mPageTable.size() * Page::memUsage();
361 for (
size_t i=0, n=mPageTable.size(); i<n; ++i)
delete mPageTable[i];
362 PageTableT().swap(mPageTable);
394 void sort() { tbb::parallel_sort(this->begin(), this->end(), std::less<ValueT>() ); }
397 void invSort() { tbb::parallel_sort(this->begin(), this->end(), std::greater<ValueT>()); }
404 template <
typename Functor>
405 void sort(Functor func) { tbb::parallel_sort(this->begin(), this->end(), func ); }
418 void print(std::ostream& os = std::cout)
const
420 os <<
"PagedArray:\n"
421 <<
"\tSize: " << this->size() <<
" elements\n"
422 <<
"\tPage table: " << this->pageCount() <<
" pages\n"
423 <<
"\tPage size: " << this->pageSize() <<
" elements\n"
424 <<
"\tCapacity: " << this->capacity() <<
" elements\n"
425 <<
"\tFootprint: " << this->memUsage() <<
" bytes\n";
432 void grow(
size_t index)
434 tbb::spin_mutex::scoped_lock lock(mGrowthMutex);
435 while(index >= mCapacity) {
436 mPageTable.push_back(
new Page() );
437 mCapacity += Page::Size;
441 void add_full(Page*& page,
size_t size);
443 void add_partially_full(Page*& page,
size_t size);
445 void add(Page*& page,
size_t size) {
446 tbb::spin_mutex::scoped_lock lock(mGrowthMutex);
447 if (size == Page::Size) {
448 this->add_full(page, size);
450 this->add_partially_full(page, size);
453 PageTableT mPageTable;
454 std::atomic<size_t> mSize;
456 tbb::spin_mutex mGrowthMutex;
461template <
typename ValueT,
size_t Log2PageSize>
464 if (mPageTable.size() > (mSize >> Log2PageSize) + 1) {
465 tbb::spin_mutex::scoped_lock lock(mGrowthMutex);
466 const size_t pageCount = (mSize >> Log2PageSize) + 1;
467 if (mPageTable.size() > pageCount) {
468 delete mPageTable.back();
469 mPageTable.pop_back();
470 mCapacity -= Page::Size;
475template <
typename ValueT,
size_t Log2PageSize>
478 if (&other !=
this && !other.
isEmpty()) {
479 tbb::spin_mutex::scoped_lock lock(mGrowthMutex);
481 Page* page =
nullptr;
482 const size_t size = mSize & Page::Mask;
484 page = mPageTable.back();
485 mPageTable.pop_back();
489 mPageTable.insert(mPageTable.end(), other.mPageTable.begin(), other.mPageTable.end());
490 mSize += other.mSize;
491 mCapacity = Page::Size*mPageTable.size();
494 PageTableT().swap(other.mPageTable);
496 if (page) this->add_partially_full(page, size);
500template <
typename ValueT,
size_t Log2PageSize>
503 assert(size == Page::Size);
504 if (mSize & Page::Mask) {
505 Page*& tmp = mPageTable.back();
506 std::swap(tmp, page);
508 mPageTable.push_back(page);
509 mCapacity += Page::Size;
514template <
typename ValueT,
size_t Log2PageSize>
515void PagedArray<ValueT, Log2PageSize>::add_partially_full(Page*& page,
size_t size)
517 assert(size > 0 && size < Page::Size);
518 if (
size_t m = mSize & Page::Mask) {
519 ValueT *s = page->data(), *t = mPageTable.back()->data() + m;
520 for (
size_t i=std::min(mSize+size, mCapacity)-mSize; i; --i) *t++ = *s++;
521 if (mSize+size > mCapacity) {
522 mPageTable.push_back(
new Page() );
523 t = mPageTable.back()->data();
524 for (
size_t i=mSize+size-mCapacity; i; --i) *t++ = *s++;
525 mCapacity += Page::Size;
528 mPageTable.push_back( page );
529 mCapacity += Page::Size;
538template <
typename ValueT,
size_t Log2PageSize>
559 (*mPage)[mSize++] = v;
560 if (mSize == Page::Size) this->flush();
568 mParent->add(mPage, mSize);
569 if (mPage ==
nullptr) mPage =
new Page();
575 size_t size()
const {
return mSize; }
576 static size_t pageSize() {
return 1UL << Log2PageSize; }
587template <
typename ValueT,
size_t Log2PageSize>
603 mParent=other.mParent;
613 const ValueT&
operator*()
const {
return (*mParent)[mPos]; }
614 const ValueT*
operator->()
const {
return &(this->operator*()); }
628 bool operator< (
const ConstIterator& other)
const {
return mPos < other.mPos; }
629 bool operator> (
const ConstIterator& other)
const {
return mPos > other.mPos; }
631 bool isValid()
const {
return mParent !=
nullptr && mPos < mParent->size(); }
632 size_t pos()
const {
return mPos; }
643template <
typename ValueT,
size_t Log2PageSize>
659 mParent=other.mParent;
684 bool operator< (
const Iterator& other)
const {
return mPos < other.mPos; }
685 bool operator> (
const Iterator& other)
const {
return mPos > other.mPos; }
687 bool isValid()
const {
return mParent !=
nullptr && mPos < mParent->size(); }
688 size_t pos()
const {
return mPos; }
697template <
typename ValueT,
size_t Log2PageSize>
702 static const size_t Size = 1UL << Log2PageSize;
703 static const size_t Mask = Size - 1UL;
704 static size_t memUsage() {
return sizeof(ValueT)*Size; }
706 Page() : mData(reinterpret_cast<ValueT*>(new char[sizeof(ValueT)*Size])) {}
710 ValueT&
operator[](
const size_t i) {
return mData[i & Mask]; }
711 const ValueT&
operator[](
const size_t i)
const {
return mData[i & Mask]; }
714 for (
size_t i=Size; i; --i) *dst++ = v;
716 ValueT*
data() {
return mData; }
720 const ValueT* src = mData;
721 for (
size_t i=n; i; --i) *dst++ = *src++;
Definition PagedArray.h:589
bool operator==(const ConstIterator &other) const
Definition PagedArray.h:624
const ValueT & operator[](const difference_type &pos) const
Definition PagedArray.h:615
bool operator>=(const ConstIterator &other) const
Definition PagedArray.h:626
ConstIterator operator+(const difference_type &pos) const
Definition PagedArray.h:619
friend ConstIterator operator+(const difference_type &pos, const ConstIterator &other)
Definition PagedArray.h:622
ValueT & reference
Definition PagedArray.h:595
ConstIterator & operator+=(const difference_type &pos)
Definition PagedArray.h:617
difference_type operator-(const ConstIterator &other) const
Definition PagedArray.h:621
ConstIterator & operator--()
Definition PagedArray.h:608
bool isValid() const
Definition PagedArray.h:631
ValueT * pointer
Definition PagedArray.h:594
std::random_access_iterator_tag iterator_category
Definition PagedArray.h:591
ConstIterator & operator-=(const difference_type &pos)
Definition PagedArray.h:618
ConstIterator operator-(const difference_type &pos) const
Definition PagedArray.h:620
bool operator!=(const ConstIterator &other) const
Definition PagedArray.h:625
size_t pos() const
Definition PagedArray.h:632
ConstIterator operator++(int)
Definition PagedArray.h:610
const ValueT & operator*() const
Definition PagedArray.h:613
std::ptrdiff_t difference_type
Definition PagedArray.h:593
const ValueT * operator->() const
Definition PagedArray.h:614
bool operator<=(const ConstIterator &other) const
Definition PagedArray.h:627
ConstIterator & operator++()
Definition PagedArray.h:607
ConstIterator(const PagedArray &parent, size_t pos=0)
Definition PagedArray.h:599
ValueT value_type
Definition PagedArray.h:592
ConstIterator & operator=(const ConstIterator &other)
Definition PagedArray.h:601
ConstIterator()
Definition PagedArray.h:598
ConstIterator operator--(int)
Definition PagedArray.h:611
ConstIterator(const ConstIterator &other)
Definition PagedArray.h:600
Definition PagedArray.h:645
bool operator>=(const Iterator &other) const
Definition PagedArray.h:682
Iterator()
Definition PagedArray.h:654
Iterator(const Iterator &other)
Definition PagedArray.h:656
ValueT & operator[](const difference_type &pos) const
Definition PagedArray.h:671
Iterator(PagedArray &parent, size_t pos=0)
Definition PagedArray.h:655
ValueT & reference
Definition PagedArray.h:651
ValueT * operator->() const
Definition PagedArray.h:670
Iterator & operator+=(const difference_type &pos)
Definition PagedArray.h:673
bool isValid() const
Definition PagedArray.h:687
Iterator operator+(const difference_type &pos) const
Definition PagedArray.h:675
ValueT & operator*() const
Definition PagedArray.h:669
friend Iterator operator+(const difference_type &pos, const Iterator &other)
Definition PagedArray.h:678
bool operator!=(const Iterator &other) const
Definition PagedArray.h:681
ValueT * pointer
Definition PagedArray.h:650
Iterator operator--(int)
Definition PagedArray.h:667
std::random_access_iterator_tag iterator_category
Definition PagedArray.h:647
Iterator & operator-=(const difference_type &pos)
Definition PagedArray.h:674
bool operator<=(const Iterator &other) const
Definition PagedArray.h:683
size_t pos() const
Definition PagedArray.h:688
difference_type operator-(const Iterator &other) const
Definition PagedArray.h:677
Iterator operator++(int)
Definition PagedArray.h:666
std::ptrdiff_t difference_type
Definition PagedArray.h:649
ValueT value_type
Definition PagedArray.h:648
Iterator & operator=(const Iterator &other)
Definition PagedArray.h:657
Iterator & operator++()
Definition PagedArray.h:663
Iterator & operator--()
Definition PagedArray.h:664
bool operator==(const Iterator &other) const
Definition PagedArray.h:680
Iterator operator-(const difference_type &pos) const
Definition PagedArray.h:676
Definition PagedArray.h:700
void copy(ValueType *dst, size_t n) const
Definition PagedArray.h:719
const ValueT & operator[](const size_t i) const
Definition PagedArray.h:711
ValueT & operator[](const size_t i)
Definition PagedArray.h:710
static size_t memUsage()
Definition PagedArray.h:704
~Page()
Definition PagedArray.h:707
ValueT * mData
Definition PagedArray.h:724
Page(const Page &)=delete
ValueT * data()
Definition PagedArray.h:716
Page()
Definition PagedArray.h:706
void fill(const ValueT &v)
Definition PagedArray.h:712
Page & operator=(const Page &)=delete
Definition PagedArray.h:541
size_t size() const
Return the current number of elements cached in this buffer.
Definition PagedArray.h:575
~ValueBuffer()
Destructor that transfers an buffered values to the parent PagedArray.
Definition PagedArray.h:550
ValueBuffer & operator=(const ValueBuffer &)=delete
void push_back(const ValueT &v)
Add a value to the buffer and increment the size.
Definition PagedArray.h:558
ValueBuffer(const ValueBuffer &other)
Definition PagedArray.h:548
PagedArrayType & parent() const
Return a reference to the parent PagedArray.
Definition PagedArray.h:573
void flush()
Manually transfers the values in this buffer to the parent PagedArray.
Definition PagedArray.h:567
ValueBuffer(PagedArray &parent)
Constructor from a PageArray.
Definition PagedArray.h:545
static size_t pageSize()
Definition PagedArray.h:576
Concurrent, page-based, dynamically-sized linear data structure with O(1) random access and STL-compl...
Definition PagedArray.h:144
ConstIterator cend() const
Return a const iterator pointing to the past-the-last element.
Definition PagedArray.h:389
size_t memUsage() const
Return the memory footprint of this array in bytes.
Definition PagedArray.h:340
static size_t log2PageSize()
Return log2 of the number of elements per memory page.
Definition PagedArray.h:337
Iterator begin()
Return a non-const iterator pointing to the first element.
Definition PagedArray.h:368
size_t size() const
Return the number of elements in this array.
Definition PagedArray.h:320
PagedArray(const PagedArray &)=delete
size_t push_back_unsafe(const ValueType &value)
Definition PagedArray.h:193
void copy(ValueType *p) const
Definition PagedArray.h:272
void sort()
Parallel sort of all the elements in ascending order.
Definition PagedArray.h:394
size_t pageCount() const
Return the number of allocated memory pages.
Definition PagedArray.h:331
void resize(size_t size)
Resize this array to the specified size.
Definition PagedArray.h:288
void sort(Functor func)
Parallel sort of all the elements based on a custom functor with the api:
Definition PagedArray.h:405
PagedArray()
Default constructor.
Definition PagedArray.h:157
void invSort()
Parallel sort of all the elements in descending order.
Definition PagedArray.h:397
ConstIterator end() const
Definition PagedArray.h:390
void fill(const ValueType &v)
Set all elements in the page table to the specified value.
Definition PagedArray.h:240
size_t freeCount() const
Return the number of additional elements that can be added to this array without allocating more memo...
Definition PagedArray.h:328
size_t capacity() const
Return the maximum number of elements that this array can contain without allocating more memory page...
Definition PagedArray.h:324
bool isPartiallyFull() const
Return true if the page table is partially full, i.e. the last non-empty page contains less than page...
Definition PagedArray.h:354
ValueT ValueType
Definition PagedArray.h:153
PagedArray & operator=(const PagedArray &)=delete
void resize(size_t size, const ValueType &v)
Resize this array to the specified size and initialize all values to v.
Definition PagedArray.h:313
ValueType & operator[](size_t i)
Return a reference to the value at the specified offset.
Definition PagedArray.h:216
ConstIterator cbegin() const
Return a const iterator pointing to the first element.
Definition PagedArray.h:379
~PagedArray()
Destructor removed all allocated pages.
Definition PagedArray.h:160
Iterator end()
Return a non-const iterator pointing to the past-the-last element.
Definition PagedArray.h:375
bool copy(ValueType *p, size_t count) const
Copy the first count values in this PageArray into a raw c-style array, assuming it to be at least co...
Definition PagedArray.h:255
ValueBuffer getBuffer()
Definition PagedArray.h:180
SharedPtr< PagedArray > Ptr
Definition PagedArray.h:154
void clear()
Removes all elements from the array and delete all pages.
Definition PagedArray.h:359
bool isEmpty() const
Return true if the container contains no elements.
Definition PagedArray.h:346
const ValueType & operator[](size_t i) const
Return a const-reference to the value at the specified offset.
Definition PagedArray.h:229
ConstIterator begin() const
Definition PagedArray.h:380
static Ptr create()
Return a shared pointer to a new instance of this class.
Definition PagedArray.h:167
void print(std::ostream &os=std::cout) const
Print information for debugging.
Definition PagedArray.h:418
static size_t pageSize()
Return the number of elements per memory page.
Definition PagedArray.h:334
std::shared_ptr< T > SharedPtr
Definition Types.h:114
Definition Exceptions.h:13
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212