blob: e629ce2da7c4168627e17a9879cc564cd07ff175 [file] [log] [blame]
[email protected]8fc56182014-08-06 21:44:331// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef TOOLS_GN_UNIQUE_VECTOR_H_
6#define TOOLS_GN_UNIQUE_VECTOR_H_
7
avicab0f832015-12-26 07:00:398#include <stddef.h>
9
[email protected]8fc56182014-08-06 21:44:3310#include <algorithm>
11
12#include "base/containers/hash_tables.h"
13
14namespace internal {
15
16// This lass allows us to insert things by reference into a hash table which
17// avoids copies. The hash function of a UniquifyRef is that of the object it
18// points to.
19//
20// There are two ways it can store data: (1) by (vector*, index) which is used
21// to refer to the array in UniqueVector and make it work even when the
22// underlying vector is reallocated; (2) by T* which is used to do lookups
23// into the hash table of things that aren't in a vector yet.
24//
25// It also caches the hash value which allows us to query and then insert
26// without recomputing the hash.
27template<typename T>
28class UniquifyRef {
29 public:
30 UniquifyRef()
tfarina026335872015-01-13 03:35:3931 : value_(nullptr),
32 vect_(nullptr),
[email protected]8fc56182014-08-06 21:44:3333 index_(static_cast<size_t>(-1)),
34 hash_val_(0) {
35 }
36
37 // Initialize with a pointer to a value.
tfarinadc6279e302015-03-02 03:07:1538 explicit UniquifyRef(const T* v)
[email protected]8fc56182014-08-06 21:44:3339 : value_(v),
tfarina026335872015-01-13 03:35:3940 vect_(nullptr),
[email protected]8fc56182014-08-06 21:44:3341 index_(static_cast<size_t>(-1)) {
42 FillHashValue();
43 }
44
45 // Initialize with an array + index.
46 UniquifyRef(const std::vector<T>* v, size_t i)
tfarina026335872015-01-13 03:35:3947 : value_(nullptr),
[email protected]8fc56182014-08-06 21:44:3348 vect_(v),
49 index_(i) {
50 FillHashValue();
51 }
52
53 // Initialize with an array + index and a known hash value to prevent
54 // re-hashing.
55 UniquifyRef(const std::vector<T>* v, size_t i, size_t hash_value)
tfarina026335872015-01-13 03:35:3956 : value_(nullptr),
[email protected]8fc56182014-08-06 21:44:3357 vect_(v),
58 index_(i),
59 hash_val_(hash_value) {
60 }
61
62 const T& value() const { return value_ ? *value_ : (*vect_)[index_]; }
63 size_t hash_val() const { return hash_val_; }
64 size_t index() const { return index_; }
65
66 private:
67 void FillHashValue() {
[email protected]8fc56182014-08-06 21:44:3368 BASE_HASH_NAMESPACE::hash<T> h;
69 hash_val_ = h(value());
[email protected]8fc56182014-08-06 21:44:3370 }
71
72 // When non-null, points to the object.
73 const T* value_;
74
75 // When value is null these are used.
76 const std::vector<T>* vect_;
77 size_t index_;
78
79 size_t hash_val_;
80};
81
82template<typename T> inline bool operator==(const UniquifyRef<T>& a,
83 const UniquifyRef<T>& b) {
84 return a.value() == b.value();
85}
86
87template<typename T> inline bool operator<(const UniquifyRef<T>& a,
88 const UniquifyRef<T>& b) {
89 return a.value() < b.value();
90}
91
92} // namespace internal
93
94namespace BASE_HASH_NAMESPACE {
95
[email protected]8fc56182014-08-06 21:44:3396template<typename T> struct hash< internal::UniquifyRef<T> > {
97 std::size_t operator()(const internal::UniquifyRef<T>& v) const {
98 return v.hash_val();
99 }
100};
[email protected]8fc56182014-08-06 21:44:33101
102} // namespace BASE_HASH_NAMESPACE
103
104// An ordered set optimized for GN's usage. Such sets are used to store lists
105// of configs and libraries, and are appended to but not randomly inserted
106// into.
107template<typename T>
108class UniqueVector {
109 public:
110 typedef std::vector<T> Vector;
111 typedef typename Vector::iterator iterator;
112 typedef typename Vector::const_iterator const_iterator;
113
114 const Vector& vector() const { return vector_; }
115 size_t size() const { return vector_.size(); }
116 bool empty() const { return vector_.empty(); }
117 void clear() { vector_.clear(); set_.clear(); }
118 void reserve(size_t s) { vector_.reserve(s); }
119
120 const T& operator[](size_t index) const { return vector_[index]; }
121
122 const_iterator begin() const { return vector_.begin(); }
123 iterator begin() { return vector_.begin(); }
124 const_iterator end() const { return vector_.end(); }
125 iterator end() { return vector_.end(); }
126
127 // Returns true if the item was appended, false if it already existed (and
128 // thus the vector was not modified).
129 bool push_back(const T& t) {
130 Ref ref(&t);
131 if (set_.find(ref) != set_.end())
132 return false; // Already have this one.
133
134 vector_.push_back(t);
135 set_.insert(Ref(&vector_, vector_.size() - 1, ref.hash_val()));
136 return true;
137 }
138
139 // Like push_back but swaps in the type to avoid a copy.
140 bool PushBackViaSwap(T* t) {
141 using std::swap;
142
143 Ref ref(t);
144 if (set_.find(ref) != set_.end())
145 return false; // Already have this one.
146
147 size_t new_index = vector_.size();
148 vector_.resize(new_index + 1);
149 swap(vector_[new_index], *t);
150 set_.insert(Ref(&vector_, vector_.size() - 1, ref.hash_val()));
151 return true;
152 }
153
154 // Appends a range of items from an iterator.
155 template<typename iter> void Append(const iter& begin, const iter& end) {
156 for (iter i = begin; i != end; ++i)
157 push_back(*i);
158 }
159
160 // Returns the index of the item matching the given value in the list, or
161 // (size_t)(-1) if it's not found.
162 size_t IndexOf(const T& t) const {
163 Ref ref(&t);
164 typename HashSet::const_iterator found = set_.find(ref);
165 if (found == set_.end())
166 return static_cast<size_t>(-1);
167 return found->index();
168 }
169
170 private:
171 typedef internal::UniquifyRef<T> Ref;
172 typedef base::hash_set<Ref> HashSet;
173
174 HashSet set_;
175 Vector vector_;
176};
177
178#endif // TOOLS_GN_UNIQUE_VECTOR_H_