1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #ifndef VK_DEBUG_WEAKMAP_HPP_
16*03ce13f7SAndroid Build Coastguard Worker #define VK_DEBUG_WEAKMAP_HPP_
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Worker #include <map>
19*03ce13f7SAndroid Build Coastguard Worker #include <memory>
20*03ce13f7SAndroid Build Coastguard Worker
21*03ce13f7SAndroid Build Coastguard Worker namespace vk {
22*03ce13f7SAndroid Build Coastguard Worker namespace dbg {
23*03ce13f7SAndroid Build Coastguard Worker
24*03ce13f7SAndroid Build Coastguard Worker // WeakMap is an associative container of keys of type K to values of type
25*03ce13f7SAndroid Build Coastguard Worker // std::weak_ptr<V>.
26*03ce13f7SAndroid Build Coastguard Worker // WeakMap's iterators will skip over elements where the value has no more
27*03ce13f7SAndroid Build Coastguard Worker // remaining std::shared_ptr<V> references.
28*03ce13f7SAndroid Build Coastguard Worker // WeakMap is not thread-safe and requires the use of an external mutex to be
29*03ce13f7SAndroid Build Coastguard Worker // used by multiple threads, concurrently.
30*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
31*03ce13f7SAndroid Build Coastguard Worker class WeakMap
32*03ce13f7SAndroid Build Coastguard Worker {
33*03ce13f7SAndroid Build Coastguard Worker using Map = std::map<K, std::weak_ptr<V>>;
34*03ce13f7SAndroid Build Coastguard Worker using MapIterator = typename Map::const_iterator;
35*03ce13f7SAndroid Build Coastguard Worker
36*03ce13f7SAndroid Build Coastguard Worker public:
37*03ce13f7SAndroid Build Coastguard Worker class iterator
38*03ce13f7SAndroid Build Coastguard Worker {
39*03ce13f7SAndroid Build Coastguard Worker public:
40*03ce13f7SAndroid Build Coastguard Worker inline iterator(const MapIterator &it, const MapIterator &end);
41*03ce13f7SAndroid Build Coastguard Worker inline void operator++();
42*03ce13f7SAndroid Build Coastguard Worker inline bool operator==(const iterator &) const;
43*03ce13f7SAndroid Build Coastguard Worker inline bool operator!=(const iterator &) const;
44*03ce13f7SAndroid Build Coastguard Worker inline std::pair<K, std::shared_ptr<V>> operator*() const;
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker private:
47*03ce13f7SAndroid Build Coastguard Worker void skipNull();
48*03ce13f7SAndroid Build Coastguard Worker
49*03ce13f7SAndroid Build Coastguard Worker MapIterator it;
50*03ce13f7SAndroid Build Coastguard Worker const MapIterator end;
51*03ce13f7SAndroid Build Coastguard Worker std::shared_ptr<V> sptr;
52*03ce13f7SAndroid Build Coastguard Worker };
53*03ce13f7SAndroid Build Coastguard Worker
54*03ce13f7SAndroid Build Coastguard Worker // begin() returns an iterator to the start of the map.
55*03ce13f7SAndroid Build Coastguard Worker inline iterator begin() const;
56*03ce13f7SAndroid Build Coastguard Worker
57*03ce13f7SAndroid Build Coastguard Worker // end() returns an iterator to the end of the map.
58*03ce13f7SAndroid Build Coastguard Worker inline iterator end() const;
59*03ce13f7SAndroid Build Coastguard Worker
60*03ce13f7SAndroid Build Coastguard Worker // approx_size() returns an approximate number of entries in the map. This
61*03ce13f7SAndroid Build Coastguard Worker // is guaranteed to be greater than or equal to the actual number of
62*03ce13f7SAndroid Build Coastguard Worker // elements in the map.
63*03ce13f7SAndroid Build Coastguard Worker inline size_t approx_size() const;
64*03ce13f7SAndroid Build Coastguard Worker
65*03ce13f7SAndroid Build Coastguard Worker // get() returns the std::shared_ptr<V> value for the given key, or nullptr
66*03ce13f7SAndroid Build Coastguard Worker // if the map does not contain the key, or the last remaining
67*03ce13f7SAndroid Build Coastguard Worker // std::shared_ptr<V> reference to the value has been dropped.
68*03ce13f7SAndroid Build Coastguard Worker inline std::shared_ptr<V> get(const K &key) const;
69*03ce13f7SAndroid Build Coastguard Worker
70*03ce13f7SAndroid Build Coastguard Worker // add() attempts to insert the key-value pair into the map.
71*03ce13f7SAndroid Build Coastguard Worker // add() returns true if there was no existing entry with the given key,
72*03ce13f7SAndroid Build Coastguard Worker // and the pair was added, otherwise false.
73*03ce13f7SAndroid Build Coastguard Worker inline bool add(const K &key, const std::shared_ptr<V> &val);
74*03ce13f7SAndroid Build Coastguard Worker
75*03ce13f7SAndroid Build Coastguard Worker // remove() attempts to remove the entry with the given key from the map.
76*03ce13f7SAndroid Build Coastguard Worker // remove() returns true if there was no existing entry with the given key,
77*03ce13f7SAndroid Build Coastguard Worker // and the entry was removed, otherwise false.
78*03ce13f7SAndroid Build Coastguard Worker inline bool remove(const K &key);
79*03ce13f7SAndroid Build Coastguard Worker
80*03ce13f7SAndroid Build Coastguard Worker private:
81*03ce13f7SAndroid Build Coastguard Worker // reap() removes any entries that have values with no external references.
82*03ce13f7SAndroid Build Coastguard Worker inline void reap();
83*03ce13f7SAndroid Build Coastguard Worker
84*03ce13f7SAndroid Build Coastguard Worker Map map;
85*03ce13f7SAndroid Build Coastguard Worker size_t reapAtSize = 32;
86*03ce13f7SAndroid Build Coastguard Worker };
87*03ce13f7SAndroid Build Coastguard Worker
88*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
iterator(const MapIterator & it,const MapIterator & end)89*03ce13f7SAndroid Build Coastguard Worker WeakMap<K, V>::iterator::iterator(const MapIterator &it, const MapIterator &end)
90*03ce13f7SAndroid Build Coastguard Worker : it(it)
91*03ce13f7SAndroid Build Coastguard Worker , end(end)
92*03ce13f7SAndroid Build Coastguard Worker {
93*03ce13f7SAndroid Build Coastguard Worker skipNull();
94*03ce13f7SAndroid Build Coastguard Worker }
95*03ce13f7SAndroid Build Coastguard Worker
96*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
operator ++()97*03ce13f7SAndroid Build Coastguard Worker void WeakMap<K, V>::iterator::operator++()
98*03ce13f7SAndroid Build Coastguard Worker {
99*03ce13f7SAndroid Build Coastguard Worker it++;
100*03ce13f7SAndroid Build Coastguard Worker skipNull();
101*03ce13f7SAndroid Build Coastguard Worker }
102*03ce13f7SAndroid Build Coastguard Worker
103*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
skipNull()104*03ce13f7SAndroid Build Coastguard Worker void WeakMap<K, V>::iterator::skipNull()
105*03ce13f7SAndroid Build Coastguard Worker {
106*03ce13f7SAndroid Build Coastguard Worker for(; it != end; ++it)
107*03ce13f7SAndroid Build Coastguard Worker {
108*03ce13f7SAndroid Build Coastguard Worker // Hold on to the shared_ptr when pointing at this map element.
109*03ce13f7SAndroid Build Coastguard Worker // This ensures that the object is not released.
110*03ce13f7SAndroid Build Coastguard Worker sptr = it->second.lock();
111*03ce13f7SAndroid Build Coastguard Worker if(sptr)
112*03ce13f7SAndroid Build Coastguard Worker {
113*03ce13f7SAndroid Build Coastguard Worker return;
114*03ce13f7SAndroid Build Coastguard Worker }
115*03ce13f7SAndroid Build Coastguard Worker }
116*03ce13f7SAndroid Build Coastguard Worker }
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
operator ==(const iterator & rhs) const119*03ce13f7SAndroid Build Coastguard Worker bool WeakMap<K, V>::iterator::operator==(const iterator &rhs) const
120*03ce13f7SAndroid Build Coastguard Worker {
121*03ce13f7SAndroid Build Coastguard Worker return it == rhs.it;
122*03ce13f7SAndroid Build Coastguard Worker }
123*03ce13f7SAndroid Build Coastguard Worker
124*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
operator !=(const iterator & rhs) const125*03ce13f7SAndroid Build Coastguard Worker bool WeakMap<K, V>::iterator::operator!=(const iterator &rhs) const
126*03ce13f7SAndroid Build Coastguard Worker {
127*03ce13f7SAndroid Build Coastguard Worker return it != rhs.it;
128*03ce13f7SAndroid Build Coastguard Worker }
129*03ce13f7SAndroid Build Coastguard Worker
130*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
operator *() const131*03ce13f7SAndroid Build Coastguard Worker std::pair<K, std::shared_ptr<V>> WeakMap<K, V>::iterator::operator*() const
132*03ce13f7SAndroid Build Coastguard Worker {
133*03ce13f7SAndroid Build Coastguard Worker return { it->first, sptr };
134*03ce13f7SAndroid Build Coastguard Worker }
135*03ce13f7SAndroid Build Coastguard Worker
136*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
begin() const137*03ce13f7SAndroid Build Coastguard Worker typename WeakMap<K, V>::iterator WeakMap<K, V>::begin() const
138*03ce13f7SAndroid Build Coastguard Worker {
139*03ce13f7SAndroid Build Coastguard Worker return iterator(map.begin(), map.end());
140*03ce13f7SAndroid Build Coastguard Worker }
141*03ce13f7SAndroid Build Coastguard Worker
142*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
end() const143*03ce13f7SAndroid Build Coastguard Worker typename WeakMap<K, V>::iterator WeakMap<K, V>::end() const
144*03ce13f7SAndroid Build Coastguard Worker {
145*03ce13f7SAndroid Build Coastguard Worker return iterator(map.end(), map.end());
146*03ce13f7SAndroid Build Coastguard Worker }
147*03ce13f7SAndroid Build Coastguard Worker
148*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
approx_size() const149*03ce13f7SAndroid Build Coastguard Worker size_t WeakMap<K, V>::approx_size() const
150*03ce13f7SAndroid Build Coastguard Worker {
151*03ce13f7SAndroid Build Coastguard Worker return map.size();
152*03ce13f7SAndroid Build Coastguard Worker }
153*03ce13f7SAndroid Build Coastguard Worker
154*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
get(const K & key) const155*03ce13f7SAndroid Build Coastguard Worker std::shared_ptr<V> WeakMap<K, V>::get(const K &key) const
156*03ce13f7SAndroid Build Coastguard Worker {
157*03ce13f7SAndroid Build Coastguard Worker auto it = map.find(key);
158*03ce13f7SAndroid Build Coastguard Worker return (it != map.end()) ? it->second.lock() : nullptr;
159*03ce13f7SAndroid Build Coastguard Worker }
160*03ce13f7SAndroid Build Coastguard Worker
161*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
add(const K & key,const std::shared_ptr<V> & val)162*03ce13f7SAndroid Build Coastguard Worker bool WeakMap<K, V>::add(const K &key, const std::shared_ptr<V> &val)
163*03ce13f7SAndroid Build Coastguard Worker {
164*03ce13f7SAndroid Build Coastguard Worker if(map.size() > reapAtSize)
165*03ce13f7SAndroid Build Coastguard Worker {
166*03ce13f7SAndroid Build Coastguard Worker reap();
167*03ce13f7SAndroid Build Coastguard Worker reapAtSize = map.size() * 2 + 32;
168*03ce13f7SAndroid Build Coastguard Worker }
169*03ce13f7SAndroid Build Coastguard Worker return map.emplace(key, val).second;
170*03ce13f7SAndroid Build Coastguard Worker }
171*03ce13f7SAndroid Build Coastguard Worker
172*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
remove(const K & key)173*03ce13f7SAndroid Build Coastguard Worker bool WeakMap<K, V>::remove(const K &key)
174*03ce13f7SAndroid Build Coastguard Worker {
175*03ce13f7SAndroid Build Coastguard Worker return map.erase(key) > 0;
176*03ce13f7SAndroid Build Coastguard Worker }
177*03ce13f7SAndroid Build Coastguard Worker
178*03ce13f7SAndroid Build Coastguard Worker template<typename K, typename V>
reap()179*03ce13f7SAndroid Build Coastguard Worker void WeakMap<K, V>::reap()
180*03ce13f7SAndroid Build Coastguard Worker {
181*03ce13f7SAndroid Build Coastguard Worker for(auto it = map.begin(); it != map.end();)
182*03ce13f7SAndroid Build Coastguard Worker {
183*03ce13f7SAndroid Build Coastguard Worker if(it->second.expired())
184*03ce13f7SAndroid Build Coastguard Worker {
185*03ce13f7SAndroid Build Coastguard Worker map.erase(it++);
186*03ce13f7SAndroid Build Coastguard Worker }
187*03ce13f7SAndroid Build Coastguard Worker else
188*03ce13f7SAndroid Build Coastguard Worker {
189*03ce13f7SAndroid Build Coastguard Worker ++it;
190*03ce13f7SAndroid Build Coastguard Worker }
191*03ce13f7SAndroid Build Coastguard Worker }
192*03ce13f7SAndroid Build Coastguard Worker }
193*03ce13f7SAndroid Build Coastguard Worker
194*03ce13f7SAndroid Build Coastguard Worker } // namespace dbg
195*03ce13f7SAndroid Build Coastguard Worker } // namespace vk
196*03ce13f7SAndroid Build Coastguard Worker
197*03ce13f7SAndroid Build Coastguard Worker #endif // VK_DEBUG_WEAKMAP_HPP_
198