/* * Copyright (C) 2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include namespace WTF { template< const char* typeArguments, typename KeyArg, typename MappedArg, typename HashArg = DefaultHash, typename KeyTraitsArg = HashTraits, typename MappedTraitsArg = HashTraits, typename LoggingKeyTraits = LoggingHashKeyTraits, typename LoggingValueTraits = LoggingHashValueTraits> class LoggingHashMap final { WTF_MAKE_FAST_ALLOCATED; public: typedef WTF::HashMap HashMap; typedef typename HashMap::KeyType KeyType; typedef typename HashMap::MappedType MappedType; typedef typename HashMap::KeyValuePairType KeyValuePairType; typedef typename HashMap::iterator iterator; typedef typename HashMap::const_iterator const_iterator; typedef typename HashMap::AddResult AddResult; private: typedef typename HashMap::MappedTraits::PeekType MappedPeekType; public: LoggingHashMap() { dataLog("auto* ", m_id, " = new HashMap<", typeArguments, ">();\n"); } ~LoggingHashMap() { dataLog("delete ", m_id, ";\n"); } LoggingHashMap(const LoggingHashMap& other) : m_map(other.m_map) { dataLog("auto* ", m_id, " = new HashMap(*", other.m_id, ");"); } LoggingHashMap(LoggingHashMap&& other) : m_map(other.m_map) { dataLog("auto* ", m_id, " = new HashMap(WTFMove(*", other.m_id, "));"); } LoggingHashMap& operator=(const LoggingHashMap& other) { dataLog("*", m_id, " = *", other.m_id, ";\n"); m_map = other.m_map; } LoggingHashMap& operator=(LoggingHashMap&& other) { dataLog("*", m_id, " = WTFMove(*", other.m_id, ");\n"); m_map = WTFMove(other.m_map); } void swap(LoggingHashMap& other) { dataLog(m_id, "->swap(*", RawPointer(&other), ");\n"); m_map.swap(other.m_map); } // A bunch of stuff does not get logged. unsigned size() const { return m_map.size(); } unsigned capacity() const { return m_map.capacity(); } bool isEmpty() const { return m_map.isEmpty(); } iterator begin() { return m_map.begin(); } iterator end() { return m_map.end(); } const_iterator begin() const { return m_map.begin(); } const_iterator end() const { return m_map.end(); } iterator random() { return m_map.random(); } const_iterator random() const { return m_map.random(); } auto keys() { return m_map.keys(); } auto keys() const { return m_map.keys(); } auto values() { return m_map.values(); } auto values() const { return m_map.values(); } iterator find(const KeyType& key) { StringPrintStream string; string.print("{\n"); string.print(" auto iter = ", m_id, "->find("); LoggingKeyTraits::print(string, key); string.print(");\n"); iterator result = m_map.find(key); if (result == m_map.end()) string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n"); else string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n"); string.print("}\n"); dataLog(string.toCString()); return result; } const_iterator find(const KeyType& key) const { StringPrintStream string; string.print("{\n"); string.print(" auto iter = ", m_id, "->find("); LoggingKeyTraits::print(string, key); string.print(");\n"); const_iterator result = m_map.find(key); if (result == m_map.end()) string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n"); else string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n"); string.print("}\n"); dataLog(string.toCString()); return result; } bool contains(const KeyType& key) const { return find(key) != end(); } MappedPeekType get(const KeyType& key) const { find(key); return m_map.get(key); } MappedPeekType inlineGet(const KeyType& key) const { find(key); return m_map.inlineGet(key); } template AddResult set(const KeyType& key, PassedType&& passedValue) { StringPrintStream string; string.print(m_id, "->set("); LoggingKeyTraits::print(string, key); string.print(", "); LoggingValueTraits::print(string, passedValue); string.print(");\n"); dataLog(string.toCString()); return set(key, std::forward(passedValue)); } template AddResult set(KeyType&& key, PassedType&& passedValue) { StringPrintStream string; string.print(m_id, "->set("); LoggingKeyTraits::print(string, key); string.print(", "); LoggingValueTraits::print(string, passedValue); string.print(");\n"); dataLog(string.toCString()); return set(WTFMove(key), std::forward(passedValue)); } template AddResult add(const KeyType& key, PassedType&& passedValue) { StringPrintStream string; string.print(m_id, "->add("); LoggingKeyTraits::print(string, key); string.print(", "); LoggingValueTraits::print(string, passedValue); string.print(");\n"); dataLog(string.toCString()); return add(key, std::forward(passedValue)); } template AddResult add(KeyType&& key, PassedType&& passedValue) { StringPrintStream string; string.print(m_id, "->add("); LoggingKeyTraits::print(string, key); string.print(", "); LoggingValueTraits::print(string, passedValue); string.print(");\n"); dataLog(string.toCString()); return add(WTFMove(key), std::forward(passedValue)); } template AddResult fastAdd(const KeyType& key, PassedType&& passedValue) { return add(key, std::forward(passedValue)); } template AddResult fastAdd(KeyType&& key, PassedType&& passedValue) { return add(WTFMove(key), std::forward(passedValue)); } template AddResult ensure(const KeyType& key, Func&& func) { StringPrintStream string; string.print(m_id, "->ensure("); LoggingKeyTraits::print(string, key); string.print(", "); string.print("[] () { return "); bool didCallFunctor = false; auto result = m_map.ensure( key, [&] () { didCallFunctor = true; auto result = func(); LoggingValueTraits::print(string, result); return result; }); if (!didCallFunctor) LoggingValueTraits::print(string, MappedTraitsArg::emptyValue()); string.print("; });\n"); dataLog(string.toCString()); return result; } template AddResult ensure(KeyType&& key, Func&& func) { StringPrintStream string; string.print(m_id, "->ensure("); LoggingKeyTraits::print(string, key); string.print(", "); string.print("[] () { return "); bool didCallFunctor = false; auto result = m_map.ensure( WTFMove(key), [&] () { didCallFunctor = true; auto result = func(); LoggingValueTraits::print(string, result); return result; }); if (!didCallFunctor) LoggingValueTraits::print(string, MappedTraitsArg::emptyValue()); string.print("; });\n"); dataLog(string.toCString()); return result; } bool remove(const KeyType& key) { StringPrintStream string; string.print(m_id, "->remove("); LoggingKeyTraits::print(string, key); string.print(");\n"); dataLog(string.toCString()); return m_map.remove(key); } bool remove(iterator iter) { // FIXME: It would be nice if we could do better than this. if (iter == end()) return false; return remove(iter->key); } // FIXME: Implement removeIf(). void clear() { dataLog(m_id, "->clear();\n"); m_map.clear(); } // FIXME: Implement the no-convert overloads. private: HashMap m_map; LoggingHashID m_id; }; } // namespace WTF using WTF::LoggingHashMap;