blob: 3d6e38e45403b2f2dfb4230efc9b55bd7f2f5baa [file] [log] [blame]
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +00001/*
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
robertphillips7a037f42014-07-21 12:40:57 -07008#ifndef SkTMultiMap_DEFINED
9#define SkTMultiMap_DEFINED
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000010
11#include "GrTypes.h"
12#include "SkTDynamicHash.h"
13
14/** A set that contains pointers to instances of T. Instances can be looked up with key Key.
15 * Multiple (possibly same) values can have the same key.
16 */
17template <typename T,
18 typename Key,
commit-bot@chromium.org55bd9402014-04-02 19:17:00 +000019 typename HashTraits=T>
robertphillips7a037f42014-07-21 12:40:57 -070020class SkTMultiMap {
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000021 struct ValueList {
halcanary96fcdcc2015-08-27 07:41:13 -070022 explicit ValueList(T* value) : fValue(value), fNext(nullptr) {}
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000023
commit-bot@chromium.org55bd9402014-04-02 19:17:00 +000024 static const Key& GetKey(const ValueList& e) { return HashTraits::GetKey(*e.fValue); }
25 static uint32_t Hash(const Key& key) { return HashTraits::Hash(key); }
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000026 T* fValue;
27 ValueList* fNext;
28 };
29public:
robertphillips7a037f42014-07-21 12:40:57 -070030 SkTMultiMap() : fCount(0) {}
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000031
robertphillips7a037f42014-07-21 12:40:57 -070032 ~SkTMultiMap() {
Robert Phillips57aa3672017-07-21 11:38:13 -040033 typename SkTDynamicHash<ValueList, Key>::Iter iter(&fHash);
34 for ( ; !iter.done(); ++iter) {
35 ValueList* next;
36 for (ValueList* cur = &(*iter); cur; cur = next) {
37 next = cur->fNext;
38 delete cur;
39 }
40 }
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000041 }
42
43 void insert(const Key& key, T* value) {
44 ValueList* list = fHash.find(key);
bsalomon49f085d2014-09-05 13:34:00 -070045 if (list) {
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000046 // The new ValueList entry is inserted as the second element in the
47 // linked list, and it will contain the value of the first element.
halcanary385fe4d2015-08-26 13:07:48 -070048 ValueList* newEntry = new ValueList(list->fValue);
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000049 newEntry->fNext = list->fNext;
50 // The existing first ValueList entry is updated to contain the
51 // inserted value.
52 list->fNext = newEntry;
53 list->fValue = value;
54 } else {
halcanary385fe4d2015-08-26 13:07:48 -070055 fHash.add(new ValueList(value));
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000056 }
57
58 ++fCount;
59 }
60
61 void remove(const Key& key, const T* value) {
62 ValueList* list = fHash.find(key);
63 // Since we expect the caller to be fully aware of what is stored, just
64 // assert that the caller removes an existing value.
bsalomon49f085d2014-09-05 13:34:00 -070065 SkASSERT(list);
halcanary96fcdcc2015-08-27 07:41:13 -070066 ValueList* prev = nullptr;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000067 while (list->fValue != value) {
68 prev = list;
69 list = list->fNext;
70 }
71
bsalomon49f085d2014-09-05 13:34:00 -070072 if (list->fNext) {
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000073 ValueList* next = list->fNext;
74 list->fValue = next->fValue;
75 list->fNext = next->fNext;
halcanary385fe4d2015-08-26 13:07:48 -070076 delete next;
bsalomon49f085d2014-09-05 13:34:00 -070077 } else if (prev) {
halcanary96fcdcc2015-08-27 07:41:13 -070078 prev->fNext = nullptr;
halcanary385fe4d2015-08-26 13:07:48 -070079 delete list;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000080 } else {
81 fHash.remove(key);
halcanary385fe4d2015-08-26 13:07:48 -070082 delete list;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000083 }
84
85 --fCount;
86 }
87
88 T* find(const Key& key) const {
89 ValueList* list = fHash.find(key);
bsalomon49f085d2014-09-05 13:34:00 -070090 if (list) {
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000091 return list->fValue;
92 }
halcanary96fcdcc2015-08-27 07:41:13 -070093 return nullptr;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000094 }
95
96 template<class FindPredicate>
97 T* find(const Key& key, const FindPredicate f) {
98 ValueList* list = fHash.find(key);
bsalomon49f085d2014-09-05 13:34:00 -070099 while (list) {
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +0000100 if (f(list->fValue)){
101 return list->fValue;
102 }
103 list = list->fNext;
104 }
halcanary96fcdcc2015-08-27 07:41:13 -0700105 return nullptr;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +0000106 }
107
108 int count() const { return fCount; }
109
bsalomon8b79d232014-11-10 10:19:06 -0800110#ifdef SK_DEBUG
robertphillipsc4ed6842016-05-24 14:17:12 -0700111 class ConstIter {
112 public:
113 explicit ConstIter(const SkTMultiMap* mmap)
114 : fIter(&(mmap->fHash))
115 , fList(nullptr) {
116 if (!fIter.done()) {
117 fList = &(*fIter);
118 }
119 }
120
121 bool done() const {
122 return fIter.done();
123 }
124
125 const T* operator*() {
126 SkASSERT(fList);
127 return fList->fValue;
128 }
129
130 void operator++() {
131 if (fList) {
132 fList = fList->fNext;
133 }
134 if (!fList) {
135 ++fIter;
136 if (!fIter.done()) {
137 fList = &(*fIter);
138 }
139 }
140 }
141
142 private:
143 typename SkTDynamicHash<ValueList, Key>::ConstIter fIter;
144 const ValueList* fList;
145 };
146
147 bool has(const T* value, const Key& key) const {
148 for (ValueList* list = fHash.find(key); list; list = list->fNext) {
149 if (list->fValue == value) {
150 return true;
151 }
152 }
153 return false;
154 }
155
bsalomon8b79d232014-11-10 10:19:06 -0800156 // This is not particularly fast and only used for validation, so debug only.
157 int countForKey(const Key& key) const {
158 int count = 0;
159 ValueList* list = fHash.find(key);
160 while (list) {
161 list = list->fNext;
162 ++count;
163 }
164 return count;
165 }
166#endif
167
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +0000168private:
commit-bot@chromium.org55bd9402014-04-02 19:17:00 +0000169 SkTDynamicHash<ValueList, Key> fHash;
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +0000170 int fCount;
171};
172
173#endif