summaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorYDBot <[email protected]>2026-07-03 01:08:31 +0000
committerYDBot <[email protected]>2026-07-03 01:08:31 +0000
commit4aef9bc8df0dbce3f6c80af0d30be15a42395c93 (patch)
treef061f46278c336ab3d9e20328e26f782409b9eab /library/cpp
parentfe803e594382bb48f98279e6ba7299555ae0c41d (diff)
parent9ee725581e8d8fe81cadd3d093e0477120c84328 (diff)
Sync branches 260703-0106
Diffstat (limited to 'library/cpp')
-rw-r--r--library/cpp/containers/paged_vector/paged_vector.h60
-rw-r--r--library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp117
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