From d0cd7193754dea38c8a8a4f2586904001c99b13c Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 1 Jul 2024 07:10:35 -0700 Subject: [PATCH] Make more CTL fixes --- ctl/allocator_traits.h | 17 ++++---- ctl/string.h | 22 +++++++--- ctl/vector.h | 7 ++-- test/ctl/vector_test.cc | 91 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 15 deletions(-) diff --git a/ctl/allocator_traits.h b/ctl/allocator_traits.h index 4873899f4..155a71bcf 100644 --- a/ctl/allocator_traits.h +++ b/ctl/allocator_traits.h @@ -11,12 +11,12 @@ struct allocator_traits { using allocator_type = Alloc; using value_type = typename Alloc::value_type; - using pointer = typename Alloc::pointer; - using const_pointer = typename Alloc::const_pointer; + using pointer = typename Alloc::value_type*; + using const_pointer = const typename Alloc::value_type*; using void_pointer = void*; using const_void_pointer = const void*; - using difference_type = typename Alloc::difference_type; - using size_type = typename Alloc::size_type; + using difference_type = ptrdiff_t; + using size_type = size_t; using propagate_on_container_copy_assignment = ctl::false_type; using propagate_on_container_move_assignment = ctl::true_type; @@ -24,10 +24,13 @@ struct allocator_traits using is_always_equal = ctl::true_type; template - using rebind_alloc = typename Alloc::template rebind::other; + struct rebind_alloc + { + using other = typename Alloc::template rebind::other; + }; template - using rebind_traits = allocator_traits>; + using rebind_traits = allocator_traits::other>; static pointer allocate(Alloc& a, size_type n) { @@ -53,7 +56,7 @@ struct allocator_traits static size_type max_size(const Alloc& a) noexcept { - return __PTRDIFF_MAX__ / sizeof(value_type); + return a.max_size(); } static Alloc select_on_container_copy_construction(const Alloc& a) diff --git a/ctl/string.h b/ctl/string.h index b2941588d..6c92d8f9f 100644 --- a/ctl/string.h +++ b/ctl/string.h @@ -332,6 +332,18 @@ class string return *this; } + string& operator+=(const char* s) noexcept + { + append(s); + return *this; + } + + string& operator+=(const ctl::string s) noexcept + { + append(s); + return *this; + } + string& operator+=(const ctl::string_view s) noexcept { append(s); @@ -344,6 +356,11 @@ class string return strcat(*this, s); } + string operator+(const char* s) const noexcept + { + return strcat(*this, s); + } + string operator+(const string& s) const noexcept { return strcat(*this, s); @@ -354,11 +371,6 @@ class string return strcat(*this, s); } - string operator+(const char* s) const noexcept - { - return strcat(*this, s); - } - int compare(const ctl::string_view s) const noexcept { return strcmp(*this, s); diff --git a/ctl/vector.h b/ctl/vector.h index 30861e27d..ce0cd5831 100644 --- a/ctl/vector.h +++ b/ctl/vector.h @@ -411,16 +411,17 @@ class vector return erase(pos, pos + 1); } - iterator erase(const_iterator first, const_iterator last) + constexpr iterator erase(const_iterator first, const_iterator last) { difference_type index = first - begin(); difference_type count = last - first; iterator it = begin() + index; - ctl::move(it + count, end(), it); + for (iterator move_it = it + count; move_it != end(); ++move_it, ++it) + *it = ctl::move(*move_it); for (difference_type i = 0; i < count; ++i) ctl::allocator_traits::destroy(alloc_, end() - i - 1); size_ -= count; - return it; + return begin() + index; } void push_back(const T& value) diff --git a/test/ctl/vector_test.cc b/test/ctl/vector_test.cc index 84469b2c0..d114c5445 100644 --- a/test/ctl/vector_test.cc +++ b/test/ctl/vector_test.cc @@ -24,6 +24,46 @@ // #include // #define ctl std +static int counter; + +// Test with non-trivial type +struct NonTrivial +{ + int value; + + NonTrivial(int v) : value(v) + { + ++counter; + } + + NonTrivial(const NonTrivial& other) : value(other.value) + { + ++counter; + } + + NonTrivial(NonTrivial&& other) noexcept : value(other.value) + { + ++counter; + } + + ~NonTrivial() + { + --counter; + } + + NonTrivial& operator=(const NonTrivial& other) + { + value = other.value; + return *this; + } + + NonTrivial& operator=(NonTrivial&& other) noexcept + { + value = other.value; + return *this; + } +}; + int main() { @@ -360,5 +400,56 @@ main() return 82; } + // Test erase(const_iterator first, const_iterator last) + { + ctl::vector v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + // Test erasing from the middle + auto it = v.erase(v.begin() + 3, v.begin() + 7); + if (v.size() != 6 || v != ctl::vector{ 1, 2, 3, 8, 9, 10 } || + it != v.begin() + 3) + return 83; + + // Test erasing from the beginning + it = v.erase(v.begin(), v.begin() + 2); + if (v.size() != 4 || v != ctl::vector{ 3, 8, 9, 10 } || + it != v.begin()) + return 84; + + // Test erasing to the end + it = v.erase(v.begin() + 2, v.end()); + if (v.size() != 2 || v != ctl::vector{ 3, 8 } || it != v.end()) + return 85; + + // Test erasing all elements + it = v.erase(v.begin(), v.end()); + if (!v.empty() || it != v.end()) + return 86; + + // Test erasing empty range + v = { 1, 2, 3, 4, 5 }; + it = v.erase(v.begin() + 2, v.begin() + 2); + if (v.size() != 5 || v != ctl::vector{ 1, 2, 3, 4, 5 } || + it != v.begin() + 2) + return 87; + + counter = 0; + + { + ctl::vector v2; + for (int i = 0; i < 10; ++i) + v2.emplace_back(i); + v2.erase(v2.begin() + 3, v2.begin() + 7); + if (v2.size() != 6 || counter != 6) + return 89; + for (int i = 0; i < (int)v2.size(); ++i) + if (v2[i].value != (i < 3 ? i : i + 4)) + return 90; + } + + if (counter != 0) + return 91; + } + CheckForMemoryLeaks(); }