Flutter Engine
The Flutter Engine
SkTMultiMap.h
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkTMultiMap_DEFINED
9#define SkTMultiMap_DEFINED
10
12
13/** A set that contains pointers to instances of T. Instances can be looked up with key Key.
14 * Multiple (possibly same) values can have the same key.
15 */
16template <typename T,
17 typename Key,
18 typename HashTraits=T>
20 struct ValueList {
21 explicit ValueList(T* value) : fValue(value), fNext(nullptr) {}
22
23 static const Key& GetKey(const ValueList& e) { return HashTraits::GetKey(*e.fValue); }
24 static uint32_t Hash(const Key& key) { return HashTraits::Hash(key); }
25 T* fValue;
26 ValueList* fNext;
27 };
28public:
29 SkTMultiMap() : fCount(0) {}
30
32 this->reset();
33 }
34
35 void reset() {
36 fHash.foreach([&](ValueList* vl) {
37 ValueList* next;
38 for (ValueList* it = vl; it; it = next) {
39 HashTraits::OnFree(it->fValue);
40 next = it->fNext;
41 delete it;
42 }
43 });
44 fHash.reset();
45 fCount = 0;
46 }
47
48 void insert(const Key& key, T* value) {
49 ValueList* list = fHash.find(key);
50 if (list) {
51 // The new ValueList entry is inserted as the second element in the
52 // linked list, and it will contain the value of the first element.
53 ValueList* newEntry = new ValueList(list->fValue);
54 newEntry->fNext = list->fNext;
55 // The existing first ValueList entry is updated to contain the
56 // inserted value.
57 list->fNext = newEntry;
58 list->fValue = value;
59 } else {
60 fHash.add(new ValueList(value));
61 }
62
63 ++fCount;
64 }
65
66 void remove(const Key& key, const T* value) {
67 ValueList* list = fHash.find(key);
68 // Temporarily making this safe for remove entries not in the map because of
69 // crbug.com/877915.
70#if 0
71 // Since we expect the caller to be fully aware of what is stored, just
72 // assert that the caller removes an existing value.
73 SkASSERT(list);
74 ValueList* prev = nullptr;
75 while (list->fValue != value) {
76 prev = list;
77 list = list->fNext;
78 }
79 this->internalRemove(prev, list, key);
80#else
81 ValueList* prev = nullptr;
82 while (list && list->fValue != value) {
83 prev = list;
84 list = list->fNext;
85 }
86 // Crash in Debug since it'd be great to detect a repro of 877915.
87 SkASSERT(list);
88 if (list) {
89 this->internalRemove(prev, list, key);
90 }
91#endif
92 }
93
94 T* find(const Key& key) const {
95 ValueList* list = fHash.find(key);
96 if (list) {
97 return list->fValue;
98 }
99 return nullptr;
100 }
101
102 template<class FindPredicate>
103 T* find(const Key& key, const FindPredicate f) {
104 ValueList* list = fHash.find(key);
105 while (list) {
106 if (f(list->fValue)){
107 return list->fValue;
108 }
109 list = list->fNext;
110 }
111 return nullptr;
112 }
113
114 template<class FindPredicate>
115 T* findAndRemove(const Key& key, const FindPredicate f) {
116 ValueList* list = fHash.find(key);
117
118 ValueList* prev = nullptr;
119 while (list) {
120 if (f(list->fValue)){
121 T* value = list->fValue;
122 this->internalRemove(prev, list, key);
123 return value;
124 }
125 prev = list;
126 list = list->fNext;
127 }
128 return nullptr;
129 }
130
131 int count() const { return fCount; }
132
133#ifdef SK_DEBUG
134 template <typename Fn> // f(T) or f(const T&)
135 void foreach(Fn&& fn) const {
136 fHash.foreach([&](const ValueList& vl) {
137 for (const ValueList* it = &vl; it; it = it->fNext) {
138 fn(*it->fValue);
139 }
140 });
141 }
142
143 bool has(const T* value, const Key& key) const {
144 for (ValueList* list = fHash.find(key); list; list = list->fNext) {
145 if (list->fValue == value) {
146 return true;
147 }
148 }
149 return false;
150 }
151
152 // This is not particularly fast and only used for validation, so debug only.
153 int countForKey(const Key& key) const {
154 int count = 0;
155 ValueList* list = fHash.find(key);
156 while (list) {
157 list = list->fNext;
158 ++count;
159 }
160 return count;
161 }
162#endif
163
164private:
166 int fCount;
167
168 void internalRemove(ValueList* prev, ValueList* elem, const Key& key) {
169 if (elem->fNext) {
170 ValueList* next = elem->fNext;
171 elem->fValue = next->fValue;
172 elem->fNext = next->fNext;
173 delete next;
174 } else if (prev) {
175 prev->fNext = nullptr;
176 delete elem;
177 } else {
178 fHash.remove(key);
179 delete elem;
180 }
181
182 --fCount;
183 }
184
185};
186
187#endif
Instance * fNext
TArray< uint32_t > Key
static float next(float f)
static float prev(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
T * find(const Key &key) const
void remove(const Key &key)
void foreach(Fn &&fn)
void add(T *entry)
int count() const
Definition: SkTMultiMap.h:131
T * find(const Key &key, const FindPredicate f)
Definition: SkTMultiMap.h:103
T * find(const Key &key) const
Definition: SkTMultiMap.h:94
void insert(const Key &key, T *value)
Definition: SkTMultiMap.h:48
void reset()
Definition: SkTMultiMap.h:35
void remove(const Key &key, const T *value)
Definition: SkTMultiMap.h:66
T * findAndRemove(const Key &key, const FindPredicate f)
Definition: SkTMultiMap.h:115
uint8_t value
static uint32_t Hash(uint32_t key)
Definition: hashmap_test.cc:65
#define T
Definition: precompiler.cc:65