diff --git a/source/tinystl/container/vector.h b/source/tinystl/container/vector.h index 1443f2b..3aefcce 100644 --- a/source/tinystl/container/vector.h +++ b/source/tinystl/container/vector.h @@ -23,8 +23,8 @@ class vector { using const_pointer = const T *; using iterator = T *; using const_iterator = const T *; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; // construct/copy/destroy vector() noexcept(noexcept(Alloc())); @@ -122,12 +122,13 @@ class vector { void resize(size_type n); void resize(size_type n, const_reference val); void swap(vector &other) noexcept( - alloc_traits::propagate_on_container_swap::val || - alloc_traits::is_always_equal::val + alloc_traits::propagate_on_container_swap::value || + alloc_traits::is_always_equal::value ); private: void throw_length_error(); + void throw_out_of_range(); size_type recommend(size_type new_size); @@ -152,19 +153,33 @@ class vector { }; template -bool operator==(const vector &lhs, const vector &rhs); +bool operator==(const vector &lhs, const vector &rhs) { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} template -auto operator<=>(const vector &lhs, const vector &rhs); +auto operator<=>(const vector &lhs, const vector &rhs) { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::compare_three_way()); +} template -void swap(vector &lhs, vector &rhs) noexcept; +void swap(vector &lhs, vector &rhs) noexcept { + lhs.swap(rhs); +} template -typename vector::size_type erase(vector &c, const U &val); +typename vector::size_type erase(vector &c, const U &val) { + typename vector::size_type old_sz = c.size(); + c.erase(std::remove(c.begin(), c.end(), val), c.end()); + return old_sz - c.size(); +} template -typename vector::size_type erase_if(vector &c, Pred pred); +typename vector::size_type erase_if(vector &c, Pred pred) { + typename vector::size_type old_sz = c.size(); + c.erase(std::remove_if(c.begin(), c.end(), pred), c.end()); + return old_sz - c.size(); +} /* -------------------------------------------------------------------------- */ /* public member functions */ @@ -419,7 +434,7 @@ Alloc vector::get_allocator() const { template typename vector::reference vector::at(size_type pos) { if (pos >= this->size()) { - this->throw_length_error(); + this->throw_out_of_range(); } return m_begin[pos]; } @@ -428,7 +443,7 @@ template typename vector::const_reference vector::at(size_type pos) const { if (pos >= this->size()) { - this->throw_length_error(); + this->throw_out_of_range(); } return m_begin[pos]; } @@ -436,38 +451,38 @@ vector::at(size_type pos) const { template typename vector::reference vector::operator[](size_type pos) { - assert(pos < this->size(), "vector[] index out of bounds"); + assert(pos < this->size() && "vector[] index out of bounds"); return m_begin[pos]; } template typename vector::const_reference vector::operator[](size_type pos) const { - assert(pos < this->size(), "vector[] index out of bounds"); + assert(pos < this->size() && "vector[] index out of bounds"); return m_begin[pos]; } template typename vector::reference vector::front() { - assert(!this->empty(), "front() called on an empty vector"); + assert(!this->empty() && "front() called on an empty vector"); return *m_begin; } template typename vector::const_reference vector::front() const { - assert(!this->empty(), "front() called on an empty vector"); + assert(!this->empty() && "front() called on an empty vector"); return *m_begin; } template typename vector::reference vector::back() { - assert(!this->empty(), "back() called on an empty vector"); + assert(!this->empty() && "back() called on an empty vector"); return *(m_end - 1); } template typename vector::const_reference vector::back() const { - assert(!this->empty(), "back() called on an empty vector"); + assert(!this->empty() && "back() called on an empty vector"); return *(m_end - 1); } @@ -642,7 +657,7 @@ void vector::clear() noexcept { template typename vector::iterator vector::insert(const_iterator pos, const_reference val) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; if (m_end < m_cap) { if (p == m_end) { @@ -686,6 +701,8 @@ vector::insert(const_iterator pos, const_reference val) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; + + p = m_begin + offset; } return iterator(p); @@ -694,7 +711,7 @@ vector::insert(const_iterator pos, const_reference val) { template typename vector::iterator vector::insert(const_iterator pos, value_type &&val) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; if (m_end < m_cap) { if (p == m_end) { @@ -731,6 +748,8 @@ vector::insert(const_iterator pos, value_type &&val) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; + + p = m_begin + offset; } return iterator(p); } @@ -738,7 +757,7 @@ vector::insert(const_iterator pos, value_type &&val) { template typename vector::iterator vector::insert(const_iterator pos, size_type n, const_reference val) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; if (n > 0) { if (n <= static_cast(m_cap - m_end)) { @@ -754,7 +773,7 @@ vector::insert(const_iterator pos, size_type n, const_reference val) { if (n > 0) { this->move_to_insert(p, old_end, p + old_n); - const_pointer pval = std::pointer_traits::pointer_to(val); + const_pointer pval = std::pointer_traits::pointer_to(val); const_pointer pp = std::to_address(p); const_pointer pend = std::to_address(m_end); if (!(pp <= pval && pval < pend)) { @@ -791,6 +810,8 @@ vector::insert(const_iterator pos, size_type n, const_reference val) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; + + p = m_begin + offset; } } @@ -803,11 +824,10 @@ template typename vector::iterator vector::insert( const_iterator pos, ForwardIter first, ForwardIter last ) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; difference_type n = std::distance(first, last); - if (n > 0) { if (n <= static_cast(m_cap - m_end)) { pointer old_end = m_end; @@ -852,6 +872,8 @@ typename vector::iterator vector::insert( m_begin = new_begin; m_end = new_end; m_cap = new_cap; + + p = m_begin + offset; } } @@ -864,8 +886,9 @@ template (!std::forward_iterator) typename vector::iterator vector::insert(const_iterator pos, InputIter first, InputIter last) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; + pointer old_end = m_end; for (; first != last; ++first) { @@ -874,6 +897,8 @@ vector::insert(const_iterator pos, InputIter first, InputIter last) { std::rotate(p, old_end, m_end); + p = m_begin + offset; + return iterator(p); } @@ -887,7 +912,7 @@ template template typename vector::iterator vector::emplace(const_iterator pos, Args &&...args) { - size_type offset = static_cast(std::distance(this->begin(), pos)); + difference_type offset = std::distance(this->cbegin(), pos); pointer p = m_begin + offset; if (m_end < m_cap) { if (p == m_end) { @@ -899,7 +924,7 @@ vector::emplace(const_iterator pos, Args &&...args) { } } else { size_type sz = this->recommend(this->size() + 1); - pointer new_begin = alloc_traits::allocate(sz); + pointer new_begin = alloc_traits::allocate(m_alloc, sz); pointer new_end = new_begin; pointer new_cap = new_begin + sz; @@ -924,6 +949,8 @@ vector::emplace(const_iterator pos, Args &&...args) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; + + p = m_begin + offset; } return iterator(p); @@ -932,9 +959,9 @@ vector::emplace(const_iterator pos, Args &&...args) { template typename vector::iterator vector::erase(const_iterator pos) { - assert(pos != this->end(), "vector::erase(iterator) called with a non-dereferenceable iterator"); + assert(pos != this->end() && "vector::erase(iterator) called with a non-dereferenceable iterator"); - pointer p = m_begin + (this->cbegin() - pos); + pointer p = m_begin + (pos - this->cbegin()); this->destruct(std::move(p + 1, m_end, p)); return iterator(p); @@ -943,7 +970,7 @@ vector::erase(const_iterator pos) { template typename vector::iterator vector::erase(const_iterator first, const_iterator last) { - assert(first <= last, "vector::erase(first, last) called with invalid range"); + assert(first <= last && "vector::erase(first, last) called with invalid range"); pointer p = m_begin + (first - this->cbegin()); if (first != last) { @@ -998,7 +1025,7 @@ vector::emplace_back(Args &&...args) { template void vector::pop_back() { - assert(!empty(), "vector::pop_back called on an empty vector"); + assert(!empty() && "vector::pop_back called on an empty vector"); this->destruct(m_end - 1); } @@ -1078,20 +1105,20 @@ void vector::resize(size_type new_sz, const_reference val) { template void vector::swap(vector &other) noexcept( - alloc_traits::propagate_on_container_swap::val || - alloc_traits::is_always_equal::val + alloc_traits::propagate_on_container_swap::value || + alloc_traits::is_always_equal::value ) { assert( alloc_traits::propagate_on_container_swap::value || - m_alloc == other.m_alloc, - "vector::swap: Either propagate_on_container_swap must be true or the " - "allocators must compare equal" + m_alloc == other.m_alloc && + "vector::swap: Either propagate_on_container_swap must be true or the " + "allocators must compare equal" ); std::swap(m_begin, other.m_begin); std::swap(m_end, other.m_end); std::swap(m_cap, other.m_cap); - if constexpr (std::bool_constant::value) { + if constexpr (alloc_traits::propagate_on_container_swap::value) { std::swap(m_alloc, other.m_alloc); } } @@ -1104,6 +1131,11 @@ void vector::throw_length_error() { throw std::length_error("vector"); } +template +void vector::throw_out_of_range() { + throw std::out_of_range("vector"); +} + template typename vector::size_type vector::recommend(size_type new_size) { diff --git a/test/container/vector.cpp b/test/container/vector.cpp new file mode 100644 index 0000000..cfae2da --- /dev/null +++ b/test/container/vector.cpp @@ -0,0 +1,590 @@ +#include + +#include + +#include + +TEST_CASE("Vector constructors", "[vector][ctor]") { + SECTION("default constructor") { + tinystl::vector vec; + std::vector std_vec; + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.empty() == std_vec.empty()); + } + + SECTION("size constructor") { + tinystl::vector vec(5); + std::vector std_vec(5); + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.size() == 5); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); // Both should be default-constructed (0) + } + } + + SECTION("size and value constructor") { + tinystl::vector vec(5, 42); + std::vector std_vec(5, 42); + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + REQUIRE(vec[i] == 42); + } + } + + SECTION("initializer list constructor") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("copy constructor") { + tinystl::vector vec1 = {1, 2, 3, 4, 5}; + tinystl::vector vec2(vec1); + std::vector std_vec1 = {1, 2, 3, 4, 5}; + std::vector std_vec2(std_vec1); + + REQUIRE(vec2.size() == std_vec2.size()); + for (size_t i = 0; i < vec2.size(); ++i) { + REQUIRE(vec2[i] == std_vec2[i]); + } + } + + SECTION("copy assignment") { + tinystl::vector vec1 = {1, 2, 3, 4, 5}; + tinystl::vector vec2; + vec2 = vec1; + std::vector std_vec1 = {1, 2, 3, 4, 5}; + std::vector std_vec2; + std_vec2 = std_vec1; + + REQUIRE(vec2.size() == std_vec2.size()); + for (size_t i = 0; i < vec2.size(); ++i) { + REQUIRE(vec2[i] == std_vec2[i]); + } + } + + SECTION("move constructor") { + tinystl::vector vec1 = {1, 2, 3, 4, 5}; + auto vec1_size = vec1.size(); + tinystl::vector vec2(std::move(vec1)); + + std::vector std_vec1 = {1, 2, 3, 4, 5}; + std::vector std_vec2(std::move(std_vec1)); + + REQUIRE(vec2.size() == vec1_size); + REQUIRE(vec2.size() == 5); + for (size_t i = 0; i < vec2.size(); ++i) { + REQUIRE(vec2[i] == (int)(i + 1)); + } + } + + SECTION("move assignment") { + tinystl::vector vec1 = {1, 2, 3, 4, 5}; + tinystl::vector vec2; + vec2 = std::move(vec1); + + std::vector std_vec1 = {1, 2, 3, 4, 5}; + std::vector std_vec2; + std_vec2 = std::move(std_vec1); + + REQUIRE(vec2.size() == 5); + for (size_t i = 0; i < vec2.size(); ++i) { + REQUIRE(vec2[i] == (int)(i + 1)); + } + } + + SECTION("range constructor") { + std::vector source = {10, 20, 30, 40, 50}; + tinystl::vector vec(source.begin(), source.end()); + std::vector std_vec(source.begin(), source.end()); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } +} + +TEST_CASE("Vector element access", "[vector][access]") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + SECTION("at returns correct element") { + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec.at(i) == std_vec.at(i)); + } + } + + SECTION("at throws on out-of-range") { + REQUIRE_THROWS_AS((void)vec.at(5), std::out_of_range); + REQUIRE_THROWS_AS((void)std_vec.at(5), std::out_of_range); + } + + SECTION("operator[] returns correct element") { + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("front returns first element") { + REQUIRE(vec.front() == std_vec.front()); + REQUIRE(vec.front() == 1); + } + + SECTION("back returns last element") { + REQUIRE(vec.back() == std_vec.back()); + REQUIRE(vec.back() == 5); + } + + SECTION("data returns pointer to data") { + int *data = vec.data(); + int *std_data = std_vec.data(); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(data[i] == std_data[i]); + } + } +} + +TEST_CASE("Vector iterators", "[vector][iterator]") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + SECTION("begin and end") { + auto it = vec.begin(); + auto std_it = std_vec.begin(); + for (size_t i = 0; i < vec.size(); ++i, ++it, ++std_it) { + REQUIRE(*it == *std_it); + } + REQUIRE(it == vec.end()); + REQUIRE(std_it == std_vec.end()); + } + + SECTION("const begin and end") { + const auto &cvec = vec; + const auto &cstd_vec = std_vec; + auto it = cvec.begin(); + auto std_it = cstd_vec.begin(); + for (size_t i = 0; i < vec.size(); ++i, ++it, ++std_it) { + REQUIRE(*it == *std_it); + } + REQUIRE(it == cvec.end()); + } + + SECTION("cbegin and cend") { + auto it = vec.cbegin(); + auto std_it = std_vec.cbegin(); + for (size_t i = 0; i < vec.size(); ++i, ++it, ++std_it) { + REQUIRE(*it == *std_it); + } + REQUIRE(it == vec.cend()); + } + + SECTION("rbegin and rend") { + auto rit = vec.rbegin(); + auto std_rit = std_vec.rbegin(); + for (size_t i = 0; i < vec.size(); ++i, ++rit, ++std_rit) { + REQUIRE(*rit == *std_rit); + } + REQUIRE(rit == vec.rend()); + } + + SECTION("const rbegin and rend") { + const auto &cvec = vec; + const auto &cstd_vec = std_vec; + auto rit = cvec.rbegin(); + auto std_rit = cstd_vec.rbegin(); + for (size_t i = 0; i < vec.size(); ++i, ++rit, ++std_rit) { + REQUIRE(*rit == *std_rit); + } + REQUIRE(rit == cvec.rend()); + } + + SECTION("crbegin and crend") { + auto rit = vec.crbegin(); + auto std_rit = std_vec.crbegin(); + for (size_t i = 0; i < vec.size(); ++i, ++rit, ++std_rit) { + REQUIRE(*rit == *std_rit); + } + REQUIRE(rit == vec.crend()); + } +} + +TEST_CASE("Vector capacity", "[vector][capacity]") { + tinystl::vector vec; + std::vector std_vec; + + SECTION("empty vector") { + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.empty() == std_vec.empty()); + REQUIRE(vec.empty() == true); + } + + SECTION("non-empty vector") { + vec = {1, 2, 3, 4, 5}; + std_vec = {1, 2, 3, 4, 5}; + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.size() == 5); + REQUIRE(vec.empty() == false); + REQUIRE(std_vec.empty() == false); + } + + SECTION("max_size") { + // max_size can differ between implementations, just check it's reasonable + REQUIRE(vec.max_size() > 0); + REQUIRE(std_vec.max_size() > 0); + } + + SECTION("reserve increases capacity") { + vec.reserve(10); + std_vec.reserve(10); + REQUIRE(vec.capacity() >= 10); + REQUIRE(std_vec.capacity() >= 10); + REQUIRE(vec.size() == 0); + REQUIRE(std_vec.size() == 0); + } + + SECTION("capacity after push_back") { + size_t initial_cap = vec.capacity(); + for (int i = 0; i < 10; ++i) { + vec.push_back(i); + } + REQUIRE(vec.capacity() >= initial_cap); + REQUIRE(vec.size() == 10); + } + + SECTION("shrink_to_fit") { + vec.reserve(100); + vec.push_back(1); + vec.shrink_to_fit(); + // After shrink_to_fit, capacity should be close to size + REQUIRE(vec.capacity() >= vec.size()); + } +} + +TEST_CASE("Vector modifiers", "[vector][modifiers]") { + SECTION("push_back and pop_back") { + tinystl::vector vec; + std::vector std_vec; + + for (int i = 1; i <= 5; ++i) { + vec.push_back(i); + std_vec.push_back(i); + } + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + + vec.pop_back(); + std_vec.pop_back(); + REQUIRE(vec.size() == 4); + REQUIRE(vec.size() == std_vec.size()); + } + + SECTION("emplace_back") { + tinystl::vector> vec; + std::vector> std_vec; + + vec.emplace_back(1, 2); + std_vec.emplace_back(1, 2); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.back().first == std_vec.back().first); + REQUIRE(vec.back().second == std_vec.back().second); + } + + SECTION("clear") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + vec.clear(); + std_vec.clear(); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.empty() == std_vec.empty()); + REQUIRE(vec.empty() == true); + } + + SECTION("insert single element") { + tinystl::vector vec = {1, 3, 5}; + std::vector std_vec = {1, 3, 5}; + + auto it = vec.insert(vec.begin() + 1, 2); + auto std_it = std_vec.insert(std_vec.begin() + 1, 2); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(*it == *std_it); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("insert multiple elements") { + tinystl::vector vec = {1, 5}; + std::vector std_vec = {1, 5}; + + vec.insert(vec.begin() + 1, 3, 42); + std_vec.insert(std_vec.begin() + 1, 3, 42); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("insert range") { + tinystl::vector vec = {1, 5}; + std::vector std_vec = {1, 5}; + std::vector source = {2, 3, 4}; + + vec.insert(vec.begin() + 1, source.begin(), source.end()); + std_vec.insert(std_vec.begin() + 1, source.begin(), source.end()); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("insert initializer list") { + tinystl::vector vec = {1, 5}; + std::vector std_vec = {1, 5}; + + vec.insert(vec.begin() + 1, {2, 3, 4}); + std_vec.insert(std_vec.begin() + 1, {2, 3, 4}); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("emplace") { + tinystl::vector> vec; + std::vector> std_vec; + + vec.emplace(vec.begin(), 1, 2); + std_vec.emplace(std_vec.begin(), 1, 2); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec[0].first == std_vec[0].first); + REQUIRE(vec[0].second == std_vec[0].second); + } + + SECTION("erase single element") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + auto it = vec.erase(vec.begin() + 2); + auto std_it = std_vec.erase(std_vec.begin() + 2); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(*it == *std_it); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("erase range") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + auto it = vec.erase(vec.begin() + 1, vec.begin() + 4); + auto std_it = std_vec.erase(std_vec.begin() + 1, std_vec.begin() + 4); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(*it == *std_it); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("resize") { + tinystl::vector vec = {1, 2, 3}; + std::vector std_vec = {1, 2, 3}; + + // Resize larger + vec.resize(5); + std_vec.resize(5); + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + + // Resize smaller + vec.resize(2); + std_vec.resize(2); + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("resize with value") { + tinystl::vector vec = {1, 2, 3}; + std::vector std_vec = {1, 2, 3}; + + vec.resize(5, 42); + std_vec.resize(5, 42); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("swap") { + tinystl::vector vec1 = {1, 2, 3}; + tinystl::vector vec2 = {4, 5, 6, 7}; + std::vector std_vec1 = {1, 2, 3}; + std::vector std_vec2 = {4, 5, 6, 7}; + + vec1.swap(vec2); + std_vec1.swap(std_vec2); + + REQUIRE(vec1.size() == std_vec1.size()); + REQUIRE(vec2.size() == std_vec2.size()); + for (size_t i = 0; i < vec1.size(); ++i) { + REQUIRE(vec1[i] == std_vec1[i]); + } + for (size_t i = 0; i < vec2.size(); ++i) { + REQUIRE(vec2[i] == std_vec2[i]); + } + } +} + +TEST_CASE("Vector assign", "[vector][assign]") { + SECTION("assign with count and value") { + tinystl::vector vec; + std::vector std_vec; + + vec.assign(5, 42); + std_vec.assign(5, 42); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + REQUIRE(vec[i] == 42); + } + } + + SECTION("assign with range") { + tinystl::vector vec; + std::vector std_vec; + std::vector source = {10, 20, 30, 40, 50}; + + vec.assign(source.begin(), source.end()); + std_vec.assign(source.begin(), source.end()); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("assign with initializer list") { + tinystl::vector vec; + std::vector std_vec; + + vec.assign({1, 2, 3, 4, 5}); + std_vec.assign({1, 2, 3, 4, 5}); + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } +} + +TEST_CASE("Vector comparison operators", "[vector][comparison]") { + tinystl::vector vec1 = {1, 2, 3}; + tinystl::vector vec2 = {1, 2, 3}; + tinystl::vector vec3 = {1, 2, 4}; + tinystl::vector vec4 = {1, 2}; + + std::vector std_vec1 = {1, 2, 3}; + std::vector std_vec2 = {1, 2, 3}; + std::vector std_vec3 = {1, 2, 4}; + std::vector std_vec4 = {1, 2}; + + SECTION("equality") { + REQUIRE((vec1 == vec2) == (std_vec1 == std_vec2)); + REQUIRE((vec1 == vec3) == (std_vec1 == std_vec3)); + REQUIRE((vec1 == vec4) == (std_vec1 == std_vec4)); + } + + SECTION("inequality") { + REQUIRE((vec1 != vec2) == (std_vec1 != std_vec2)); + REQUIRE((vec1 != vec3) == (std_vec1 != std_vec3)); + REQUIRE((vec1 != vec4) == (std_vec1 != std_vec4)); + } + + SECTION("less than") { + REQUIRE((vec1 < vec2) == (std_vec1 < std_vec2)); + REQUIRE((vec1 < vec3) == (std_vec1 < std_vec3)); + REQUIRE((vec1 < vec4) == (std_vec1 < std_vec4)); + } + + SECTION("less than or equal") { + REQUIRE((vec1 <= vec2) == (std_vec1 <= std_vec2)); + REQUIRE((vec1 <= vec3) == (std_vec1 <= std_vec3)); + REQUIRE((vec1 <= vec4) == (std_vec1 <= std_vec4)); + } + + SECTION("greater than") { + REQUIRE((vec1 > vec2) == (std_vec1 > std_vec2)); + REQUIRE((vec1 > vec3) == (std_vec1 > std_vec3)); + REQUIRE((vec1 > vec4) == (std_vec1 > std_vec4)); + } + + SECTION("greater than or equal") { + REQUIRE((vec1 >= vec2) == (std_vec1 >= std_vec2)); + REQUIRE((vec1 >= vec3) == (std_vec1 >= std_vec3)); + REQUIRE((vec1 >= vec4) == (std_vec1 >= std_vec4)); + } +} + +TEST_CASE("Vector special cases", "[vector][special]") { + SECTION("self assignment") { + tinystl::vector vec = {1, 2, 3, 4, 5}; + std::vector std_vec = {1, 2, 3, 4, 5}; + + vec = vec; + std_vec = std_vec; + + REQUIRE(vec.size() == std_vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + REQUIRE(vec[i] == std_vec[i]); + } + } + + SECTION("empty vector operations") { + tinystl::vector vec; + std::vector std_vec; + + REQUIRE(vec.empty() == std_vec.empty()); + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.begin() == vec.end()); + REQUIRE(std_vec.begin() == std_vec.end()); + } + + SECTION("large vector") { + const size_t large_size = 10000; + tinystl::vector vec(large_size, 42); + std::vector std_vec(large_size, 42); + + REQUIRE(vec.size() == std_vec.size()); + REQUIRE(vec.size() == large_size); + + // Check a few random elements + for (size_t i = 0; i < large_size; i += 1000) { + REQUIRE(vec[i] == std_vec[i]); + REQUIRE(vec[i] == 42); + } + } +}