blob: 38e471456e560f794f1834466bc0fae96abf406b [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2021 The Dawn & Tint Authors
Ryan Harrisondbc13af2022-02-21 15:19:07 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
Ryan Harrisondbc13af2022-02-21 15:19:07 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
Ryan Harrisondbc13af2022-02-21 15:19:07 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 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 Harrisondbc13af2022-02-21 15:19:07 +000027
dan sinclair22b4dd22023-07-21 00:40:07 +000028#ifndef SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_
29#define SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_
Ryan Harrisondbc13af2022-02-21 15:19:07 +000030
31#include <cstddef>
32#include <functional>
33#include <unordered_set>
34#include <utility>
35#include <vector>
36
dan sinclair22b4dd22023-07-21 00:40:07 +000037#include "src/tint/utils/containers/hashset.h"
38#include "src/tint/utils/containers/vector.h"
Ben Claytondce63f52022-08-17 18:07:20 +000039
dan sinclairbae54e72023-07-28 15:01:54 +000040namespace tint {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000041
42/// UniqueVector is an ordered container that only contains unique items.
43/// Attempting to add a duplicate is a no-op.
Ben Clayton76aec252024-02-05 20:49:36 +000044template <typename T, size_t N, typename HASH = Hasher<T>, typename EQUAL = std::equal_to<T>>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000045struct UniqueVector {
Ben Clayton63d0fab2023-03-06 15:43:16 +000046 /// STL-friendly alias to T. Used by gmock.
47 using value_type = T;
48
dan sinclair41e4d9a2022-05-01 14:40:55 +000049 /// Constructor
50 UniqueVector() = default;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000051
dan sinclair41e4d9a2022-05-01 14:40:55 +000052 /// 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 Claytondce63f52022-08-17 18:07:20 +000057 Add(el);
dan sinclair41e4d9a2022-05-01 14:40:55 +000058 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000059 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000060
Ben Clayton5ef873a2023-06-27 17:33:06 +000061 /// Add appends the item to the end of the vector, if the vector does not
dan sinclair41e4d9a2022-05-01 14:40:55 +000062 /// 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 Claytondce63f52022-08-17 18:07:20 +000065 bool Add(const T& item) {
66 if (set.Add(item)) {
67 vector.Push(item);
dan sinclair41e4d9a2022-05-01 14:40:55 +000068 return true;
69 }
70 return false;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000071 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000072
Ben Clayton5ef873a2023-06-27 17:33:06 +000073 /// 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 sinclair41e4d9a2022-05-01 14:40:55 +000083 /// @returns true if the vector contains `item`
84 /// @param item the item
Ben Claytondce63f52022-08-17 18:07:20 +000085 bool Contains(const T& item) const { return set.Contains(item); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000086
dan sinclair41e4d9a2022-05-01 14:40:55 +000087 /// @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 Harrisondbc13af2022-02-21 15:19:07 +000090
dan sinclair41e4d9a2022-05-01 14:40:55 +000091 /// @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 Harrisondbc13af2022-02-21 15:19:07 +000094
dan sinclair41e4d9a2022-05-01 14:40:55 +000095 /// @returns true if the vector is empty
Ben Claytondce63f52022-08-17 18:07:20 +000096 bool IsEmpty() const { return vector.IsEmpty(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000097
Ben Clayton5ef873a2023-06-27 17:33:06 +000098 /// Removes all elements from the vector
99 void Clear() {
100 vector.Clear();
101 set.Clear();
102 }
103
dan sinclair41e4d9a2022-05-01 14:40:55 +0000104 /// @returns the number of items in the vector
Ben Claytondce63f52022-08-17 18:07:20 +0000105 size_t Length() const { return vector.Length(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000106
Ben Claytond99af032022-05-20 09:03:50 +0000107 /// @returns the pointer to the first element in the vector, or nullptr if the vector is empty.
Ben Claytondce63f52022-08-17 18:07:20 +0000108 const T* Data() const { return vector.IsEmpty() ? nullptr : &vector[0]; }
Ben Claytond99af032022-05-20 09:03:50 +0000109
dan sinclair41e4d9a2022-05-01 14:40:55 +0000110 /// @returns an iterator to the beginning of the vector
Ben Claytondce63f52022-08-17 18:07:20 +0000111 auto begin() const { return vector.begin(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000112
dan sinclair41e4d9a2022-05-01 14:40:55 +0000113 /// @returns an iterator to the end of the vector
Ben Claytondce63f52022-08-17 18:07:20 +0000114 auto end() const { return vector.end(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000115
dan sinclair41e4d9a2022-05-01 14:40:55 +0000116 /// @returns an iterator to the beginning of the reversed vector
Ben Claytondce63f52022-08-17 18:07:20 +0000117 auto rbegin() const { return vector.rbegin(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000118
dan sinclair41e4d9a2022-05-01 14:40:55 +0000119 /// @returns an iterator to the end of the reversed vector
Ben Claytondce63f52022-08-17 18:07:20 +0000120 auto rend() const { return vector.rend(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000121
Ben Clayton49334b02022-12-06 19:39:02 +0000122 /// @returns a reference to the internal vector
123 operator VectorRef<T>() const { return vector; }
Ben Claytondce63f52022-08-17 18:07:20 +0000124
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 Harrisondbc13af2022-02-21 15:19:07 +0000128
Ben Clayton7d04ced2022-08-03 08:43:15 +0000129 /// Pre-allocates `count` elements in the vector and set
130 /// @param count the number of elements to pre-allocate
Ben Claytondce63f52022-08-17 18:07:20 +0000131 void Reserve(size_t count) {
132 vector.Reserve(count);
133 set.Reserve(count);
Ben Clayton7d04ced2022-08-03 08:43:15 +0000134 }
135
dan sinclair41e4d9a2022-05-01 14:40:55 +0000136 /// Removes the last element from the vector
137 /// @returns the popped element
Ben Claytondce63f52022-08-17 18:07:20 +0000138 T Pop() {
139 set.Remove(vector.Back());
140 return vector.Pop();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000141 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000142
Ben Clayton5ef873a2023-06-27 17:33:06 +0000143 /// 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 sinclair41e4d9a2022-05-01 14:40:55 +0000155 private:
Ben Claytondce63f52022-08-17 18:07:20 +0000156 Vector<T, N> vector;
157 Hashset<T, N, HASH, EQUAL> set;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000158};
159
dan sinclairbae54e72023-07-28 15:01:54 +0000160} // namespace tint
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000161
dan sinclair22b4dd22023-07-21 00:40:07 +0000162#endif // SRC_TINT_UTILS_CONTAINERS_UNIQUE_VECTOR_H_