Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 1 | // Copyright 2021 The Dawn & Tint Authors |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 2 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 3 | // Redistribution and use in source and binary forms, with or without |
| 4 | // modification, are permitted provided that the following conditions are met: |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 5 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 6 | // 1. Redistributions of source code must retain the above copyright notice, this |
| 7 | // list of conditions and the following disclaimer. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 8 | // |
Austin Eng | cc2516a | 2023-10-17 20:57:54 +0000 | [diff] [blame] | 9 | // 2. Redistributions in binary form must reproduce the above copyright notice, |
| 10 | // this list of conditions and the following disclaimer in the documentation |
| 11 | // and/or other materials provided with the distribution. |
| 12 | // |
| 13 | // 3. Neither the name of the copyright holder nor the names of its |
| 14 | // contributors may be used to endorse or promote products derived from |
| 15 | // this software without specific prior written permission. |
| 16 | // |
| 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| 21 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 24 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 27 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 28 | #ifndef SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_ |
| 29 | #define SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_ |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 30 | |
| 31 | #include <cstddef> |
| 32 | #include <functional> |
| 33 | #include <unordered_set> |
| 34 | #include <utility> |
| 35 | #include <vector> |
| 36 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 37 | #include "src/tint/utils/containers/hashset.h" |
| 38 | #include "src/tint/utils/containers/vector.h" |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 39 | |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 40 | namespace tint { |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 41 | |
| 42 | /// UniqueVector is an ordered container that only contains unique items. |
| 43 | /// Attempting to add a duplicate is a no-op. |
Ben Clayton | 76aec25 | 2024-02-05 20:49:36 +0000 | [diff] [blame] | 44 | template <typename T, size_t N, typename HASH = Hasher<T>, typename EQUAL = std::equal_to<T>> |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 45 | struct UniqueVector { |
Ben Clayton | 63d0fab | 2023-03-06 15:43:16 +0000 | [diff] [blame] | 46 | /// STL-friendly alias to T. Used by gmock. |
| 47 | using value_type = T; |
| 48 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 49 | /// Constructor |
| 50 | UniqueVector() = default; |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 51 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 52 | /// Constructor |
| 53 | /// @param v the vector to construct this UniqueVector with. Duplicate |
| 54 | /// elements will be removed. |
| 55 | explicit UniqueVector(std::vector<T>&& v) { |
| 56 | for (auto& el : v) { |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 57 | Add(el); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 58 | } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 59 | } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 60 | |
Ben Clayton | 5ef873a | 2023-06-27 17:33:06 +0000 | [diff] [blame] | 61 | /// Add appends the item to the end of the vector, if the vector does not |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 62 | /// already contain the given item. |
| 63 | /// @param item the item to append to the end of the vector |
| 64 | /// @returns true if the item was added, otherwise false. |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 65 | bool Add(const T& item) { |
| 66 | if (set.Add(item)) { |
| 67 | vector.Push(item); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 68 | return true; |
| 69 | } |
| 70 | return false; |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 71 | } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 72 | |
Ben Clayton | 5ef873a | 2023-06-27 17:33:06 +0000 | [diff] [blame] | 73 | /// Removes @p count elements from the vector |
| 74 | /// @param start the index of the first element to remove |
| 75 | /// @param count the number of elements to remove |
| 76 | void Erase(size_t start, size_t count = 1) { |
| 77 | for (size_t i = 0; i < count; i++) { |
| 78 | set.Remove(vector[start + i]); |
| 79 | } |
| 80 | vector.Erase(start, count); |
| 81 | } |
| 82 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 83 | /// @returns true if the vector contains `item` |
| 84 | /// @param item the item |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 85 | bool Contains(const T& item) const { return set.Contains(item); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 86 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 87 | /// @param i the index of the element to retrieve |
| 88 | /// @returns the element at the index `i` |
| 89 | T& operator[](size_t i) { return vector[i]; } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 90 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 91 | /// @param i the index of the element to retrieve |
| 92 | /// @returns the element at the index `i` |
| 93 | const T& operator[](size_t i) const { return vector[i]; } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 94 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 95 | /// @returns true if the vector is empty |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 96 | bool IsEmpty() const { return vector.IsEmpty(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 97 | |
Ben Clayton | 5ef873a | 2023-06-27 17:33:06 +0000 | [diff] [blame] | 98 | /// Removes all elements from the vector |
| 99 | void Clear() { |
| 100 | vector.Clear(); |
| 101 | set.Clear(); |
| 102 | } |
| 103 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 104 | /// @returns the number of items in the vector |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 105 | size_t Length() const { return vector.Length(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 106 | |
Ben Clayton | d99af03 | 2022-05-20 09:03:50 +0000 | [diff] [blame] | 107 | /// @returns the pointer to the first element in the vector, or nullptr if the vector is empty. |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 108 | const T* Data() const { return vector.IsEmpty() ? nullptr : &vector[0]; } |
Ben Clayton | d99af03 | 2022-05-20 09:03:50 +0000 | [diff] [blame] | 109 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 110 | /// @returns an iterator to the beginning of the vector |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 111 | auto begin() const { return vector.begin(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 112 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 113 | /// @returns an iterator to the end of the vector |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 114 | auto end() const { return vector.end(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 115 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 116 | /// @returns an iterator to the beginning of the reversed vector |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 117 | auto rbegin() const { return vector.rbegin(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 118 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 119 | /// @returns an iterator to the end of the reversed vector |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 120 | auto rend() const { return vector.rend(); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 121 | |
Ben Clayton | 49334b0 | 2022-12-06 19:39:02 +0000 | [diff] [blame] | 122 | /// @returns a reference to the internal vector |
| 123 | operator VectorRef<T>() const { return vector; } |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 124 | |
| 125 | /// @returns the std::move()'d vector. |
| 126 | /// @note The UniqueVector must not be used after calling this method |
| 127 | VectorRef<T> Release() { return std::move(vector); } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 128 | |
Ben Clayton | 7d04ced | 2022-08-03 08:43:15 +0000 | [diff] [blame] | 129 | /// Pre-allocates `count` elements in the vector and set |
| 130 | /// @param count the number of elements to pre-allocate |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 131 | void Reserve(size_t count) { |
| 132 | vector.Reserve(count); |
| 133 | set.Reserve(count); |
Ben Clayton | 7d04ced | 2022-08-03 08:43:15 +0000 | [diff] [blame] | 134 | } |
| 135 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 136 | /// Removes the last element from the vector |
| 137 | /// @returns the popped element |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 138 | T Pop() { |
| 139 | set.Remove(vector.Back()); |
| 140 | return vector.Pop(); |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 141 | } |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 142 | |
Ben Clayton | 5ef873a | 2023-06-27 17:33:06 +0000 | [diff] [blame] | 143 | /// Removes the last element from the vector if it is equal to @p value |
| 144 | /// @param value the value to pop if it is at the back of the vector |
| 145 | /// @returns true if the value was popped, otherwise false |
| 146 | bool TryPop(T value) { |
| 147 | if (!vector.IsEmpty() && vector.Back() == value) { |
| 148 | set.Remove(vector.Back()); |
| 149 | vector.Pop(); |
| 150 | return true; |
| 151 | } |
| 152 | return false; |
| 153 | } |
| 154 | |
dan sinclair | 41e4d9a | 2022-05-01 14:40:55 +0000 | [diff] [blame] | 155 | private: |
Ben Clayton | dce63f5 | 2022-08-17 18:07:20 +0000 | [diff] [blame] | 156 | Vector<T, N> vector; |
| 157 | Hashset<T, N, HASH, EQUAL> set; |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 158 | }; |
| 159 | |
dan sinclair | bae54e7 | 2023-07-28 15:01:54 +0000 | [diff] [blame] | 160 | } // namespace tint |
Ryan Harrison | dbc13af | 2022-02-21 15:19:07 +0000 | [diff] [blame] | 161 | |
dan sinclair | 22b4dd2 | 2023-07-21 00:40:07 +0000 | [diff] [blame] | 162 | #endif // SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_ |