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