// Copyright 2019 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef VK_DEBUG_WEAKMAP_HPP_ #define VK_DEBUG_WEAKMAP_HPP_ #include #include namespace vk { namespace dbg { // WeakMap is an associative container of keys of type K to values of type // std::weak_ptr. // WeakMap's iterators will skip over elements where the value has no more // remaining std::shared_ptr references. // WeakMap is not thread-safe and requires the use of an external mutex to be // used by multiple threads, concurrently. template class WeakMap { using Map = std::map>; using MapIterator = typename Map::const_iterator; public: class iterator { public: inline iterator(const MapIterator &it, const MapIterator &end); inline void operator++(); inline bool operator==(const iterator &) const; inline bool operator!=(const iterator &) const; inline std::pair> operator*() const; private: void skipNull(); MapIterator it; const MapIterator end; std::shared_ptr sptr; }; // begin() returns an iterator to the start of the map. inline iterator begin() const; // end() returns an iterator to the end of the map. inline iterator end() const; // approx_size() returns an approximate number of entries in the map. This // is guaranteed to be greater than or equal to the actual number of // elements in the map. inline size_t approx_size() const; // get() returns the std::shared_ptr value for the given key, or nullptr // if the map does not contain the key, or the last remaining // std::shared_ptr reference to the value has been dropped. inline std::shared_ptr get(const K &key) const; // add() attempts to insert the key-value pair into the map. // add() returns true if there was no existing entry with the given key, // and the pair was added, otherwise false. inline bool add(const K &key, const std::shared_ptr &val); // remove() attempts to remove the entry with the given key from the map. // remove() returns true if there was no existing entry with the given key, // and the entry was removed, otherwise false. inline bool remove(const K &key); private: // reap() removes any entries that have values with no external references. inline void reap(); Map map; size_t reapAtSize = 32; }; template WeakMap::iterator::iterator(const MapIterator &it, const MapIterator &end) : it(it) , end(end) { skipNull(); } template void WeakMap::iterator::operator++() { it++; skipNull(); } template void WeakMap::iterator::skipNull() { for(; it != end; ++it) { // Hold on to the shared_ptr when pointing at this map element. // This ensures that the object is not released. sptr = it->second.lock(); if(sptr) { return; } } } template bool WeakMap::iterator::operator==(const iterator &rhs) const { return it == rhs.it; } template bool WeakMap::iterator::operator!=(const iterator &rhs) const { return it != rhs.it; } template std::pair> WeakMap::iterator::operator*() const { return { it->first, sptr }; } template typename WeakMap::iterator WeakMap::begin() const { return iterator(map.begin(), map.end()); } template typename WeakMap::iterator WeakMap::end() const { return iterator(map.end(), map.end()); } template size_t WeakMap::approx_size() const { return map.size(); } template std::shared_ptr WeakMap::get(const K &key) const { auto it = map.find(key); return (it != map.end()) ? it->second.lock() : nullptr; } template bool WeakMap::add(const K &key, const std::shared_ptr &val) { if(map.size() > reapAtSize) { reap(); reapAtSize = map.size() * 2 + 32; } return map.emplace(key, val).second; } template bool WeakMap::remove(const K &key) { return map.erase(key) > 0; } template void WeakMap::reap() { for(auto it = map.begin(); it != map.end();) { if(it->second.expired()) { map.erase(it++); } else { ++it; } } } } // namespace dbg } // namespace vk #endif // VK_DEBUG_WEAKMAP_HPP_