diff options
| author | YDBot <[email protected]> | 2026-07-03 01:08:31 +0000 |
|---|---|---|
| committer | YDBot <[email protected]> | 2026-07-03 01:08:31 +0000 |
| commit | 4aef9bc8df0dbce3f6c80af0d30be15a42395c93 (patch) | |
| tree | f061f46278c336ab3d9e20328e26f782409b9eab /library/cpp | |
| parent | fe803e594382bb48f98279e6ba7299555ae0c41d (diff) | |
| parent | 9ee725581e8d8fe81cadd3d093e0477120c84328 (diff) | |
Sync branches 260703-0106
Diffstat (limited to 'library/cpp')
| -rw-r--r-- | library/cpp/containers/paged_vector/paged_vector.h | 60 | ||||
| -rw-r--r-- | library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp | 117 |
2 files changed, 154 insertions, 23 deletions
diff --git a/library/cpp/containers/paged_vector/paged_vector.h b/library/cpp/containers/paged_vector/paged_vector.h index 3a2c58caf7b..96be0042e0a 100644 --- a/library/cpp/containers/paged_vector/paged_vector.h +++ b/library/cpp/containers/paged_vector/paged_vector.h @@ -147,13 +147,15 @@ namespace std { namespace NPagedVector { //2-level radix tree template <class T, ui32 PageSize, class A> - class TPagedVector: private TVector<TSimpleSharedPtr<TVector<T, A>>, A> { + class TPagedVector { static_assert(PageSize, "expect PageSize"); typedef TVector<T, A> TPage; - typedef TVector<TSimpleSharedPtr<TPage>, A> TPages; + typedef TVector<THolder<TPage>, A> TPages; typedef TPagedVector<T, PageSize, A> TSelf; + TPages Pages_; + public: typedef NPrivate::TPagedVectorIterator<T, T, PageSize, A> iterator; typedef NPrivate::TPagedVectorIterator<const T, T, PageSize, A> const_iterator; @@ -164,12 +166,30 @@ namespace NPagedVector { typedef const value_type& const_reference; TPagedVector() = default; + TPagedVector(TPagedVector&& other) noexcept = default; + + TPagedVector(const TPagedVector& other) { + Pages_.reserve(other.Pages_.size()); + for (auto& ptr : other.Pages_) { + Pages_.emplace_back(MakeHolder<TPage>(*ptr)); + } + } template <typename TIter> TPagedVector(TIter b, TIter e) { append(b, e); } + TPagedVector& operator=(const TPagedVector& other) { + if (this != &other) { + TPagedVector tmp(other); + swap(tmp); + } + return *this; + } + + TPagedVector& operator=(TPagedVector&& other) noexcept = default; + iterator begin() { return iterator(this, 0); } @@ -203,7 +223,7 @@ namespace NPagedVector { } void swap(TSelf& v) { - TPages::swap((TPages&)v); + Pages_.swap(v.Pages_); } private: @@ -220,23 +240,23 @@ namespace NPagedVector { } TPage& PageAt(size_t pnum) const { - return *TPages::at(pnum); + return *Pages_.at(pnum); } TPage& CurrentPage() const { - return *TPages::back(); + return *Pages_.back(); } size_t CurrentPageSize() const { - return TPages::empty() ? 0 : CurrentPage().size(); + return Pages_.empty() ? 0 : CurrentPage().size(); } size_t NPages() const { - return TPages::size(); + return Pages_.size(); } void AllocateNewPage() { - TPages::push_back(new TPage()); + Pages_.emplace_back(MakeHolder<TPage>()); CurrentPage().reserve(PageSize); } @@ -246,7 +266,7 @@ namespace NPagedVector { } void PrepareAppend() { - if (TPages::empty() || CurrentPage().size() + 1 > PageSize) + if (Pages_.empty() || CurrentPage().size() + 1 > PageSize) AllocateNewPage(); } @@ -256,7 +276,7 @@ namespace NPagedVector { } bool empty() const { - return TPages::empty() || (1 == NPages() && CurrentPage().empty()); + return Pages_.empty() || (1 == NPages() && CurrentPage().empty()); } explicit operator bool() const noexcept { @@ -276,7 +296,7 @@ namespace NPagedVector { void pop_back() { if (CurrentPage().empty()) - TPages::pop_back(); + Pages_.pop_back(); CurrentPage().pop_back(); } @@ -311,7 +331,7 @@ namespace NPagedVector { size_t pidx = InPageIndex(it.Offset); if (CurrentPage().empty()) - TPages::pop_back(); + Pages_.pop_back(); for (size_t p = NPages() - 1; p > pnum; --p) { PageAt(p - 1).push_back(PageAt(p).front()); @@ -355,11 +375,11 @@ namespace NPagedVector { } reference front() { - return TPages::front()->front(); + return Pages_.front()->front(); } const_reference front() const { - return TPages::front()->front(); + return Pages_.front()->front(); } reference back() { @@ -371,7 +391,7 @@ namespace NPagedVector { } void clear() { - TPages::clear(); + Pages_.clear(); } void resize(size_t sz) { @@ -387,7 +407,7 @@ namespace NPagedVector { CurrentPage().resize(PageSize); if (newpages < npages) - TPages::resize(newpages); + Pages_.resize(newpages); else for (size_t i = npages; i < newpages; ++i) MakeNewPage(); @@ -399,19 +419,19 @@ namespace NPagedVector { } reference at(size_t idx) { - return TPages::at(PageNumber(idx))->at(InPageIndex(idx)); + return Pages_.at(PageNumber(idx))->at(InPageIndex(idx)); } const_reference at(size_t idx) const { - return TPages::at(PageNumber(idx))->at(InPageIndex(idx)); + return Pages_.at(PageNumber(idx))->at(InPageIndex(idx)); } reference operator[](size_t idx) { - return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx)); + return Pages_.operator[](PageNumber(idx))->operator[](InPageIndex(idx)); } const_reference operator[](size_t idx) const { - return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx)); + return Pages_.operator[](PageNumber(idx))->operator[](InPageIndex(idx)); } friend bool operator==(const TSelf& a, const TSelf& b) { diff --git a/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp b/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp index d059ce34ec1..54e4b71fa70 100644 --- a/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp +++ b/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp @@ -18,7 +18,11 @@ class TPagedVectorTest: public TTestBase { UNIT_TEST(TestIterators) UNIT_TEST(TestEmplaceBack1) UNIT_TEST(TestEmplaceBack2) - //UNIT_TEST(TestEbo) + UNIT_TEST(TestCopyConstructor) + UNIT_TEST(TestCopyAssignment) + UNIT_TEST(TestMoveConstructor) + UNIT_TEST(TestMoveAssignment) + // UNIT_TEST(TestEbo) UNIT_TEST_SUITE_END(); private: @@ -376,9 +380,116 @@ private: } } + void TestCopyConstructor() { + using NPagedVector::TPagedVector; + TPagedVector<int, 3> v; + for (int i = 0; i < 10; ++i) { + v.push_back(i); + } + + TPagedVector<int, 3> copied(v); + + UNIT_ASSERT_VALUES_EQUAL(copied.size(), 10u); + UNIT_ASSERT_VALUES_EQUAL(v.size(), 10u); + + for (int i = 0; i < 10; ++i) { + // values are the same + UNIT_ASSERT_VALUES_EQUAL(v[i], i); + UNIT_ASSERT_VALUES_EQUAL(copied[i], i); + + // but pointers are different (the elements have been copied) + UNIT_ASSERT_VALUES_UNEQUAL(&copied[i], &v[i]); + } + + // Modifying the copy must not affect the original. + copied[0] = 999; + UNIT_ASSERT_VALUES_EQUAL(v[0], 0); + } + + void TestCopyAssignment() { + using NPagedVector::TPagedVector; + TPagedVector<int, 3> v; + for (int i = 0; i < 10; ++i) { + v.push_back(i); + } + + TPagedVector<int, 3> assigned; + assigned.push_back(999); + assigned = v; + + // The source vector should remain unchanged after copy. + UNIT_ASSERT_VALUES_EQUAL(v.size(), 10u); + + UNIT_ASSERT_VALUES_EQUAL(assigned.size(), 10u); + for (int i = 0; i < 10; ++i) { + // values are the same + UNIT_ASSERT_VALUES_EQUAL(v[i], i); + UNIT_ASSERT_VALUES_EQUAL(assigned[i], i); + + // but pointers are different (the elements have been copied) + UNIT_ASSERT_VALUES_UNEQUAL(&assigned[i], &v[i]); + } + + // Modifying the assigned vector must not affect the original. + assigned[0] = 999; + UNIT_ASSERT_VALUES_EQUAL(v[0], 0); + } + + void TestMoveConstructor() { + using NPagedVector::TPagedVector; + TPagedVector<int, 3> v; + for (int i = 0; i < 10; ++i) { + v.push_back(i); + } + + auto orig_ptr = &v[5]; + + TPagedVector<int, 3> moved(std::move(v)); + + UNIT_ASSERT_VALUES_EQUAL(moved.size(), 10u); + + // the move must keep original element pointers + UNIT_ASSERT_VALUES_EQUAL(orig_ptr, &moved[5]); + + for (int i = 0; i < 10; ++i) { + UNIT_ASSERT_VALUES_EQUAL(moved[i], i); + } + + // After move, the source vector should be empty. + UNIT_ASSERT(v.empty()); + UNIT_ASSERT_VALUES_EQUAL(v.size(), 0u); + } + + void TestMoveAssignment() { + using NPagedVector::TPagedVector; + TPagedVector<int, 3> v; + for (int i = 0; i < 10; ++i) { + v.push_back(i); + } + + auto orig_ptr = &v[7]; + + TPagedVector<int, 3> assigned; + assigned.push_back(999); + assigned = std::move(v); + + UNIT_ASSERT_VALUES_EQUAL(assigned.size(), 10u); + + // the move must keep original element pointers + UNIT_ASSERT_VALUES_EQUAL(orig_ptr, &assigned[7]); + + for (int i = 0; i < 10; ++i) { + UNIT_ASSERT_VALUES_EQUAL(assigned[i], i); + } + + // After move, the source vector should be empty. + UNIT_ASSERT(v.empty()); + UNIT_ASSERT_VALUES_EQUAL(v.size(), 0u); + } + /* This test check a potential issue with empty base class - * optimization. Some compilers (VC6) do not implement it - * correctly resulting ina wrong behavior. */ + * optimization. Some compilers (VC6) do not implement it + * correctly resulting ina wrong behavior. */ void TestEbo() { using NPagedVector::TPagedVector; // We use heap memory as test failure can corrupt vector internal |
