summaryrefslogtreecommitdiff
path: root/include/ftl
diff options
context:
space:
mode:
Diffstat (limited to 'include/ftl')
l---------include/ftl/.clang-format1
-rw-r--r--include/ftl/array_traits.h135
-rw-r--r--include/ftl/future.h109
-rw-r--r--include/ftl/initializer_list.h108
-rw-r--r--include/ftl/small_map.h203
-rw-r--r--include/ftl/small_vector.h387
-rw-r--r--include/ftl/static_vector.h394
7 files changed, 0 insertions, 1337 deletions
diff --git a/include/ftl/.clang-format b/include/ftl/.clang-format
deleted file mode 120000
index 86b159339f..0000000000
--- a/include/ftl/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../../../../build/soong/scripts/system-clang-format-2 \ No newline at end of file
diff --git a/include/ftl/array_traits.h b/include/ftl/array_traits.h
deleted file mode 100644
index 1265fa15fe..0000000000
--- a/include/ftl/array_traits.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <algorithm>
-#include <iterator>
-#include <new>
-#include <type_traits>
-
-#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
-
-namespace android::ftl {
-
-template <typename T>
-struct ArrayTraits {
- using value_type = T;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
-
- using pointer = value_type*;
- using reference = value_type&;
- using iterator = pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using const_pointer = const value_type*;
- using const_reference = const value_type&;
- using const_iterator = const_pointer;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- template <typename... Args>
- static 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.
- return new (ptr) value_type(std::forward<Args>(args)...);
- } else {
- // Fall back to list initialization.
- return new (ptr) value_type{std::forward<Args>(args)...};
- }
- }
-};
-
-// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
-template <typename Self, typename T>
-class ArrayIterators {
- FTL_ARRAY_TRAIT(T, size_type);
-
- FTL_ARRAY_TRAIT(T, reference);
- FTL_ARRAY_TRAIT(T, iterator);
- FTL_ARRAY_TRAIT(T, reverse_iterator);
-
- FTL_ARRAY_TRAIT(T, const_reference);
- FTL_ARRAY_TRAIT(T, const_iterator);
- FTL_ARRAY_TRAIT(T, const_reverse_iterator);
-
- Self& self() const { return *const_cast<Self*>(static_cast<const Self*>(this)); }
-
- public:
- const_iterator begin() const { return cbegin(); }
- const_iterator cbegin() const { return self().begin(); }
-
- const_iterator end() const { return cend(); }
- const_iterator cend() const { return self().end(); }
-
- reverse_iterator rbegin() { return std::make_reverse_iterator(self().end()); }
- const_reverse_iterator rbegin() const { return crbegin(); }
- const_reverse_iterator crbegin() const { return self().rbegin(); }
-
- reverse_iterator rend() { return std::make_reverse_iterator(self().begin()); }
- const_reverse_iterator rend() const { return crend(); }
- const_reverse_iterator crend() const { return self().rend(); }
-
- iterator last() { return self().end() - 1; }
- const_iterator last() const { return self().last(); }
-
- reference front() { return *self().begin(); }
- const_reference front() const { return self().front(); }
-
- reference back() { return *last(); }
- const_reference back() const { return self().back(); }
-
- reference operator[](size_type i) { return *(self().begin() + i); }
- const_reference operator[](size_type i) const { return self()[i]; }
-};
-
-// Mixin to define comparison operators for an array-like template.
-// 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) {
- 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) {
- 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) {
- 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) {
- 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) {
- 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) {
- return !(lhs > rhs);
- }
-};
-
-} // namespace android::ftl
diff --git a/include/ftl/future.h b/include/ftl/future.h
deleted file mode 100644
index dd6358fa7d..0000000000
--- a/include/ftl/future.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <future>
-#include <type_traits>
-#include <utility>
-
-namespace android::ftl {
-
-// Creates a future that defers a function call until its result is queried.
-//
-// auto future = ftl::defer([](int x) { return x + 1; }, 99);
-// assert(future.get() == 100);
-//
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
- return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
-
-// Creates a future that wraps a value.
-//
-// auto future = ftl::yield(42);
-// assert(future.get() == 42);
-//
-// auto ptr = std::make_unique<char>('!');
-// auto future = ftl::yield(std::move(ptr));
-// assert(*future.get() == '!');
-//
-template <typename T>
-inline std::future<T> yield(T&& v) {
- return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
-}
-
-namespace details {
-
-template <typename T>
-struct future_result {
- using type = T;
-};
-
-template <typename T>
-struct future_result<std::future<T>> {
- using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
-
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
-//
-// auto future = ftl::yield(123);
-// std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
-//
-// std::future<char> chain =
-// ftl::chain(std::move(future))
-// .then([](int x) { return static_cast<std::size_t>(x % 2); })
-// .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-// assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
- // Implicit conversion.
- Chain(std::future<T>&& f) : future(std::move(f)) {}
- operator std::future<T>&&() && { return std::move(future); }
-
- T get() && { return future.get(); }
-
- template <typename F, typename R = std::invoke_result_t<F, T>>
- auto then(F&& op) && -> Chain<future_result_t<R>> {
- return defer(
- [](auto&& f, F&& op) {
- R r = op(f.get());
- if constexpr (std::is_same_v<R, future_result_t<R>>) {
- return r;
- } else {
- return r.get();
- }
- },
- std::move(future), std::forward<F>(op));
- }
-
- std::future<T> future;
-};
-
-} // namespace details
-
-template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
- return std::move(f);
-}
-
-} // namespace android::ftl
diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h
deleted file mode 100644
index 769c09ff11..0000000000
--- a/include/ftl/initializer_list.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <tuple>
-#include <utility>
-
-namespace android::ftl {
-
-// Compile-time counterpart of std::initializer_list<T> that stores per-element constructor
-// arguments with heterogeneous types. For a container with elements of type T, given Sizes
-// (S0, S1, ..., SN), N elements are initialized: the first element is initialized with the
-// first S0 arguments, the second element is initialized with the next S1 arguments, and so
-// on. The list of Types (T0, ..., TM) is flattened, so M is equal to the sum of the Sizes.
-//
-// An InitializerList is created using ftl::init::list, and is consumed by constructors of
-// containers. The function call operator is overloaded such that arguments are accumulated
-// in a tuple with each successive call. For instance, the following calls initialize three
-// strings using different constructors, i.e. string literal, default, and count/character:
-//
-// ... = ftl::init::list<std::string>("abc")()(3u, '?');
-//
-// The following syntax is a shorthand for key-value pairs, where the first argument is the
-// key, and the rest construct the value. The types of the key and value are deduced if the
-// first pair contains exactly two arguments:
-//
-// ... = ftl::init::map<int, std::string>(-1, "abc")(-2)(-3, 3u, '?');
-//
-// ... = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
-//
-// WARNING: The InitializerList returned by an ftl::init::list expression must be consumed
-// immediately, since temporary arguments are destroyed after the full expression. Storing
-// an InitializerList results in dangling references.
-//
-template <typename T, typename Sizes = std::index_sequence<>, typename... Types>
-struct InitializerList;
-
-template <typename T, std::size_t... Sizes, typename... Types>
-struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
- // Creates a superset InitializerList by appending the number of arguments to Sizes, and
- // expanding Types with forwarding references for each argument.
- template <typename... Args>
- [[nodiscard]] constexpr auto operator()(Args&&... args) && -> InitializerList<
- T, std::index_sequence<Sizes..., sizeof...(Args)>, Types..., Args&&...> {
- return {std::tuple_cat(std::move(tuple), std::forward_as_tuple(std::forward<Args>(args)...))};
- }
-
- // The temporary InitializerList returned by operator() is bound to an rvalue reference in
- // container constructors, which extends the lifetime of any temporary arguments that this
- // tuple refers to until the completion of the full expression containing the construction.
- std::tuple<Types...> tuple;
-};
-
-template <typename K, typename V>
-struct KeyValue {};
-
-// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
-// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
-// with the latter.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
- // Accumulate the three arguments to std::pair's piecewise constructor.
- template <typename... Args>
- [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
- KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
- std::tuple<K&&>, std::tuple<Args&&...>> {
- return {std::tuple_cat(
- std::move(tuple),
- std::forward_as_tuple(std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)),
- std::forward_as_tuple(std::forward<Args>(args)...)))};
- }
-
- std::tuple<Types...> tuple;
-};
-
-namespace init {
-
-template <typename T, typename... Args>
-[[nodiscard]] constexpr auto list(Args&&... args) {
- return InitializerList<T>{}(std::forward<Args>(args)...);
-}
-
-template <typename K, typename V, typename... Args>
-[[nodiscard]] constexpr auto map(Args&&... args) {
- return list<KeyValue<K, V>>(std::forward<Args>(args)...);
-}
-
-template <typename K, typename V>
-[[nodiscard]] constexpr auto map(K&& k, V&& v) {
- return list<KeyValue<K, V>>(std::forward<K>(k), std::forward<V>(v));
-}
-
-} // namespace init
-} // namespace android::ftl
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
deleted file mode 100644
index 84c15ebdca..0000000000
--- a/include/ftl/small_map.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <ftl/initializer_list.h>
-#include <ftl/small_vector.h>
-
-#include <functional>
-#include <optional>
-#include <type_traits>
-#include <utility>
-
-namespace android::ftl {
-
-// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
-// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
-// exceeds N, at which point mappings are relocated to dynamic memory.
-//
-// SmallMap<K, V, 0> unconditionally allocates on the heap.
-//
-// Example usage:
-//
-// ftl::SmallMap<int, std::string, 3> map;
-// assert(map.empty());
-// assert(!map.dynamic());
-//
-// map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
-// assert(map.size() == 3u);
-// assert(!map.dynamic());
-//
-// assert(map.contains(123));
-// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
-//
-// const auto opt = map.find(-1);
-// assert(opt);
-//
-// std::string& ref = *opt;
-// assert(ref.empty());
-// ref = "xyz";
-//
-// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
-//
-template <typename K, typename V, std::size_t N>
-class SmallMap final {
- using Map = SmallVector<std::pair<const K, V>, N>;
-
- public:
- using key_type = K;
- using mapped_type = V;
-
- using value_type = typename Map::value_type;
- using size_type = typename Map::size_type;
- using difference_type = typename Map::difference_type;
-
- using reference = typename Map::reference;
- using iterator = typename Map::iterator;
-
- using const_reference = typename Map::const_reference;
- using const_iterator = typename Map::const_iterator;
-
- // Creates an empty map.
- SmallMap() = default;
-
- // Constructs at most N key-value pairs in place by forwarding per-pair constructor arguments.
- // The template arguments K, V, and N are inferred using the deduction guide defined below.
- // The syntax for listing pairs is as follows:
- //
- // ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
- //
- // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
- // assert(map.size() == 3u);
- // assert(map.contains(-1) && map.find(-1)->get().empty());
- // assert(map.contains(42) && map.find(42)->get() == "???");
- // assert(map.contains(123) && map.find(123)->get() == "abc");
- //
- // The types of the key and value are deduced if the first pair contains exactly two arguments:
- //
- // ftl::SmallMap map = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
- // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, char, 3>>);
- //
- template <typename U, std::size_t... Sizes, typename... Types>
- SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
- : map_(std::move(list)) {
- // TODO: Enforce unique keys.
- }
-
- size_type max_size() const { return map_.max_size(); }
- size_type size() const { return map_.size(); }
- bool empty() const { return map_.empty(); }
-
- // Returns whether the map is backed by static or dynamic storage.
- bool dynamic() const { return map_.dynamic(); }
-
- iterator begin() { return map_.begin(); }
- const_iterator begin() const { return cbegin(); }
- const_iterator cbegin() const { return map_.cbegin(); }
-
- iterator end() { return map_.end(); }
- const_iterator end() const { return cend(); }
- const_iterator cend() const { return map_.cend(); }
-
- // Returns whether a mapping exists for the given key.
- bool contains(const key_type& key) const {
- return find(key, [](const mapped_type&) {});
- }
-
- // Returns a reference to the value for the given key, or std::nullopt if the key was not found.
- //
- // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
- //
- // const auto opt = map.find('c');
- // assert(opt == 'C');
- //
- // char d = 'd';
- // const auto ref = map.find('d').value_or(std::ref(d));
- // ref.get() = 'D';
- // assert(d == 'D');
- //
- auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
- return find(key, [](const mapped_type& v) { return std::cref(v); });
- }
-
- auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
- return find(key, [](mapped_type& v) { return std::ref(v); });
- }
-
- // Returns the result R of a unary operation F on (a constant or mutable reference to) the value
- // for the given key, or std::nullopt if the key was not found. If F has a return type of void,
- // then the Boolean result indicates whether the key was found.
- //
- // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
- //
- // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
- // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
- //
- template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
- auto find(const key_type& key, F f) const
- -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
- for (auto& [k, v] : *this) {
- if (k == key) {
- if constexpr (std::is_void_v<R>) {
- f(v);
- return true;
- } else {
- return f(v);
- }
- }
- }
-
- return {};
- }
-
- template <typename F>
- auto find(const key_type& key, F f) {
- return std::as_const(*this).find(
- key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); });
- }
-
- private:
- Map map_;
-};
-
-// Deduction guide for in-place constructor.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
- -> SmallMap<K, V, sizeof...(Sizes)>;
-
-// Returns whether the key-value pairs of two maps are equal.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
- if (lhs.size() != rhs.size()) return false;
-
- for (const auto& [k, v] : lhs) {
- const auto& lv = v;
- if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
- return false;
- }
- }
-
- return true;
-}
-
-// TODO: Remove in C++20.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
- return !(lhs == rhs);
-}
-
-} // namespace android::ftl
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
deleted file mode 100644
index cb0ae359eb..0000000000
--- a/include/ftl/small_vector.h
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <ftl/array_traits.h>
-#include <ftl/static_vector.h>
-
-#include <algorithm>
-#include <iterator>
-#include <type_traits>
-#include <utility>
-#include <variant>
-#include <vector>
-
-namespace android::ftl {
-
-template <typename>
-struct is_small_vector;
-
-// ftl::StaticVector that promotes to std::vector when full. SmallVector is a drop-in replacement
-// for std::vector with statically allocated storage for N elements, whose goal is to improve run
-// time by avoiding heap allocation and increasing probability of cache hits. The standard API is
-// augmented by an unstable_erase operation that does not preserve order, and a replace operation
-// that destructively emplaces.
-//
-// SmallVector<T, 0> is a specialization that thinly wraps std::vector.
-//
-// Example usage:
-//
-// ftl::SmallVector<char, 3> vector;
-// assert(vector.empty());
-// assert(!vector.dynamic());
-//
-// vector = {'a', 'b', 'c'};
-// assert(vector.size() == 3u);
-// assert(!vector.dynamic());
-//
-// vector.push_back('d');
-// assert(vector.dynamic());
-//
-// vector.unstable_erase(vector.begin());
-// assert(vector == (ftl::SmallVector{'d', 'b', 'c'}));
-//
-// vector.pop_back();
-// assert(vector.back() == 'b');
-// assert(vector.dynamic());
-//
-// const char array[] = "hi";
-// vector = ftl::SmallVector(array);
-// assert(vector == (ftl::SmallVector{'h', 'i', '\0'}));
-// assert(!vector.dynamic());
-//
-// ftl::SmallVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
-// assert(strings.size() == 3u);
-// assert(!strings.dynamic());
-//
-// assert(strings[0] == "abc");
-// assert(strings[1] == "123");
-// assert(strings[2] == "???");
-//
-template <typename T, std::size_t N>
-class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
- using Static = StaticVector<T, N>;
- using Dynamic = SmallVector<T, 0>;
-
- // TODO: Replace with std::remove_cvref_t in C++20.
- template <typename U>
- using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>;
-
- public:
- FTL_ARRAY_TRAIT(T, value_type);
- FTL_ARRAY_TRAIT(T, size_type);
- FTL_ARRAY_TRAIT(T, difference_type);
-
- FTL_ARRAY_TRAIT(T, pointer);
- FTL_ARRAY_TRAIT(T, reference);
- FTL_ARRAY_TRAIT(T, iterator);
- FTL_ARRAY_TRAIT(T, reverse_iterator);
-
- FTL_ARRAY_TRAIT(T, const_pointer);
- FTL_ARRAY_TRAIT(T, const_reference);
- FTL_ARRAY_TRAIT(T, const_iterator);
- FTL_ARRAY_TRAIT(T, const_reverse_iterator);
-
- // Creates an empty vector.
- SmallVector() = default;
-
- // Constructs at most N elements. See StaticVector for underlying constructors.
- template <typename Arg, typename... Args,
- typename = std::enable_if_t<!is_small_vector<remove_cvref_t<Arg>>{}>>
- SmallVector(Arg&& arg, Args&&... args)
- : vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
-
- // Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
- SmallVector(const SmallVector<U, M>& other)
- : SmallVector(kIteratorRange, other.begin(), other.end()) {}
-
- void swap(SmallVector& other) { vector_.swap(other.vector_); }
-
- // Returns whether the vector is backed by static or dynamic storage.
- bool dynamic() const { return std::holds_alternative<Dynamic>(vector_); }
-
- // Avoid std::visit as it generates a dispatch table.
-#define DISPATCH(T, F, ...) \
- T F() __VA_ARGS__ { \
- return dynamic() ? std::get<Dynamic>(vector_).F() : std::get<Static>(vector_).F(); \
- }
-
- DISPATCH(size_type, max_size, const)
- DISPATCH(size_type, size, const)
- DISPATCH(bool, empty, const)
-
- // noexcept to suppress warning about zero variadic macro arguments.
- DISPATCH(iterator, begin, noexcept)
- DISPATCH(const_iterator, begin, const)
- DISPATCH(const_iterator, cbegin, const)
-
- DISPATCH(iterator, end, noexcept)
- DISPATCH(const_iterator, end, const)
- DISPATCH(const_iterator, cend, const)
-
- DISPATCH(reverse_iterator, rbegin, noexcept)
- DISPATCH(const_reverse_iterator, rbegin, const)
- DISPATCH(const_reverse_iterator, crbegin, const)
-
- DISPATCH(reverse_iterator, rend, noexcept)
- DISPATCH(const_reverse_iterator, rend, const)
- DISPATCH(const_reverse_iterator, crend, const)
-
- DISPATCH(iterator, last, noexcept)
- DISPATCH(const_iterator, last, const)
-
- DISPATCH(reference, front, noexcept)
- DISPATCH(const_reference, front, const)
-
- DISPATCH(reference, back, noexcept)
- DISPATCH(const_reference, back, const)
-
-#undef DISPATCH
-
- reference operator[](size_type i) {
- return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i];
- }
-
- const_reference operator[](size_type i) const { return const_cast<SmallVector&>(*this)[i]; }
-
- // Replaces an element, and returns a reference to it. The iterator must be dereferenceable, so
- // replacing at end() is erroneous.
- //
- // The element is emplaced via move constructor, so type T does not need to define copy/move
- // assignment, e.g. its data members may be const.
- //
- // The arguments may directly or indirectly refer to the element being replaced.
- //
- // Iterators to the replaced element point to its replacement, and others remain valid.
- //
- template <typename... Args>
- reference replace(const_iterator it, Args&&... args) {
- if (dynamic()) {
- return std::get<Dynamic>(vector_).replace(it, std::forward<Args>(args)...);
- } else {
- return std::get<Static>(vector_).replace(it, std::forward<Args>(args)...);
- }
- }
-
- // Appends an element, and returns a reference to it.
- //
- // If the vector reaches its static or dynamic capacity, then all iterators are invalidated.
- // Otherwise, only the end() iterator is invalidated.
- //
- template <typename... Args>
- reference emplace_back(Args&&... args) {
- constexpr auto kInsertStatic = &Static::template emplace_back<Args...>;
- constexpr auto kInsertDynamic = &Dynamic::template emplace_back<Args...>;
- return *insert<kInsertStatic, kInsertDynamic>(std::forward<Args>(args)...);
- }
-
- // Appends an element.
- //
- // If the vector reaches its static or dynamic capacity, then all iterators are invalidated.
- // Otherwise, only the end() iterator is invalidated.
- //
- void push_back(const value_type& v) {
- constexpr auto kInsertStatic =
- static_cast<bool (Static::*)(const value_type&)>(&Static::push_back);
- constexpr auto kInsertDynamic =
- static_cast<bool (Dynamic::*)(const value_type&)>(&Dynamic::push_back);
- insert<kInsertStatic, kInsertDynamic>(v);
- }
-
- void push_back(value_type&& v) {
- constexpr auto kInsertStatic = static_cast<bool (Static::*)(value_type &&)>(&Static::push_back);
- constexpr auto kInsertDynamic =
- static_cast<bool (Dynamic::*)(value_type &&)>(&Dynamic::push_back);
- insert<kInsertStatic, kInsertDynamic>(std::move(v));
- }
-
- // Removes the last element. The vector must not be empty, or the call is erroneous.
- //
- // The last() and end() iterators are invalidated.
- //
- void pop_back() {
- if (dynamic()) {
- std::get<Dynamic>(vector_).pop_back();
- } else {
- std::get<Static>(vector_).pop_back();
- }
- }
-
- // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
- // this moves the last element to the slot of the erased element.
- //
- // The last() and end() iterators, as well as those to the erased element, are invalidated.
- //
- void unstable_erase(iterator it) {
- if (dynamic()) {
- std::get<Dynamic>(vector_).unstable_erase(it);
- } else {
- std::get<Static>(vector_).unstable_erase(it);
- }
- }
-
- private:
- template <auto InsertStatic, auto InsertDynamic, typename... Args>
- auto insert(Args&&... args) {
- if (Dynamic* const vector = std::get_if<Dynamic>(&vector_)) {
- return (vector->*InsertDynamic)(std::forward<Args>(args)...);
- }
-
- auto& vector = std::get<Static>(vector_);
- if (vector.full()) {
- return (promote(vector).*InsertDynamic)(std::forward<Args>(args)...);
- } else {
- return (vector.*InsertStatic)(std::forward<Args>(args)...);
- }
- }
-
- Dynamic& promote(Static& static_vector) {
- assert(static_vector.full());
-
- // Allocate double capacity to reduce probability of reallocation.
- Dynamic vector;
- vector.reserve(Static::max_size() * 2);
- std::move(static_vector.begin(), static_vector.end(), std::back_inserter(vector));
-
- return vector_.template emplace<Dynamic>(std::move(vector));
- }
-
- std::variant<Static, Dynamic> vector_;
-};
-
-// Partial specialization without static storage.
-template <typename T>
-class SmallVector<T, 0> final : ArrayTraits<T>,
- ArrayIterators<SmallVector<T, 0>, T>,
- std::vector<T> {
- using ArrayTraits<T>::construct_at;
-
- using Iter = ArrayIterators<SmallVector, T>;
- using Impl = std::vector<T>;
-
- friend Iter;
-
- public:
- FTL_ARRAY_TRAIT(T, value_type);
- FTL_ARRAY_TRAIT(T, size_type);
- FTL_ARRAY_TRAIT(T, difference_type);
-
- FTL_ARRAY_TRAIT(T, pointer);
- FTL_ARRAY_TRAIT(T, reference);
- FTL_ARRAY_TRAIT(T, iterator);
- FTL_ARRAY_TRAIT(T, reverse_iterator);
-
- FTL_ARRAY_TRAIT(T, const_pointer);
- FTL_ARRAY_TRAIT(T, const_reference);
- FTL_ARRAY_TRAIT(T, const_iterator);
- FTL_ARRAY_TRAIT(T, const_reverse_iterator);
-
- using Impl::Impl;
-
- using Impl::empty;
- using Impl::max_size;
- using Impl::size;
-
- using Impl::reserve;
-
- // std::vector iterators are not necessarily raw pointers.
- iterator begin() { return Impl::data(); }
- iterator end() { return Impl::data() + size(); }
-
- using Iter::begin;
- using Iter::end;
-
- using Iter::cbegin;
- using Iter::cend;
-
- using Iter::rbegin;
- using Iter::rend;
-
- using Iter::crbegin;
- using Iter::crend;
-
- using Iter::last;
-
- using Iter::back;
- using Iter::front;
-
- using Iter::operator[];
-
- template <typename... Args>
- reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
- }
-
- template <typename... Args>
- iterator emplace_back(Args&&... args) {
- return &Impl::emplace_back(std::forward<Args>(args)...);
- }
-
- bool push_back(const value_type& v) {
- Impl::push_back(v);
- return true;
- }
-
- bool push_back(value_type&& v) {
- Impl::push_back(std::move(v));
- return true;
- }
-
- using Impl::pop_back;
-
- void unstable_erase(iterator it) {
- if (it != last()) std::iter_swap(it, last());
- pop_back();
- }
-
- void swap(SmallVector& other) { Impl::swap(other); }
-};
-
-template <typename>
-struct is_small_vector : std::false_type {};
-
-template <typename T, std::size_t N>
-struct is_small_vector<SmallVector<T, N>> : std::true_type {};
-
-// Deduction guide for array constructor.
-template <typename T, std::size_t N>
-SmallVector(T (&)[N]) -> SmallVector<std::remove_cv_t<T>, N>;
-
-// Deduction guide for variadic constructor.
-template <typename T, typename... Us, typename V = std::decay_t<T>,
- typename = std::enable_if_t<(std::is_constructible_v<V, Us> && ...)>>
-SmallVector(T&&, Us&&...) -> SmallVector<V, 1 + sizeof...(Us)>;
-
-// Deduction guide for in-place constructor.
-template <typename T, std::size_t... Sizes, typename... Types>
-SmallVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
- -> SmallVector<T, sizeof...(Sizes)>;
-
-// Deduction guide for StaticVector conversion.
-template <typename T, std::size_t N>
-SmallVector(StaticVector<T, N>&&) -> SmallVector<T, N>;
-
-template <typename T, std::size_t N>
-inline void swap(SmallVector<T, N>& lhs, SmallVector<T, N>& rhs) {
- lhs.swap(rhs);
-}
-
-} // namespace android::ftl
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
deleted file mode 100644
index 96a1ae853d..0000000000
--- a/include/ftl/static_vector.h
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <ftl/array_traits.h>
-#include <ftl/initializer_list.h>
-
-#include <algorithm>
-#include <cassert>
-#include <iterator>
-#include <memory>
-#include <type_traits>
-#include <utility>
-
-namespace android::ftl {
-
-constexpr struct IteratorRangeTag {
-} kIteratorRange;
-
-// Fixed-capacity, statically allocated counterpart of std::vector. Like std::array, StaticVector
-// allocates contiguous storage for N elements of type T at compile time, but stores at most (rather
-// than exactly) N elements. Unlike std::array, its default constructor does not require T to have a
-// default constructor, since elements are constructed in place as the vector grows. Operations that
-// insert an element (emplace_back, push_back, etc.) fail when the vector is full. The API otherwise
-// adheres to standard containers, except the unstable_erase operation that does not preserve order,
-// and the replace operation that destructively emplaces.
-//
-// StaticVector<T, 1> is analogous to an iterable std::optional.
-// StaticVector<T, 0> is an error.
-//
-// Example usage:
-//
-// ftl::StaticVector<char, 3> vector;
-// assert(vector.empty());
-//
-// vector = {'a', 'b'};
-// assert(vector.size() == 2u);
-//
-// vector.push_back('c');
-// assert(vector.full());
-//
-// assert(!vector.push_back('d'));
-// assert(vector.size() == 3u);
-//
-// vector.unstable_erase(vector.begin());
-// assert(vector == (ftl::StaticVector{'c', 'b'}));
-//
-// vector.pop_back();
-// assert(vector.back() == 'c');
-//
-// const char array[] = "hi";
-// vector = ftl::StaticVector(array);
-// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
-//
-// ftl::StaticVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
-// assert(strings.size() == 3u);
-// assert(strings[0] == "abc");
-// assert(strings[1] == "123");
-// assert(strings[2] == "???");
-//
-template <typename T, std::size_t N>
-class StaticVector final : ArrayTraits<T>,
- ArrayIterators<StaticVector<T, N>, T>,
- ArrayComparators<StaticVector> {
- static_assert(N > 0);
-
- using ArrayTraits<T>::construct_at;
-
- using Iter = ArrayIterators<StaticVector, T>;
- friend Iter;
-
- // There is ambiguity when constructing from two iterator-like elements like pointers:
- // they could be an iterator range, or arguments for in-place construction. Assume the
- // latter unless they are input iterators and cannot be used to construct elements. If
- // the former is intended, the caller can pass an IteratorRangeTag to disambiguate.
- template <typename I, typename Traits = std::iterator_traits<I>>
- using is_input_iterator =
- std::conjunction<std::is_base_of<std::input_iterator_tag, typename Traits::iterator_category>,
- std::negation<std::is_constructible<T, I>>>;
-
- public:
- FTL_ARRAY_TRAIT(T, value_type);
- FTL_ARRAY_TRAIT(T, size_type);
- FTL_ARRAY_TRAIT(T, difference_type);
-
- FTL_ARRAY_TRAIT(T, pointer);
- FTL_ARRAY_TRAIT(T, reference);
- FTL_ARRAY_TRAIT(T, iterator);
- FTL_ARRAY_TRAIT(T, reverse_iterator);
-
- FTL_ARRAY_TRAIT(T, const_pointer);
- FTL_ARRAY_TRAIT(T, const_reference);
- FTL_ARRAY_TRAIT(T, const_iterator);
- FTL_ARRAY_TRAIT(T, const_reverse_iterator);
-
- // Creates an empty vector.
- StaticVector() = default;
-
- // Copies and moves a vector, respectively.
- StaticVector(const StaticVector& other)
- : StaticVector(kIteratorRange, other.begin(), other.end()) {}
-
- StaticVector(StaticVector&& other) { swap<true>(other); }
-
- // Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
- StaticVector(const StaticVector<U, M>& other)
- : StaticVector(kIteratorRange, other.begin(), other.end()) {}
-
- // Copies at most N elements from an array.
- template <typename U, std::size_t M>
- explicit StaticVector(U (&array)[M])
- : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {}
-
- // Copies at most N elements from the range [first, last).
- //
- // IteratorRangeTag disambiguates with initialization from two iterator-like elements.
- //
- template <typename Iterator, typename = std::enable_if_t<is_input_iterator<Iterator>{}>>
- StaticVector(Iterator first, Iterator last) : StaticVector(kIteratorRange, first, last) {
- using V = typename std::iterator_traits<Iterator>::value_type;
- static_assert(std::is_constructible_v<value_type, V>, "Incompatible iterator range");
- }
-
- template <typename Iterator>
- StaticVector(IteratorRangeTag, Iterator first, Iterator last)
- : size_(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
- std::uninitialized_copy(first, first + size_, begin());
- }
-
- // Constructs at most N elements. The template arguments T and N are inferred using the
- // deduction guide defined below. Note that T is determined from the first element, and
- // subsequent elements must have convertible types:
- //
- // ftl::StaticVector vector = {1, 2, 3};
- // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<int, 3>>);
- //
- // const auto copy = "quince"s;
- // auto move = "tart"s;
- // ftl::StaticVector vector = {copy, std::move(move)};
- //
- // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 2>>);
- //
- template <typename E, typename... Es,
- typename = std::enable_if_t<std::is_constructible_v<value_type, E>>>
- StaticVector(E&& element, Es&&... elements)
- : StaticVector(std::index_sequence<0>{}, std::forward<E>(element),
- std::forward<Es>(elements)...) {
- static_assert(sizeof...(elements) < N, "Too many elements");
- }
-
- // Constructs at most N elements in place by forwarding per-element constructor arguments. The
- // template arguments T and N are inferred using the deduction guide defined below. The syntax
- // for listing arguments is as follows:
- //
- // ftl::StaticVector vector = ftl::init::list<std::string>("abc")()(3u, '?');
- //
- // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
- // assert(vector.full());
- // assert(vector[0] == "abc");
- // assert(vector[1].empty());
- // assert(vector[2] == "???");
- //
- template <typename U, std::size_t Size, std::size_t... Sizes, typename... Types>
- StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& list)
- : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
- std::index_sequence<Sizes...>{}, list.tuple) {}
-
- ~StaticVector() { std::destroy(begin(), end()); }
-
- StaticVector& operator=(const StaticVector& other) {
- StaticVector copy(other);
- swap(copy);
- return *this;
- }
-
- StaticVector& operator=(StaticVector&& other) {
- std::destroy(begin(), end());
- size_ = 0;
- swap<true>(other);
- return *this;
- }
-
- // IsEmpty enables a fast path when the vector is known to be empty at compile time.
- template <bool IsEmpty = false>
- void swap(StaticVector&);
-
- static constexpr size_type max_size() { return N; }
- size_type size() const { return size_; }
-
- bool empty() const { return size() == 0; }
- bool full() const { return size() == max_size(); }
-
- iterator begin() { return std::launder(reinterpret_cast<pointer>(data_)); }
- iterator end() { return begin() + size(); }
-
- using Iter::begin;
- using Iter::end;
-
- using Iter::cbegin;
- using Iter::cend;
-
- using Iter::rbegin;
- using Iter::rend;
-
- using Iter::crbegin;
- using Iter::crend;
-
- using Iter::last;
-
- using Iter::back;
- using Iter::front;
-
- using Iter::operator[];
-
- // Replaces an element, and returns a reference to it. The iterator must be dereferenceable, so
- // replacing at end() is erroneous.
- //
- // The element is emplaced via move constructor, so type T does not need to define copy/move
- // assignment, e.g. its data members may be const.
- //
- // The arguments may directly or indirectly refer to the element being replaced.
- //
- // Iterators to the replaced element point to its replacement, and others remain valid.
- //
- template <typename... Args>
- reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
- }
-
- // Appends an element, and returns an iterator to it. If the vector is full, the element is not
- // inserted, and the end() iterator is returned.
- //
- // On success, the end() iterator is invalidated.
- //
- template <typename... Args>
- iterator emplace_back(Args&&... args) {
- if (full()) return end();
- const iterator it = construct_at(end(), std::forward<Args>(args)...);
- ++size_;
- return it;
- }
-
- // Appends an element unless the vector is full, and returns whether the element was inserted.
- //
- // On success, the end() iterator is invalidated.
- //
- bool push_back(const value_type& v) {
- // Two statements for sequence point.
- const iterator it = emplace_back(v);
- return it != end();
- }
-
- bool push_back(value_type&& v) {
- // Two statements for sequence point.
- const iterator it = emplace_back(std::move(v));
- return it != end();
- }
-
- // Removes the last element. The vector must not be empty, or the call is erroneous.
- //
- // The last() and end() iterators are invalidated.
- //
- void pop_back() { unstable_erase(last()); }
-
- // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
- // this moves the last element to the slot of the erased element.
- //
- // The last() and end() iterators, as well as those to the erased element, are invalidated.
- //
- void unstable_erase(const_iterator it) {
- std::destroy_at(it);
- if (it != last()) {
- // Move last element and destroy its source for destructor side effects. This is only
- // safe because exceptions are disabled.
- construct_at(it, std::move(back()));
- std::destroy_at(last());
- }
- --size_;
- }
-
- private:
- // Recursion for variadic constructor.
- template <std::size_t I, typename E, typename... Es>
- StaticVector(std::index_sequence<I>, E&& element, Es&&... elements)
- : StaticVector(std::index_sequence<I + 1>{}, std::forward<Es>(elements)...) {
- construct_at(begin() + I, std::forward<E>(element));
- }
-
- // Base case for variadic constructor.
- template <std::size_t I>
- explicit StaticVector(std::index_sequence<I>) : size_(I) {}
-
- // Recursion for in-place constructor.
- //
- // Construct element I by extracting its arguments from the InitializerList tuple. ArgIndex
- // is the position of its first argument in Args, and ArgCount is the number of arguments.
- // The Indices sequence corresponds to [0, ArgCount).
- //
- // The Sizes sequence lists the argument counts for elements after I, so Size is the ArgCount
- // for the next element. The recursion stops when Sizes is empty for the last element.
- //
- template <std::size_t I, std::size_t ArgIndex, std::size_t ArgCount, std::size_t... Indices,
- std::size_t Size, std::size_t... Sizes, typename... Args>
- StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
- std::index_sequence<Size, Sizes...>, std::tuple<Args...>& tuple)
- : StaticVector(std::index_sequence<I + 1, ArgIndex + ArgCount, Size>{},
- std::make_index_sequence<Size>{}, std::index_sequence<Sizes...>{}, tuple) {
- construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
- }
-
- // Base case for in-place constructor.
- template <std::size_t I, std::size_t ArgIndex, std::size_t ArgCount, std::size_t... Indices,
- typename... Args>
- StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
- std::index_sequence<>, std::tuple<Args...>& tuple)
- : size_(I + 1) {
- construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
- }
-
- size_type size_ = 0;
- std::aligned_storage_t<sizeof(value_type), alignof(value_type)> data_[N];
-};
-
-// Deduction guide for array constructor.
-template <typename T, std::size_t N>
-StaticVector(T (&)[N]) -> StaticVector<std::remove_cv_t<T>, N>;
-
-// Deduction guide for variadic constructor.
-template <typename T, typename... Us, typename V = std::decay_t<T>,
- typename = std::enable_if_t<(std::is_constructible_v<V, Us> && ...)>>
-StaticVector(T&&, Us&&...) -> StaticVector<V, 1 + sizeof...(Us)>;
-
-// Deduction guide for in-place constructor.
-template <typename T, std::size_t... Sizes, typename... Types>
-StaticVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
- -> StaticVector<T, sizeof...(Sizes)>;
-
-template <typename T, std::size_t N>
-template <bool IsEmpty>
-void StaticVector<T, N>::swap(StaticVector& other) {
- auto [to, from] = std::make_pair(this, &other);
- if (from == this) return;
-
- // Assume this vector has fewer elements, so the excess of the other vector will be moved to it.
- auto [min, max] = std::make_pair(size(), other.size());
-
- // No elements to swap if moving into an empty vector.
- if constexpr (IsEmpty) {
- assert(min == 0);
- } else {
- if (min > max) {
- std::swap(from, to);
- std::swap(min, max);
- }
-
- // Swap elements [0, min).
- std::swap_ranges(begin(), begin() + min, other.begin());
-
- // No elements to move if sizes are equal.
- if (min == max) return;
- }
-
- // Move elements [min, max) and destroy their source for destructor side effects.
- const auto [first, last] = std::make_pair(from->begin() + min, from->begin() + max);
- std::uninitialized_move(first, last, to->begin() + min);
- std::destroy(first, last);
-
- std::swap(size_, other.size_);
-}
-
-template <typename T, std::size_t N>
-inline void swap(StaticVector<T, N>& lhs, StaticVector<T, N>& rhs) {
- lhs.swap(rhs);
-}
-
-} // namespace android::ftl