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