pw_vector: Add missing modifier member functions
- Implement insert and erase functions.
Bug: b/234872989
Change-Id: I8a06daee877f7661f137451bb58aee310593eadd
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/126610
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Viktor Elizarov <elizarovv@google.com>
diff --git a/pw_containers/public/pw_containers/vector.h b/pw_containers/public/pw_containers/vector.h
index 853e1eb..62ebc8a 100644
--- a/pw_containers/public/pw_containers/vector.h
+++ b/pw_containers/public/pw_containers/vector.h
@@ -327,26 +327,28 @@
void clear() noexcept;
- // TODO(hepler): insert, emplace, and erase are not yet implemented.
- // Currently, items can only be added to or removed from the end.
- iterator insert(const_iterator index, const T& value);
+ iterator insert(const_iterator index, size_type count, const T& value);
+
+ iterator insert(const_iterator index, const T& value) {
+ return insert(index, 1, value);
+ }
iterator insert(const_iterator index, T&& value);
- iterator insert(const_iterator index, size_type count, const T& value);
-
template <typename Iterator>
iterator insert(const_iterator index, Iterator first, Iterator last);
- iterator insert(const_iterator index, std::initializer_list<T> list);
+ iterator insert(const_iterator index, std::initializer_list<T> list) {
+ return insert(index, list.begin(), list.end());
+ }
template <typename... Args>
iterator emplace(const_iterator index, Args&&... args);
- iterator erase(const_iterator index);
-
iterator erase(const_iterator first, const_iterator last);
+ iterator erase(const_iterator index) { return erase(index, index + 1); }
+
void push_back(const T& value) { emplace_back(value); }
void push_back(T&& value) { emplace_back(std::move(value)); }
@@ -446,8 +448,10 @@
template <typename T>
void Vector<T, vector_impl::kGeneric>::clear() noexcept {
- for (auto& item : *this) {
- item.~T();
+ if constexpr (!std::is_trivially_destructible_v<value_type>) {
+ for (auto& item : *this) {
+ item.~T();
+ }
}
size_ = 0;
}
@@ -464,7 +468,9 @@
template <typename T>
void Vector<T, vector_impl::kGeneric>::pop_back() {
if (!empty()) {
- back().~T();
+ if constexpr (!std::is_trivially_destructible_v<value_type>) {
+ back().~T();
+ }
size_ -= 1;
}
}
@@ -482,6 +488,110 @@
}
template <typename T>
+typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
+ T&& value) {
+ PW_DASSERT(index >= cbegin());
+ PW_DASSERT(index <= cend());
+ PW_DASSERT(!full());
+
+ iterator insertion_point = begin() + std::distance(cbegin(), index);
+ if (insertion_point == end()) {
+ emplace_back(std::move(value));
+ return insertion_point;
+ }
+
+ std::move_backward(insertion_point, end(), end() + 1);
+ *insertion_point = std::move(value);
+ ++size_;
+
+ // Return an iterator pointing to the inserted value.
+ return insertion_point;
+}
+
+template <typename T>
+template <typename Iterator>
+typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
+ Iterator first,
+ Iterator last) {
+ PW_DASSERT(index >= cbegin());
+ PW_DASSERT(index <= cend());
+ PW_DASSERT(!full());
+
+ iterator insertion_point = begin() + std::distance(cbegin(), index);
+
+ const size_t insertion_count = std::distance(first, last);
+ if (insertion_count == 0) {
+ return insertion_point;
+ }
+ PW_DASSERT(size() + insertion_count <= max_size());
+
+ iterator return_value = insertion_point;
+
+ if (insertion_point != end()) {
+ std::move_backward(insertion_point, end(), end() + insertion_count);
+ }
+
+ while (first != last) {
+ *insertion_point = *first;
+ ++first;
+ ++insertion_point;
+ }
+ size_ += insertion_count;
+
+ // Return an iterator pointing to the first element inserted.
+ return return_value;
+}
+
+template <typename T>
+typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
+ size_type count,
+ const T& value) {
+ PW_DASSERT(index >= cbegin());
+ PW_DASSERT(index <= cend());
+ PW_DASSERT(size() + count <= max_size());
+
+ iterator insertion_point = begin() + std::distance(cbegin(), index);
+ if (count == size_type{}) {
+ return insertion_point;
+ }
+
+ if (insertion_point != end()) {
+ std::move_backward(insertion_point, end(), end() + count);
+ }
+
+ iterator return_value = insertion_point;
+
+ for (size_type final_count = size_ + count; size_ != final_count; ++size_) {
+ *insertion_point = value;
+ ++insertion_point;
+ }
+
+ // Return an iterator pointing to the first element inserted.
+ return return_value;
+}
+
+template <typename T>
+typename Vector<T>::iterator Vector<T>::erase(Vector<T>::const_iterator first,
+ Vector<T>::const_iterator last) {
+ iterator source = begin() + std::distance(cbegin(), last);
+ if (first == last) {
+ return source;
+ }
+
+ if constexpr (!std::is_trivially_destructible_v<T>) {
+ std::destroy(first, last);
+ }
+
+ iterator destination = begin() + std::distance(cbegin(), first);
+ iterator new_end = std::move(source, end(), destination);
+
+ size_ = std::distance(begin(), new_end);
+
+ // Return an iterator following the last removed element.
+ return new_end;
+}
+
+template <typename T>
template <typename Iterator>
void Vector<T, vector_impl::kGeneric>::CopyFrom(Iterator first, Iterator last) {
while (first != last) {
diff --git a/pw_containers/vector_test.cc b/pw_containers/vector_test.cc
index e90da6f..4bde247 100644
--- a/pw_containers/vector_test.cc
+++ b/pw_containers/vector_test.cc
@@ -76,6 +76,19 @@
moved += 1;
}
+ Counter& operator=(const Counter& other) {
+ value = other.value;
+ created += 1;
+ return *this;
+ }
+
+ Counter& operator=(Counter&& other) {
+ value = other.value;
+ other.value = 0;
+ moved += 1;
+ return *this;
+ }
+
~Counter() { destroyed += 1; }
int value;
@@ -467,6 +480,212 @@
EXPECT_EQ(vector.size(), 0u);
}
+TEST(Vector, Modify_Erase_TrivialRangeBegin) {
+ Vector<size_t, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(i);
+ }
+
+ vector.erase(vector.begin() + 2, vector.end());
+ EXPECT_EQ(vector.size(), 2u);
+
+ for (size_t i = 0; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i], i);
+ }
+}
+
+TEST(Vector, Modify_Erase_TrivialRangeEnd) {
+ Vector<size_t, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(i);
+ }
+
+ vector.erase(vector.begin(), vector.end() - 2);
+ EXPECT_EQ(vector.size(), 2u);
+
+ for (size_t i = 0; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i], 8u + i);
+ }
+}
+
+TEST(Vector, Modify_Erase_TrivialSingleItem) {
+ Vector<size_t, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(i);
+ }
+
+ vector.erase(vector.begin() + 9);
+
+ EXPECT_EQ(vector.size(), 9u);
+ EXPECT_EQ(vector.at(8), 8u);
+ EXPECT_EQ(vector.at(0), 0u);
+
+ vector.erase(vector.begin());
+ EXPECT_EQ(vector.size(), 8u);
+ EXPECT_EQ(vector.at(0), 1u);
+}
+
+TEST(Vector, Modify_Erase_NonTrivialRangeBegin) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(static_cast<int>(i));
+ }
+
+ for (size_t i = 0; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i].value, static_cast<int>(i));
+ }
+
+ vector.erase(vector.begin() + 2, vector.end());
+ EXPECT_EQ(vector.size(), 2u);
+
+ for (size_t i = 0; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i].value, static_cast<int>(i));
+ }
+
+ EXPECT_EQ(Counter::destroyed, 8);
+ EXPECT_EQ(Counter::moved, 0);
+}
+
+TEST(Vector, Modify_Erase_NonTrivialRangeEnd) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(static_cast<int>(i));
+ }
+
+ vector.erase(vector.begin(), vector.end() - 2);
+ EXPECT_EQ(vector.size(), 2u);
+
+ for (size_t i = 0; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i].value, static_cast<int>(8u + i));
+ }
+
+ EXPECT_EQ(Counter::destroyed, 8);
+ EXPECT_EQ(Counter::moved, 2);
+}
+
+TEST(Vector, Modify_Erase_None) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ vector.emplace_back(static_cast<int>(i));
+ }
+
+ vector.erase(vector.begin() + 2, vector.begin() + 2);
+ EXPECT_EQ(vector.size(), 10u);
+
+ EXPECT_EQ(Counter::destroyed, 0);
+ EXPECT_EQ(Counter::moved, 0);
+ EXPECT_EQ(Counter::created, 10);
+}
+
+TEST(Vector, Modify_Insert_End) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ for (size_t i = 0; i < 8u; ++i) {
+ vector.emplace_back(static_cast<int>(i));
+ }
+
+ EXPECT_EQ(vector.size(), 8u);
+ EXPECT_EQ(Counter::created, 8);
+
+ decltype(vector)::iterator it = vector.insert(vector.cend(), 8);
+ EXPECT_EQ(it->value, 8);
+ EXPECT_EQ(vector.at(8).value, 8);
+
+ EXPECT_EQ(Counter::destroyed, 1);
+ EXPECT_EQ(Counter::moved, 1);
+ EXPECT_EQ(Counter::created, 9);
+}
+
+TEST(Vector, Modify_Insert_Begin) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ for (size_t i = 0; i < 8u; ++i) {
+ vector.emplace_back(static_cast<int>(i));
+ }
+
+ EXPECT_EQ(vector.size(), 8u);
+
+ decltype(vector)::iterator it = vector.insert(vector.cbegin(), 123);
+ EXPECT_EQ(it->value, 123);
+ EXPECT_EQ(vector.at(0).value, 123);
+ EXPECT_EQ(vector.at(8).value, 7);
+
+ EXPECT_EQ(Counter::moved, 9);
+}
+
+TEST(Vector, Modify_Insert_CountCopies) {
+ Counter::Reset();
+ Vector<Counter, 10> vector;
+
+ vector.emplace_back(123);
+ vector.insert(vector.cbegin() + 1, 8, Counter{421});
+ EXPECT_EQ(vector.at(0).value, 123);
+ EXPECT_EQ(vector.size(), 9u);
+
+ for (size_t i = 1; i < vector.size(); ++i) {
+ EXPECT_EQ(vector[i].value, 421);
+ }
+
+ EXPECT_EQ(Counter::moved, 0);
+ EXPECT_EQ(Counter::created, 10);
+}
+
+TEST(Vector, Modify_Insert_IteratorRange) {
+ std::array array_to_insert_first{0, 1, 2, 8, 9};
+ std::array array_to_insert_middle{3, 4, 5, 6, 7};
+
+ Vector<int, 10> vector(array_to_insert_first.begin(),
+ array_to_insert_first.end());
+
+ decltype(vector)::iterator it = vector.insert(vector.cbegin() + 3,
+ array_to_insert_middle.begin(),
+ array_to_insert_middle.end());
+ EXPECT_EQ(*it, array_to_insert_middle.front());
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ EXPECT_EQ(vector[i], static_cast<int>(i));
+ }
+}
+
+TEST(Vector, Modify_Insert_InitializerListRange) {
+ std::array array_to_insert_first{0, 1, 2, 8, 9};
+ Vector<int, 10> vector(array_to_insert_first.begin(),
+ array_to_insert_first.end());
+
+ decltype(vector)::iterator it =
+ vector.insert(vector.cbegin() + 3, {3, 4, 5, 6, 7});
+ EXPECT_EQ(*it, 3);
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ EXPECT_EQ(vector[i], static_cast<int>(i));
+ }
+}
+
+TEST(Vector, Modify_Insert_NonTrivial_InitializerListRange) {
+ std::array<Counter, 5> array_to_insert_first{0, 1, 2, 8, 9};
+ Vector<Counter, 10> vector(array_to_insert_first.begin(),
+ array_to_insert_first.end());
+
+ decltype(vector)::iterator it = vector.insert(
+ vector.cbegin() + 3, std::initializer_list<Counter>{3, 4, 5, 6, 7});
+ EXPECT_EQ(it->value, 3);
+
+ for (size_t i = 0; i < vector.max_size(); ++i) {
+ EXPECT_EQ(vector[i].value, static_cast<int>(i));
+ }
+}
+
TEST(Vector, Generic) {
Vector<int, 10> vector{1, 2, 3, 4, 5};