| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2020 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #pragma once | 
|  | 18 |  | 
|  | 19 | #include <algorithm> | 
|  | 20 | #include <iterator> | 
|  | 21 | #include <new> | 
| Dominik Laskowski | ccd50a4 | 2020-10-30 19:56:38 -0700 | [diff] [blame] | 22 | #include <type_traits> | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 23 |  | 
|  | 24 | #define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U | 
|  | 25 |  | 
|  | 26 | namespace android::ftl { | 
|  | 27 |  | 
|  | 28 | template <typename T> | 
|  | 29 | struct ArrayTraits { | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 30 | using value_type = T; | 
|  | 31 | using size_type = std::size_t; | 
|  | 32 | using difference_type = std::ptrdiff_t; | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 33 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 34 | using pointer = value_type*; | 
|  | 35 | using reference = value_type&; | 
|  | 36 | using iterator = pointer; | 
|  | 37 | using reverse_iterator = std::reverse_iterator<iterator>; | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 38 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 39 | using const_pointer = const value_type*; | 
|  | 40 | using const_reference = const value_type&; | 
|  | 41 | using const_iterator = const_pointer; | 
|  | 42 | using const_reverse_iterator = std::reverse_iterator<const_iterator>; | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 43 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 44 | template <typename... Args> | 
|  | 45 | static pointer construct_at(const_iterator it, Args&&... args) { | 
|  | 46 | void* const ptr = const_cast<void*>(static_cast<const void*>(it)); | 
|  | 47 | if constexpr (std::is_constructible_v<value_type, Args...>) { | 
|  | 48 | // TODO: Replace with std::construct_at in C++20. | 
|  | 49 | return new (ptr) value_type(std::forward<Args>(args)...); | 
|  | 50 | } else { | 
|  | 51 | // Fall back to list initialization. | 
|  | 52 | return new (ptr) value_type{std::forward<Args>(args)...}; | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 53 | } | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 54 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 55 | }; | 
|  | 56 |  | 
|  | 57 | // CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end. | 
|  | 58 | template <typename Self, typename T> | 
|  | 59 | class ArrayIterators { | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 60 | FTL_ARRAY_TRAIT(T, size_type); | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 61 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 62 | FTL_ARRAY_TRAIT(T, reference); | 
|  | 63 | FTL_ARRAY_TRAIT(T, iterator); | 
|  | 64 | FTL_ARRAY_TRAIT(T, reverse_iterator); | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 65 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 66 | FTL_ARRAY_TRAIT(T, const_reference); | 
|  | 67 | FTL_ARRAY_TRAIT(T, const_iterator); | 
|  | 68 | FTL_ARRAY_TRAIT(T, const_reverse_iterator); | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 69 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 70 | Self& self() const { return *const_cast<Self*>(static_cast<const Self*>(this)); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 71 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 72 | public: | 
|  | 73 | const_iterator begin() const { return cbegin(); } | 
|  | 74 | const_iterator cbegin() const { return self().begin(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 75 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 76 | const_iterator end() const { return cend(); } | 
|  | 77 | const_iterator cend() const { return self().end(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 78 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 79 | reverse_iterator rbegin() { return std::make_reverse_iterator(self().end()); } | 
|  | 80 | const_reverse_iterator rbegin() const { return crbegin(); } | 
|  | 81 | const_reverse_iterator crbegin() const { return self().rbegin(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 82 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 83 | reverse_iterator rend() { return std::make_reverse_iterator(self().begin()); } | 
|  | 84 | const_reverse_iterator rend() const { return crend(); } | 
|  | 85 | const_reverse_iterator crend() const { return self().rend(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 86 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 87 | iterator last() { return self().end() - 1; } | 
|  | 88 | const_iterator last() const { return self().last(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 89 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 90 | reference front() { return *self().begin(); } | 
|  | 91 | const_reference front() const { return self().front(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 92 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 93 | reference back() { return *last(); } | 
|  | 94 | const_reference back() const { return self().back(); } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 95 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 96 | reference operator[](size_type i) { return *(self().begin() + i); } | 
|  | 97 | const_reference operator[](size_type i) const { return self()[i]; } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 98 | }; | 
|  | 99 |  | 
|  | 100 | // Mixin to define comparison operators for an array-like template. | 
|  | 101 | // TODO: Replace with operator<=> in C++20. | 
| Dominik Laskowski | 5444fc8 | 2020-11-24 13:41:10 -0800 | [diff] [blame] | 102 | template <template <typename, std::size_t> class Array> | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 103 | struct ArrayComparators { | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 104 | template <typename T, std::size_t N, std::size_t M> | 
|  | 105 | friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 106 | return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); | 
|  | 107 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 108 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 109 | template <typename T, std::size_t N, std::size_t M> | 
|  | 110 | friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 111 | return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); | 
|  | 112 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 113 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 114 | template <typename T, std::size_t N, std::size_t M> | 
|  | 115 | friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 116 | return rhs < lhs; | 
|  | 117 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 118 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 119 | template <typename T, std::size_t N, std::size_t M> | 
|  | 120 | friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 121 | return !(lhs == rhs); | 
|  | 122 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 123 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 124 | template <typename T, std::size_t N, std::size_t M> | 
|  | 125 | friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 126 | return !(lhs < rhs); | 
|  | 127 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 128 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 129 | template <typename T, std::size_t N, std::size_t M> | 
|  | 130 | friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) { | 
|  | 131 | return !(lhs > rhs); | 
|  | 132 | } | 
| Dominik Laskowski | 0bacf27 | 2020-10-22 14:08:27 -0700 | [diff] [blame] | 133 | }; | 
|  | 134 |  | 
| Dominik Laskowski | e21dbed | 2020-12-04 20:51:43 -0800 | [diff] [blame] | 135 | }  // namespace android::ftl |