FTL: Refine container semantics
Allow constructing StaticVector and SmallVector by moving smaller
convertible vectors, which so far incurred a copy. Allow the same
copy/move conversion for SmallMap.
Consistently with StaticVector, do not require assignable elements for
the SmallVector to be assignable, which notably enables SmallMap to be
assignable despite its const keys.
Allow comparison of convertible containers.
Bug: 185536303
Test: ftl_test
Change-Id: I35923e794ef26178dc3072f514dea7ad5600bc15
diff --git a/include/ftl/details/array_traits.h b/include/ftl/details/array_traits.h
index 16e63ec..5234c38 100644
--- a/include/ftl/details/array_traits.h
+++ b/include/ftl/details/array_traits.h
@@ -42,7 +42,7 @@
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <typename... Args>
- static pointer construct_at(const_iterator it, Args&&... args) {
+ static constexpr pointer construct_at(const_iterator it, Args&&... args) {
void* const ptr = const_cast<void*>(static_cast<const void*>(it));
if constexpr (std::is_constructible_v<value_type, Args...>) {
// TODO: Replace with std::construct_at in C++20.
@@ -52,6 +52,42 @@
return new (ptr) value_type{std::forward<Args>(args)...};
}
}
+
+ // TODO: Make constexpr in C++20.
+ template <typename... Args>
+ static reference replace_at(const_iterator it, Args&&... args) {
+ value_type element{std::forward<Args>(args)...};
+ return replace_at(it, std::move(element));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static reference replace_at(const_iterator it, value_type&& value) {
+ std::destroy_at(it);
+ // This is only safe because exceptions are disabled.
+ return *construct_at(it, std::move(value));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap(reference a, reference b) {
+ value_type c{std::move(a)};
+ replace_at(&a, std::move(b));
+ replace_at(&b, std::move(c));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) {
+ while (first1 != last1) {
+ in_place_swap(*first1++, *first2++);
+ }
+ }
+
+ // TODO: Replace with std::uninitialized_copy in C++20.
+ template <typename Iterator>
+ static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) {
+ while (first != last) {
+ construct_at(out++, *first++);
+ }
+ }
};
// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
@@ -101,33 +137,33 @@
// TODO: Replace with operator<=> in C++20.
template <template <typename, std::size_t> class Array>
struct ArrayComparators {
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator==(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return rhs < lhs;
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator!=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs == rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs < rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs > rhs);
}
};