1*b7893ccfSSadaf Ebrahimi /* Copyright (c) 2015-2017, 2019 The Khronos Group Inc. 2*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2017, 2019 Valve Corporation 3*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2017, 2019 LunarG, Inc. 4*b7893ccfSSadaf Ebrahimi * 5*b7893ccfSSadaf Ebrahimi * Licensed under the Apache License, Version 2.0 (the "License"); 6*b7893ccfSSadaf Ebrahimi * you may not use this file except in compliance with the License. 7*b7893ccfSSadaf Ebrahimi * You may obtain a copy of the License at 8*b7893ccfSSadaf Ebrahimi * 9*b7893ccfSSadaf Ebrahimi * http://www.apache.org/licenses/LICENSE-2.0 10*b7893ccfSSadaf Ebrahimi * 11*b7893ccfSSadaf Ebrahimi * Unless required by applicable law or agreed to in writing, software 12*b7893ccfSSadaf Ebrahimi * distributed under the License is distributed on an "AS IS" BASIS, 13*b7893ccfSSadaf Ebrahimi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*b7893ccfSSadaf Ebrahimi * See the License for the specific language governing permissions and 15*b7893ccfSSadaf Ebrahimi * limitations under the License. 16*b7893ccfSSadaf Ebrahimi * 17*b7893ccfSSadaf Ebrahimi * Author: Mark Lobodzinski <[email protected]> 18*b7893ccfSSadaf Ebrahimi * Author: Courtney Goeltzenleuchter <[email protected]> 19*b7893ccfSSadaf Ebrahimi * Author: Dave Houlton <[email protected]> 20*b7893ccfSSadaf Ebrahimi */ 21*b7893ccfSSadaf Ebrahimi 22*b7893ccfSSadaf Ebrahimi #pragma once 23*b7893ccfSSadaf Ebrahimi 24*b7893ccfSSadaf Ebrahimi #include <cassert> 25*b7893ccfSSadaf Ebrahimi #include <cstddef> 26*b7893ccfSSadaf Ebrahimi #include <functional> 27*b7893ccfSSadaf Ebrahimi #include <stdbool.h> 28*b7893ccfSSadaf Ebrahimi #include <string> 29*b7893ccfSSadaf Ebrahimi #include <vector> 30*b7893ccfSSadaf Ebrahimi #include <set> 31*b7893ccfSSadaf Ebrahimi #include "cast_utils.h" 32*b7893ccfSSadaf Ebrahimi #include "vk_format_utils.h" 33*b7893ccfSSadaf Ebrahimi #include "vk_layer_logging.h" 34*b7893ccfSSadaf Ebrahimi 35*b7893ccfSSadaf Ebrahimi #ifndef WIN32 36*b7893ccfSSadaf Ebrahimi #include <strings.h> // For ffs() 37*b7893ccfSSadaf Ebrahimi #else 38*b7893ccfSSadaf Ebrahimi #include <intrin.h> // For __lzcnt() 39*b7893ccfSSadaf Ebrahimi #endif 40*b7893ccfSSadaf Ebrahimi 41*b7893ccfSSadaf Ebrahimi #ifdef __cplusplus 42*b7893ccfSSadaf Ebrahimi // Traits objects to allow string_join to operate on collections of const char * 43*b7893ccfSSadaf Ebrahimi template <typename String> 44*b7893ccfSSadaf Ebrahimi struct StringJoinSizeTrait { sizeStringJoinSizeTrait45*b7893ccfSSadaf Ebrahimi static size_t size(const String &str) { return str.size(); } 46*b7893ccfSSadaf Ebrahimi }; 47*b7893ccfSSadaf Ebrahimi 48*b7893ccfSSadaf Ebrahimi template <> 49*b7893ccfSSadaf Ebrahimi struct StringJoinSizeTrait<const char *> { 50*b7893ccfSSadaf Ebrahimi static size_t size(const char *str) { 51*b7893ccfSSadaf Ebrahimi if (!str) return 0; 52*b7893ccfSSadaf Ebrahimi return strlen(str); 53*b7893ccfSSadaf Ebrahimi } 54*b7893ccfSSadaf Ebrahimi }; 55*b7893ccfSSadaf Ebrahimi // Similar to perl/python join 56*b7893ccfSSadaf Ebrahimi // * String must support size, reserve, append, and be default constructable 57*b7893ccfSSadaf Ebrahimi // * StringCollection must support size, const forward iteration, and store 58*b7893ccfSSadaf Ebrahimi // strings compatible with String::append 59*b7893ccfSSadaf Ebrahimi // * Accessor trait can be set if default accessors (compatible with string 60*b7893ccfSSadaf Ebrahimi // and const char *) don't support size(StringCollection::value_type &) 61*b7893ccfSSadaf Ebrahimi // 62*b7893ccfSSadaf Ebrahimi // Return type based on sep type 63*b7893ccfSSadaf Ebrahimi template <typename String = std::string, typename StringCollection = std::vector<String>, 64*b7893ccfSSadaf Ebrahimi typename Accessor = StringJoinSizeTrait<typename StringCollection::value_type>> 65*b7893ccfSSadaf Ebrahimi static inline String string_join(const String &sep, const StringCollection &strings) { 66*b7893ccfSSadaf Ebrahimi String joined; 67*b7893ccfSSadaf Ebrahimi const size_t count = strings.size(); 68*b7893ccfSSadaf Ebrahimi if (!count) return joined; 69*b7893ccfSSadaf Ebrahimi 70*b7893ccfSSadaf Ebrahimi // Prereserved storage, s.t. we will execute in linear time (avoids reallocation copies) 71*b7893ccfSSadaf Ebrahimi size_t reserve = (count - 1) * sep.size(); 72*b7893ccfSSadaf Ebrahimi for (const auto &str : strings) { 73*b7893ccfSSadaf Ebrahimi reserve += Accessor::size(str); // abstracted to allow const char * type in StringCollection 74*b7893ccfSSadaf Ebrahimi } 75*b7893ccfSSadaf Ebrahimi joined.reserve(reserve + 1); 76*b7893ccfSSadaf Ebrahimi 77*b7893ccfSSadaf Ebrahimi // Seps only occur *between* strings entries, so first is special 78*b7893ccfSSadaf Ebrahimi auto current = strings.cbegin(); 79*b7893ccfSSadaf Ebrahimi joined.append(*current); 80*b7893ccfSSadaf Ebrahimi ++current; 81*b7893ccfSSadaf Ebrahimi for (; current != strings.cend(); ++current) { 82*b7893ccfSSadaf Ebrahimi joined.append(sep); 83*b7893ccfSSadaf Ebrahimi joined.append(*current); 84*b7893ccfSSadaf Ebrahimi } 85*b7893ccfSSadaf Ebrahimi return joined; 86*b7893ccfSSadaf Ebrahimi } 87*b7893ccfSSadaf Ebrahimi 88*b7893ccfSSadaf Ebrahimi // Requires StringCollection::value_type has a const char * constructor and is compatible the string_join::String above 89*b7893ccfSSadaf Ebrahimi template <typename StringCollection = std::vector<std::string>, typename SepString = std::string> 90*b7893ccfSSadaf Ebrahimi static inline SepString string_join(const char *sep, const StringCollection &strings) { 91*b7893ccfSSadaf Ebrahimi return string_join<SepString, StringCollection>(SepString(sep), strings); 92*b7893ccfSSadaf Ebrahimi } 93*b7893ccfSSadaf Ebrahimi 94*b7893ccfSSadaf Ebrahimi // Perl/Python style join operation for general types using stream semantics 95*b7893ccfSSadaf Ebrahimi // Note: won't be as fast as string_join above, but simpler to use (and code) 96*b7893ccfSSadaf Ebrahimi // Note: Modifiable reference doesn't match the google style but does match std style for stream handling and algorithms 97*b7893ccfSSadaf Ebrahimi template <typename Stream, typename String, typename ForwardIt> 98*b7893ccfSSadaf Ebrahimi Stream &stream_join(Stream &stream, const String &sep, ForwardIt first, ForwardIt last) { 99*b7893ccfSSadaf Ebrahimi if (first != last) { 100*b7893ccfSSadaf Ebrahimi stream << *first; 101*b7893ccfSSadaf Ebrahimi ++first; 102*b7893ccfSSadaf Ebrahimi while (first != last) { 103*b7893ccfSSadaf Ebrahimi stream << sep << *first; 104*b7893ccfSSadaf Ebrahimi ++first; 105*b7893ccfSSadaf Ebrahimi } 106*b7893ccfSSadaf Ebrahimi } 107*b7893ccfSSadaf Ebrahimi return stream; 108*b7893ccfSSadaf Ebrahimi } 109*b7893ccfSSadaf Ebrahimi 110*b7893ccfSSadaf Ebrahimi // stream_join For whole collections with forward iterators 111*b7893ccfSSadaf Ebrahimi template <typename Stream, typename String, typename Collection> 112*b7893ccfSSadaf Ebrahimi Stream &stream_join(Stream &stream, const String &sep, const Collection &values) { 113*b7893ccfSSadaf Ebrahimi return stream_join(stream, sep, values.cbegin(), values.cend()); 114*b7893ccfSSadaf Ebrahimi } 115*b7893ccfSSadaf Ebrahimi 116*b7893ccfSSadaf Ebrahimi typedef void *dispatch_key; 117*b7893ccfSSadaf Ebrahimi static inline dispatch_key get_dispatch_key(const void *object) { return (dispatch_key) * (VkLayerDispatchTable **)object; } 118*b7893ccfSSadaf Ebrahimi 119*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT VkLayerInstanceCreateInfo *get_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func); 120*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT VkLayerDeviceCreateInfo *get_chain_info(const VkDeviceCreateInfo *pCreateInfo, VkLayerFunction func); 121*b7893ccfSSadaf Ebrahimi 122*b7893ccfSSadaf Ebrahimi static inline bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); } 123*b7893ccfSSadaf Ebrahimi 124*b7893ccfSSadaf Ebrahimi extern "C" { 125*b7893ccfSSadaf Ebrahimi #endif 126*b7893ccfSSadaf Ebrahimi 127*b7893ccfSSadaf Ebrahimi #define VK_LAYER_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION) 128*b7893ccfSSadaf Ebrahimi 129*b7893ccfSSadaf Ebrahimi typedef enum VkStringErrorFlagBits { 130*b7893ccfSSadaf Ebrahimi VK_STRING_ERROR_NONE = 0x00000000, 131*b7893ccfSSadaf Ebrahimi VK_STRING_ERROR_LENGTH = 0x00000001, 132*b7893ccfSSadaf Ebrahimi VK_STRING_ERROR_BAD_DATA = 0x00000002, 133*b7893ccfSSadaf Ebrahimi } VkStringErrorFlagBits; 134*b7893ccfSSadaf Ebrahimi typedef VkFlags VkStringErrorFlags; 135*b7893ccfSSadaf Ebrahimi 136*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT void layer_debug_report_actions(debug_report_data *report_data, 137*b7893ccfSSadaf Ebrahimi std::vector<VkDebugReportCallbackEXT> &logging_callback, 138*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, const char *layer_identifier); 139*b7893ccfSSadaf Ebrahimi 140*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT void layer_debug_messenger_actions(debug_report_data *report_data, 141*b7893ccfSSadaf Ebrahimi std::vector<VkDebugUtilsMessengerEXT> &logging_messenger, 142*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, const char *layer_identifier); 143*b7893ccfSSadaf Ebrahimi 144*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array); 145*b7893ccfSSadaf Ebrahimi VK_LAYER_EXPORT bool white_list(const char *item, const std::set<std::string> &whitelist); 146*b7893ccfSSadaf Ebrahimi 147*b7893ccfSSadaf Ebrahimi static inline int u_ffs(int val) { 148*b7893ccfSSadaf Ebrahimi #ifdef WIN32 149*b7893ccfSSadaf Ebrahimi unsigned long bit_pos = 0; 150*b7893ccfSSadaf Ebrahimi if (_BitScanForward(&bit_pos, val) != 0) { 151*b7893ccfSSadaf Ebrahimi bit_pos += 1; 152*b7893ccfSSadaf Ebrahimi } 153*b7893ccfSSadaf Ebrahimi return bit_pos; 154*b7893ccfSSadaf Ebrahimi #else 155*b7893ccfSSadaf Ebrahimi return ffs(val); 156*b7893ccfSSadaf Ebrahimi #endif 157*b7893ccfSSadaf Ebrahimi } 158*b7893ccfSSadaf Ebrahimi 159*b7893ccfSSadaf Ebrahimi #ifdef __cplusplus 160*b7893ccfSSadaf Ebrahimi } 161*b7893ccfSSadaf Ebrahimi #endif 162*b7893ccfSSadaf Ebrahimi 163*b7893ccfSSadaf Ebrahimi // shared_mutex support added in MSVC 2015 update 2 164*b7893ccfSSadaf Ebrahimi #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && NTDDI_VERSION > NTDDI_WIN10_RS2 165*b7893ccfSSadaf Ebrahimi #include <shared_mutex> 166*b7893ccfSSadaf Ebrahimi #endif 167*b7893ccfSSadaf Ebrahimi 168*b7893ccfSSadaf Ebrahimi // Limited concurrent_unordered_map that supports internally-synchronized 169*b7893ccfSSadaf Ebrahimi // insert/erase/access. Splits locking across N buckets and uses shared_mutex 170*b7893ccfSSadaf Ebrahimi // for read/write locking. Iterators are not supported. The following 171*b7893ccfSSadaf Ebrahimi // operations are supported: 172*b7893ccfSSadaf Ebrahimi // 173*b7893ccfSSadaf Ebrahimi // insert_or_assign: Insert a new element or update an existing element. 174*b7893ccfSSadaf Ebrahimi // insert: Insert a new element and return whether it was inserted. 175*b7893ccfSSadaf Ebrahimi // erase: Remove an element. 176*b7893ccfSSadaf Ebrahimi // contains: Returns true if the key is in the map. 177*b7893ccfSSadaf Ebrahimi // find: Returns != end() if found, value is in ret->second. 178*b7893ccfSSadaf Ebrahimi // pop: Erases and returns the erased value if found. 179*b7893ccfSSadaf Ebrahimi // 180*b7893ccfSSadaf Ebrahimi // find/end: find returns a vaguely iterator-like type that can be compared to 181*b7893ccfSSadaf Ebrahimi // end and can use iter->second to retrieve the reference. This is to ease porting 182*b7893ccfSSadaf Ebrahimi // for existing code that combines the existence check and lookup in a single 183*b7893ccfSSadaf Ebrahimi // operation (and thus a single lock). i.e.: 184*b7893ccfSSadaf Ebrahimi // 185*b7893ccfSSadaf Ebrahimi // auto iter = map.find(key); 186*b7893ccfSSadaf Ebrahimi // if (iter != map.end()) { 187*b7893ccfSSadaf Ebrahimi // T t = iter->second; 188*b7893ccfSSadaf Ebrahimi // ... 189*b7893ccfSSadaf Ebrahimi // 190*b7893ccfSSadaf Ebrahimi // snapshot: Return an array of elements (key, value pairs) that satisfy an optional 191*b7893ccfSSadaf Ebrahimi // predicate. This can be used as a substitute for iterators in exceptional cases. 192*b7893ccfSSadaf Ebrahimi template <typename Key, typename T, int BUCKETSLOG2 = 2> 193*b7893ccfSSadaf Ebrahimi class vl_concurrent_unordered_map { 194*b7893ccfSSadaf Ebrahimi public: 195*b7893ccfSSadaf Ebrahimi void insert_or_assign(const Key &key, const T &value) { 196*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 197*b7893ccfSSadaf Ebrahimi write_lock_guard_t lock(locks[h].lock); 198*b7893ccfSSadaf Ebrahimi maps[h][key] = value; 199*b7893ccfSSadaf Ebrahimi } 200*b7893ccfSSadaf Ebrahimi 201*b7893ccfSSadaf Ebrahimi bool insert(const Key &key, const T &value) { 202*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 203*b7893ccfSSadaf Ebrahimi write_lock_guard_t lock(locks[h].lock); 204*b7893ccfSSadaf Ebrahimi auto ret = maps[h].insert(typename std::unordered_map<Key, T>::value_type(key, value)); 205*b7893ccfSSadaf Ebrahimi return ret.second; 206*b7893ccfSSadaf Ebrahimi } 207*b7893ccfSSadaf Ebrahimi 208*b7893ccfSSadaf Ebrahimi // returns size_type 209*b7893ccfSSadaf Ebrahimi size_t erase(const Key &key) { 210*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 211*b7893ccfSSadaf Ebrahimi write_lock_guard_t lock(locks[h].lock); 212*b7893ccfSSadaf Ebrahimi return maps[h].erase(key); 213*b7893ccfSSadaf Ebrahimi } 214*b7893ccfSSadaf Ebrahimi 215*b7893ccfSSadaf Ebrahimi bool contains(const Key &key) { 216*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 217*b7893ccfSSadaf Ebrahimi read_lock_guard_t lock(locks[h].lock); 218*b7893ccfSSadaf Ebrahimi return maps[h].count(key) != 0; 219*b7893ccfSSadaf Ebrahimi } 220*b7893ccfSSadaf Ebrahimi 221*b7893ccfSSadaf Ebrahimi // type returned by find() and end(). 222*b7893ccfSSadaf Ebrahimi class FindResult { 223*b7893ccfSSadaf Ebrahimi public: 224*b7893ccfSSadaf Ebrahimi FindResult(bool a, T b) : result(a, std::move(b)) {} 225*b7893ccfSSadaf Ebrahimi 226*b7893ccfSSadaf Ebrahimi // == and != only support comparing against end() 227*b7893ccfSSadaf Ebrahimi bool operator==(const FindResult &other) const { 228*b7893ccfSSadaf Ebrahimi if (result.first == false && other.result.first == false) { 229*b7893ccfSSadaf Ebrahimi return true; 230*b7893ccfSSadaf Ebrahimi } 231*b7893ccfSSadaf Ebrahimi return false; 232*b7893ccfSSadaf Ebrahimi } 233*b7893ccfSSadaf Ebrahimi bool operator!=(const FindResult &other) const { return !(*this == other); } 234*b7893ccfSSadaf Ebrahimi 235*b7893ccfSSadaf Ebrahimi // Make -> act kind of like an iterator. 236*b7893ccfSSadaf Ebrahimi std::pair<bool, T> *operator->() { return &result; } 237*b7893ccfSSadaf Ebrahimi const std::pair<bool, T> *operator->() const { return &result; } 238*b7893ccfSSadaf Ebrahimi 239*b7893ccfSSadaf Ebrahimi private: 240*b7893ccfSSadaf Ebrahimi // (found, reference to element) 241*b7893ccfSSadaf Ebrahimi std::pair<bool, T> result; 242*b7893ccfSSadaf Ebrahimi }; 243*b7893ccfSSadaf Ebrahimi 244*b7893ccfSSadaf Ebrahimi // find()/end() return a FindResult containing a copy of the value. For end(), 245*b7893ccfSSadaf Ebrahimi // return a default value. 246*b7893ccfSSadaf Ebrahimi FindResult end() { return FindResult(false, T()); } 247*b7893ccfSSadaf Ebrahimi 248*b7893ccfSSadaf Ebrahimi FindResult find(const Key &key) { 249*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 250*b7893ccfSSadaf Ebrahimi read_lock_guard_t lock(locks[h].lock); 251*b7893ccfSSadaf Ebrahimi 252*b7893ccfSSadaf Ebrahimi auto itr = maps[h].find(key); 253*b7893ccfSSadaf Ebrahimi bool found = itr != maps[h].end(); 254*b7893ccfSSadaf Ebrahimi 255*b7893ccfSSadaf Ebrahimi if (found) { 256*b7893ccfSSadaf Ebrahimi return FindResult(true, itr->second); 257*b7893ccfSSadaf Ebrahimi } else { 258*b7893ccfSSadaf Ebrahimi return end(); 259*b7893ccfSSadaf Ebrahimi } 260*b7893ccfSSadaf Ebrahimi } 261*b7893ccfSSadaf Ebrahimi 262*b7893ccfSSadaf Ebrahimi FindResult pop(const Key &key) { 263*b7893ccfSSadaf Ebrahimi uint32_t h = ConcurrentMapHashObject(key); 264*b7893ccfSSadaf Ebrahimi write_lock_guard_t lock(locks[h].lock); 265*b7893ccfSSadaf Ebrahimi 266*b7893ccfSSadaf Ebrahimi auto itr = maps[h].find(key); 267*b7893ccfSSadaf Ebrahimi bool found = itr != maps[h].end(); 268*b7893ccfSSadaf Ebrahimi 269*b7893ccfSSadaf Ebrahimi if (found) { 270*b7893ccfSSadaf Ebrahimi auto ret = std::move(FindResult(true, itr->second)); 271*b7893ccfSSadaf Ebrahimi maps[h].erase(itr); 272*b7893ccfSSadaf Ebrahimi return ret; 273*b7893ccfSSadaf Ebrahimi } else { 274*b7893ccfSSadaf Ebrahimi return end(); 275*b7893ccfSSadaf Ebrahimi } 276*b7893ccfSSadaf Ebrahimi } 277*b7893ccfSSadaf Ebrahimi 278*b7893ccfSSadaf Ebrahimi std::vector<std::pair<const Key, T>> snapshot(std::function<bool(T)> f = nullptr) { 279*b7893ccfSSadaf Ebrahimi std::vector<std::pair<const Key, T>> ret; 280*b7893ccfSSadaf Ebrahimi for (int h = 0; h < BUCKETS; ++h) { 281*b7893ccfSSadaf Ebrahimi read_lock_guard_t lock(locks[h].lock); 282*b7893ccfSSadaf Ebrahimi for (auto j : maps[h]) { 283*b7893ccfSSadaf Ebrahimi if (!f || f(j.second)) { 284*b7893ccfSSadaf Ebrahimi ret.push_back(j); 285*b7893ccfSSadaf Ebrahimi } 286*b7893ccfSSadaf Ebrahimi } 287*b7893ccfSSadaf Ebrahimi } 288*b7893ccfSSadaf Ebrahimi return ret; 289*b7893ccfSSadaf Ebrahimi } 290*b7893ccfSSadaf Ebrahimi 291*b7893ccfSSadaf Ebrahimi private: 292*b7893ccfSSadaf Ebrahimi static const int BUCKETS = (1 << BUCKETSLOG2); 293*b7893ccfSSadaf Ebrahimi // shared_mutex support added in MSVC 2015 update 2 294*b7893ccfSSadaf Ebrahimi #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && NTDDI_VERSION > NTDDI_WIN10_RS2 295*b7893ccfSSadaf Ebrahimi #include <shared_mutex> 296*b7893ccfSSadaf Ebrahimi typedef std::shared_mutex lock_t; 297*b7893ccfSSadaf Ebrahimi typedef std::shared_lock<lock_t> read_lock_guard_t; 298*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<lock_t> write_lock_guard_t; 299*b7893ccfSSadaf Ebrahimi #else 300*b7893ccfSSadaf Ebrahimi typedef std::mutex lock_t; 301*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<lock_t> read_lock_guard_t; 302*b7893ccfSSadaf Ebrahimi typedef std::unique_lock<lock_t> write_lock_guard_t; 303*b7893ccfSSadaf Ebrahimi #endif 304*b7893ccfSSadaf Ebrahimi 305*b7893ccfSSadaf Ebrahimi std::unordered_map<Key, T> maps[BUCKETS]; 306*b7893ccfSSadaf Ebrahimi struct { 307*b7893ccfSSadaf Ebrahimi lock_t lock; 308*b7893ccfSSadaf Ebrahimi // Put each lock on its own cache line to avoid false cache line sharing. 309*b7893ccfSSadaf Ebrahimi char padding[(-int(sizeof(lock_t))) & 63]; 310*b7893ccfSSadaf Ebrahimi } locks[BUCKETS]; 311*b7893ccfSSadaf Ebrahimi 312*b7893ccfSSadaf Ebrahimi uint32_t ConcurrentMapHashObject(const Key &object) const { 313*b7893ccfSSadaf Ebrahimi uint64_t u64 = (uint64_t)(uintptr_t)object; 314*b7893ccfSSadaf Ebrahimi uint32_t hash = (uint32_t)(u64 >> 32) + (uint32_t)u64; 315*b7893ccfSSadaf Ebrahimi hash ^= (hash >> BUCKETSLOG2) ^ (hash >> (2 * BUCKETSLOG2)); 316*b7893ccfSSadaf Ebrahimi hash &= (BUCKETS - 1); 317*b7893ccfSSadaf Ebrahimi return hash; 318*b7893ccfSSadaf Ebrahimi } 319*b7893ccfSSadaf Ebrahimi }; 320