HashUtil.h (2520B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef gc_HashUtil_h 8 #define gc_HashUtil_h 9 10 #include <type_traits> 11 12 #include "vm/JSContext.h" 13 14 namespace js { 15 16 /* 17 * Used to add entries to a js::HashMap or HashSet where the key depends on a GC 18 * thing that may be moved by generational or compacting GC between the call to 19 * lookupForAdd() and relookupOrAdd(). 20 */ 21 template <class T> 22 struct DependentAddPtr { 23 using AddPtr = typename T::AddPtr; 24 using Entry = typename T::Entry; 25 26 template <class Lookup> 27 DependentAddPtr(const JSContext* cx, T& table, const Lookup& lookup) 28 : addPtr(table.lookupForAdd(lookup)), 29 originalGcNumber(cx->runtime()->gc.gcNumber()) {} 30 31 DependentAddPtr(DependentAddPtr&& other) 32 : addPtr(other.addPtr), originalGcNumber(other.originalGcNumber) {} 33 34 template <class KeyInput, class ValueInput> 35 bool add(JSContext* cx, T& table, const KeyInput& key, 36 const ValueInput& value) { 37 refreshAddPtr(cx, table, key); 38 if (!table.relookupOrAdd(addPtr, key, value)) { 39 ReportOutOfMemory(cx); 40 return false; 41 } 42 return true; 43 } 44 45 template <class KeyInput> 46 void remove(JSContext* cx, T& table, const KeyInput& key) { 47 refreshAddPtr(cx, table, key); 48 if (addPtr) { 49 table.remove(addPtr); 50 } 51 } 52 53 bool found() const { return addPtr.found(); } 54 explicit operator bool() const { return found(); } 55 const Entry& operator*() const { return *addPtr; } 56 const Entry* operator->() const { return &*addPtr; } 57 58 private: 59 AddPtr addPtr; 60 const uint64_t originalGcNumber; 61 62 template <class KeyInput> 63 void refreshAddPtr(JSContext* cx, T& table, const KeyInput& key) { 64 bool gcHappened = originalGcNumber != cx->runtime()->gc.gcNumber(); 65 if (gcHappened) { 66 addPtr = table.lookupForAdd(key); 67 } 68 } 69 70 DependentAddPtr() = delete; 71 DependentAddPtr(const DependentAddPtr&) = delete; 72 DependentAddPtr& operator=(const DependentAddPtr&) = delete; 73 }; 74 75 template <typename T, typename Lookup> 76 inline auto MakeDependentAddPtr(const JSContext* cx, T& table, 77 const Lookup& lookup) { 78 using Ptr = DependentAddPtr<std::remove_reference_t<decltype(table)>>; 79 return Ptr(cx, table, lookup); 80 } 81 82 } // namespace js 83 84 #endif