aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/containers/paged_vector/paged_vector.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/containers/paged_vector/paged_vector.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/containers/paged_vector/paged_vector.h')
-rw-r--r--library/cpp/containers/paged_vector/paged_vector.h432
1 files changed, 432 insertions, 0 deletions
diff --git a/library/cpp/containers/paged_vector/paged_vector.h b/library/cpp/containers/paged_vector/paged_vector.h
new file mode 100644
index 0000000000..6a3657d3ea
--- /dev/null
+++ b/library/cpp/containers/paged_vector/paged_vector.h
@@ -0,0 +1,432 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <iterator>
+
+namespace NPagedVector {
+ template <class T, ui32 PageSize = 1u << 20, class A = std::allocator<T>>
+ class TPagedVector;
+
+ namespace NPrivate {
+ template <class T, class TT, ui32 PageSize, class A>
+ struct TPagedVectorIterator {
+ private:
+ friend class TPagedVector<TT, PageSize, A>;
+ typedef TPagedVector<TT, PageSize, A> TVec;
+ typedef TPagedVectorIterator<T, TT, PageSize, A> TSelf;
+ size_t Offset;
+ TVec* Vector;
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ friend struct TPagedVectorIterator;
+
+ public:
+ TPagedVectorIterator()
+ : Offset()
+ , Vector()
+ {
+ }
+
+ TPagedVectorIterator(TVec* vector, size_t offset)
+ : Offset(offset)
+ , Vector(vector)
+ {
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ TPagedVectorIterator(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it)
+ : Offset(it.Offset)
+ , Vector(it.Vector)
+ {
+ }
+
+ T& operator*() const {
+ return (*Vector)[Offset];
+ }
+
+ T* operator->() const {
+ return &(**this);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator==(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset == it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator!=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this == it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator<(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset < it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator<=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset <= it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator>(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this <= it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator>=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this < it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ ptrdiff_t operator-(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset - it.Offset;
+ }
+
+ TSelf& operator+=(ptrdiff_t off) {
+ Offset += off;
+ return *this;
+ }
+
+ TSelf& operator-=(ptrdiff_t off) {
+ return this->operator+=(-off);
+ }
+
+ TSelf& operator++() {
+ return this->operator+=(1);
+ }
+
+ TSelf& operator--() {
+ return this->operator+=(-1);
+ }
+
+ TSelf operator++(int) {
+ TSelf it = *this;
+ this->operator+=(1);
+ return it;
+ }
+
+ TSelf operator--(int) {
+ TSelf it = *this;
+ this->operator+=(-1);
+ return it;
+ }
+
+ TSelf operator+(ptrdiff_t off) {
+ TSelf res = *this;
+ res += off;
+ return res;
+ }
+
+ TSelf operator-(ptrdiff_t off) {
+ return this->operator+(-off);
+ }
+
+ size_t GetOffset() {
+ return Offset;
+ }
+ };
+ }
+}
+
+namespace std {
+ template <class T, class TT, ui32 PageSize, class A>
+ struct iterator_traits<NPagedVector::NPrivate::TPagedVectorIterator<T, TT, PageSize, A>> {
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef random_access_iterator_tag iterator_category;
+ };
+
+}
+
+namespace NPagedVector {
+ //2-level radix tree
+ template <class T, ui32 PageSize, class A>
+ class TPagedVector: private TVector<TSimpleSharedPtr<TVector<T, A>>, A> {
+ static_assert(PageSize, "expect PageSize");
+
+ typedef TVector<T, A> TPage;
+ typedef TVector<TSimpleSharedPtr<TPage>, A> TPages;
+ typedef TPagedVector<T, PageSize, A> TSelf;
+
+ public:
+ typedef NPrivate::TPagedVectorIterator<T, T, PageSize, A> iterator;
+ typedef NPrivate::TPagedVectorIterator<const T, T, PageSize, A> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef T value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ TPagedVector() = default;
+
+ template <typename TIter>
+ TPagedVector(TIter b, TIter e) {
+ append(b, e);
+ }
+
+ iterator begin() {
+ return iterator(this, 0);
+ }
+
+ const_iterator begin() const {
+ return const_iterator((TSelf*)this, 0);
+ }
+
+ iterator end() {
+ return iterator(this, size());
+ }
+
+ const_iterator end() const {
+ return const_iterator((TSelf*)this, size());
+ }
+
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ void swap(TSelf& v) {
+ TPages::swap((TPages&)v);
+ }
+
+ private:
+ static size_t PageNumber(size_t idx) {
+ return idx / PageSize;
+ }
+
+ static size_t InPageIndex(size_t idx) {
+ return idx % PageSize;
+ }
+
+ static size_t Index(size_t pnum, size_t poff) {
+ return pnum * PageSize + poff;
+ }
+
+ TPage& PageAt(size_t pnum) const {
+ return *TPages::at(pnum);
+ }
+
+ TPage& CurrentPage() const {
+ return *TPages::back();
+ }
+
+ size_t CurrentPageSize() const {
+ return TPages::empty() ? 0 : CurrentPage().size();
+ }
+
+ size_t NPages() const {
+ return TPages::size();
+ }
+
+ void AllocateNewPage() {
+ TPages::push_back(new TPage());
+ CurrentPage().reserve(PageSize);
+ }
+
+ void MakeNewPage() {
+ AllocateNewPage();
+ CurrentPage().resize(PageSize);
+ }
+
+ void PrepareAppend() {
+ if (TPages::empty() || CurrentPage().size() + 1 > PageSize)
+ AllocateNewPage();
+ }
+
+ public:
+ size_t size() const {
+ return empty() ? 0 : (NPages() - 1) * PageSize + CurrentPage().size();
+ }
+
+ bool empty() const {
+ return TPages::empty() || 1 == NPages() && CurrentPage().empty();
+ }
+
+ explicit operator bool() const noexcept {
+ return !empty();
+ }
+
+ void emplace_back() {
+ PrepareAppend();
+ CurrentPage().emplace_back();
+ }
+
+ void push_back(const_reference t) {
+ PrepareAppend();
+ CurrentPage().push_back(t);
+ }
+
+ void pop_back() {
+ if (CurrentPage().empty())
+ TPages::pop_back();
+ CurrentPage().pop_back();
+ }
+
+ template <typename TIter>
+ void append(TIter b, TIter e) {
+ size_t sz = e - b;
+ size_t sz1 = Min<size_t>(sz, PageSize - CurrentPageSize());
+ size_t sz2 = (sz - sz1) / PageSize;
+ size_t sz3 = (sz - sz1) % PageSize;
+
+ if (sz1) {
+ PrepareAppend();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b, b + sz1);
+ }
+
+ for (size_t i = 0; i < sz2; ++i) {
+ AllocateNewPage();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b + sz1 + i * PageSize, b + sz1 + (i + 1) * PageSize);
+ }
+
+ if (sz3) {
+ AllocateNewPage();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b + sz1 + sz2 * PageSize, e);
+ }
+ }
+
+ iterator erase(iterator it) {
+ size_t pnum = PageNumber(it.Offset);
+ size_t pidx = InPageIndex(it.Offset);
+
+ if (CurrentPage().empty())
+ TPages::pop_back();
+
+ for (size_t p = NPages() - 1; p > pnum; --p) {
+ PageAt(p - 1).push_back(PageAt(p).front());
+ PageAt(p).erase(PageAt(p).begin());
+ }
+
+ PageAt(pnum).erase(PageAt(pnum).begin() + pidx);
+ return it;
+ }
+
+ iterator erase(iterator b, iterator e) {
+ // todo : suboptimal!
+ while (b != e) {
+ b = erase(b);
+ --e;
+ }
+
+ return b;
+ }
+
+ iterator insert(iterator it, const value_type& v) {
+ size_t pnum = PageNumber(it.Offset);
+ size_t pidx = InPageIndex(it.Offset);
+
+ PrepareAppend();
+
+ for (size_t p = NPages() - 1; p > pnum; --p) {
+ PageAt(p).insert(PageAt(p).begin(), PageAt(p - 1).back());
+ PageAt(p - 1).pop_back();
+ }
+
+ PageAt(pnum).insert(PageAt(pnum).begin() + pidx, v);
+ return it;
+ }
+
+ template <typename TIter>
+ void insert(iterator it, TIter b, TIter e) {
+ // todo : suboptimal!
+ for (; b != e; ++b, ++it)
+ it = insert(it, *b);
+ }
+
+ reference front() {
+ return TPages::front()->front();
+ }
+
+ const_reference front() const {
+ return TPages::front()->front();
+ }
+
+ reference back() {
+ return CurrentPage().back();
+ }
+
+ const_reference back() const {
+ return CurrentPage().back();
+ }
+
+ void clear() {
+ TPages::clear();
+ }
+
+ void resize(size_t sz) {
+ if (sz == size())
+ return;
+
+ const size_t npages = NPages();
+ const size_t newwholepages = sz / PageSize;
+ const size_t pagepart = sz % PageSize;
+ const size_t newpages = newwholepages + bool(pagepart);
+
+ if (npages && newwholepages >= npages)
+ CurrentPage().resize(PageSize);
+
+ if (newpages < npages)
+ TPages::resize(newpages);
+ else
+ for (size_t i = npages; i < newpages; ++i)
+ MakeNewPage();
+
+ if (pagepart)
+ CurrentPage().resize(pagepart);
+
+ Y_VERIFY(sz == size(), "%" PRIu64 " %" PRIu64, (ui64)sz, (ui64)size());
+ }
+
+ reference at(size_t idx) {
+ return TPages::at(PageNumber(idx))->at(InPageIndex(idx));
+ }
+
+ const_reference at(size_t idx) const {
+ return TPages::at(PageNumber(idx))->at(InPageIndex(idx));
+ }
+
+ reference operator[](size_t idx) {
+ return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx));
+ }
+
+ const_reference operator[](size_t idx) const {
+ return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx));
+ }
+
+ friend bool operator==(const TSelf& a, const TSelf& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+ }
+
+ friend bool operator<(const TSelf& a, const TSelf& b) {
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+ }
+ };
+
+ namespace NPrivate {
+ typedef std::is_same<std::random_access_iterator_tag, std::iterator_traits<
+ TPagedVector<ui32>::iterator>::iterator_category>
+ TIteratorCheck;
+ static_assert(TIteratorCheck::value, "expect TIteratorCheck::Result");
+ }
+
+}