Ptex: PtexHashMap.h Source File

Ptex

PtexHashMap.h
Go to the documentation of this file.
1/*
2PTEX SOFTWARE
3Copyright 2014 Disney Enterprises, Inc. All rights reserved
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
18 Studios" or the names of its contributors may NOT be used to
19 endorse or promote products derived from this software without
20 specific prior written permission from Walt Disney Pictures.
21
22Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34*/
39
40#ifndef PtexHashMap_h
41#define PtexHashMap_h
42
43#include <vector>
44#include <string>
45#include "PtexPlatform.h"
46#include "PtexMutex.h"
47
48 PTEX_NAMESPACE_BEGIN
49
50 inline bool memCompare(const char* a, const char* b, int len)
51{
52 int len64 = len & ~7;
53 uint64_t val64[2];
54 for (int i = 0; i < len64; i+=8) {
55 memcpy(&val64[0], &a[i], 8);
56 memcpy(&val64[1], &b[i], 8);
57 if (val64[0] != val64[1]) return 1;
58 }
59 return memcmp(&a[len64], &b[len64], len & 7);
60}
61
62
63 class StringKey
64{
65 const char* volatile _val;
66 uint16_t volatile _len;
67 uint16_t volatile _ownsVal;
68 uint32_t volatile _hash;
69
70 void operator=(const StringKey& key); // disallow
71 StringKey(const StringKey& key); // disallow
72
73public:
74 StringKey() : _val(0), _len(0), _ownsVal(false), _hash(0) {}
75 StringKey(const char* val)
76 {
77 _val = val;
78 _len = uint16_t(strlen(val));
79 _hash = uint32_t(std::hash<std::string_view>{}(std::string_view(_val, _len)));
80 _ownsVal = false;
81 }
82
83 ~StringKey() { if (_ownsVal) delete [] _val; }
84
85 void copy(volatile StringKey& key) volatile
86 {
87 char* newval = new char[key._len+1];
88 memcpy(newval, key._val, key._len+1);
89 _val = newval;
90 _len = key._len;
91 _hash = key._hash;
92 _ownsVal = true;
93 }
94
95 void move(volatile StringKey& key) volatile
96 {
97 _val = key._val;
98 _len = key._len;
99 _hash = key._hash;
100 _ownsVal = key._ownsVal;
101 key._ownsVal = false;
102 }
103
104 bool matches(const StringKey& key) const volatile
105 {
106 return key._hash == _hash && key._len == _len && _val && 0 == memCompare(key._val, _val, _len);
107 }
108
109 bool isEmpty() const volatile { return _val==0; }
110
111 uint32_t hash() const volatile
112 {
113 return _hash;
114 }
115};
116
117 class IntKey
118{
119 int _val;
120
121public:
122 IntKey() : _val(0) {}
123 IntKey(int val) : _val(val) {}
124 void copy(volatile IntKey& key) volatile { _val = key._val; }
125 void move(volatile IntKey& key) volatile { _val = key._val; }
126 bool matches(const IntKey& key) const volatile { return _val == key._val; }
127 bool isEmpty() volatile const { return _val==0; }
128 uint32_t hash() volatile const { return (_val*7919) & ~0xf; }
129};
130
131template <typename Key, typename Value>
132 class PtexHashMap
133{
134 // a table is a TableHeader followed in memory by an array of Entry records
135
136 struct TableHeader {
137 uint32_t numEntries;
138 uint32_t size;
139 };
140
141 class Entry {
142 Entry(const Entry&); // disallow
143 void operator=(const Entry&); // disallow
144 public:
145 Entry() : key(), value(0) {}
146 Key volatile key;
147 Value volatile value;
148 };
149
150 PtexHashMap(const PtexHashMap&); // disallow
151 void operator=(const PtexHashMap&); // disallow
152
153 void initContents()
154 {
155 size_t memUsed;
156 _table = allocTable(16, memUsed);
157 }
158
159 void deleteContents()
160 {
161 TableHeader* header;
162 Entry* entries;
163 getTable(_table, header, entries);
164
165 for (uint32_t i = 0; i < header->numEntries; ++i) {
166 if (entries[i].value) delete entries[i].value;
167 }
168 free(_table);
169 for (size_t i = 0; i < _oldTables.size(); ++i) {
170 free(_oldTables[i]);
171 }
172 std::vector<void*>().swap(_oldTables);
173 }
174
175public:
176 PtexHashMap()
177 {
178 initContents();
179 }
180
181 ~PtexHashMap()
182 {
183 deleteContents();
184 }
185
186 void clear()
187 {
188 deleteContents();
189 initContents();
190 }
191
192 uint32_t size() const {
193 return ((TableHeader*)_table)->size;
194 }
195
196 Value get(Key& key) const
197 {
198 const TableHeader* header;
199 const Entry* entries;
200 getTable(_table, header, entries);
201 uint32_t mask = header->numEntries-1;
202 uint32_t hash = key.hash();
203
204 Value result = 0;
205 for (uint32_t i = hash;; ++i) {
206 const Entry& e = entries[i & mask];
207 if (e.key.matches(key)) {
208 result = e.value;
209 break;
210 }
211 if (e.value == 0) {
212 break;
213 }
214 }
215
216 return result;
217 }
218
219 Value tryInsert(Key& key, Value value, size_t& newMemUsed)
220 {
221 void* table = lockTableAndGrowIfNeeded(newMemUsed);
222 TableHeader* header;
223 Entry* entries;
224 getTable(table, header, entries);
225 uint32_t mask = header->numEntries-1;
226 uint32_t hash = key.hash();
227
228 Value result = 0;
229 for (uint32_t i = hash;; ++i) {
230 Entry& e = entries[i & mask];
231 if (e.value == 0) {
232 e.value = value;
233 ++header->size;
234 PtexMemoryFence(); // must write key after value
235 e.key.copy(key);
236 result = e.value;
237 break;
238 }
239 while (e.key.isEmpty()) ;
240 if (e.key.matches(key)) {
241 result = e.value;
242 break;
243 }
244 }
245 unlockTable(table);
246 return result;
247 }
248
249 template <typename Fn>
250 void foreach(Fn& fn) const
251 {
252 const TableHeader* header;
253 const Entry* entries;
254 getTable(_table, header, entries);
255 for (uint32_t i = 0; i < header->numEntries; ++i) {
256 Value v = entries[i].value;
257 if (v) fn(v);
258 }
259 }
260
261private:
262 void* allocTable(int32_t numEntries, size_t& memsize)
263 {
264 memsize = sizeof(TableHeader) + sizeof(Entry) * numEntries;
265 void* table = malloc(memsize);
266 memset(table, 0, memsize);
267 TableHeader* header = (TableHeader*) table;
268 header->numEntries = numEntries;
269 header->size = 0;
270 return table;
271 }
272
273 static void getTable(const void* table, const TableHeader*& header, const Entry*& entries)
274 {
275 header = (const TableHeader*) table;
276 entries = (const Entry*)((const char*)table + sizeof(TableHeader));
277 }
278
279 static void getTable(void* table, TableHeader*& header, Entry*& entries)
280 {
281 header = (TableHeader*) table;
282 entries = (Entry*)((char*)table + sizeof(TableHeader));
283 }
284
285 void unlockTable(void* table)
286 {
287 _table = table;
288 _lock.unlock();
289 }
290
291 void* lockTableAndGrowIfNeeded(size_t& newMemUsed)
292 {
293 _lock.lock();
294 void* table = _table;
295 TableHeader* header;
296 Entry* entries;
297 getTable(table, header, entries);
298
299 if (header->size*2 >= header->numEntries) {
300 table = grow(table, newMemUsed);
301 }
302 return table;
303 }
304
305 void* grow(void* oldTable, size_t& newMemUsed)
306 {
307 TableHeader* oldHeader;
308 Entry* oldEntries;
309 getTable(oldTable, oldHeader, oldEntries);
310
311 _oldTables.push_back(oldTable);
312 void* newTable = allocTable(oldHeader->numEntries*2, newMemUsed);
313 TableHeader* newHeader;
314 Entry* newEntries;
315 getTable(newTable, newHeader, newEntries);
316 uint32_t mask = newHeader->numEntries-1;
317 for (uint32_t oldIndex = 0; oldIndex < oldHeader->numEntries; ++oldIndex) {
318 Entry& oldEntry = oldEntries[oldIndex];
319 if (oldEntry.value) {
320 for (int newIndex = oldEntry.key.hash();; ++newIndex) {
321 Entry& newEntry = newEntries[newIndex&mask];
322 if (!newEntry.value) {
323 newEntry.key.move(oldEntry.key);
324 newEntry.value = oldEntry.value;
325 break;
326 }
327 }
328 }
329 }
330 newHeader->size = oldHeader->size;
331 return newTable;
332 }
333
334 void* _table;
335 Mutex _lock;
336 std::vector<void*> _oldTables;
337};
338
339 PTEX_NAMESPACE_END
340
341#endif
memCompare
PTEX_NAMESPACE_BEGIN bool memCompare(const char *a, const char *b, int len)
Definition PtexHashMap.h:50
PtexMutex.h
PtexPlatform.h
Platform-specific classes, functions, and includes.
PtexMemoryFence
PTEX_INLINE void PtexMemoryFence()
Definition PtexPlatform.h:292
PTEX_NAMESPACE_END
#define PTEX_NAMESPACE_END
Definition PtexVersion.h:62
IntKey::IntKey
IntKey(int val)
Definition PtexHashMap.h:123
IntKey::matches
bool matches(const IntKey &key) const volatile
Definition PtexHashMap.h:126
IntKey::IntKey
IntKey()
Definition PtexHashMap.h:122
IntKey::_val
int _val
Definition PtexHashMap.h:119
IntKey::copy
void copy(volatile IntKey &key) volatile
Definition PtexHashMap.h:124
IntKey::hash
uint32_t hash() volatile const
Definition PtexHashMap.h:128
IntKey::move
void move(volatile IntKey &key) volatile
Definition PtexHashMap.h:125
IntKey::isEmpty
bool isEmpty() volatile const
Definition PtexHashMap.h:127
Mutex
Definition PtexPlatform.h:139
PtexHashMap::Entry::Entry
Entry()
Definition PtexHashMap.h:145
PtexHashMap::Entry::key
Key volatile key
Definition PtexHashMap.h:146
PtexHashMap::Entry::Entry
Entry(const Entry &)
PtexHashMap::Entry::operator=
void operator=(const Entry &)
PtexHashMap::Entry::value
Value volatile value
Definition PtexHashMap.h:147
PtexHashMap< StringKey, PtexCachedReader * >::_lock
Mutex _lock
Definition PtexHashMap.h:335
PtexHashMap::size
uint32_t size() const
Definition PtexHashMap.h:192
PtexHashMap::deleteContents
void deleteContents()
Definition PtexHashMap.h:159
PtexHashMap< StringKey, PtexCachedReader * >::_table
void * _table
Definition PtexHashMap.h:334
PtexHashMap::getTable
static void getTable(const void *table, const TableHeader *&header, const Entry *&entries)
Definition PtexHashMap.h:273
PtexHashMap::allocTable
void * allocTable(int32_t numEntries, size_t &memsize)
Definition PtexHashMap.h:262
PtexHashMap::grow
void * grow(void *oldTable, size_t &newMemUsed)
Definition PtexHashMap.h:305
PtexHashMap::PtexHashMap
PtexHashMap(const PtexHashMap &)
PtexHashMap< StringKey, PtexCachedReader * >::_oldTables
std::vector< void * > _oldTables
Definition PtexHashMap.h:336
PtexHashMap::clear
void clear()
Definition PtexHashMap.h:186
PtexHashMap::~PtexHashMap
~PtexHashMap()
Definition PtexHashMap.h:181
PtexHashMap::unlockTable
void unlockTable(void *table)
Definition PtexHashMap.h:285
PtexHashMap::get
Value get(Key &key) const
Definition PtexHashMap.h:196
PtexHashMap::PtexHashMap
PtexHashMap()
Definition PtexHashMap.h:176
PtexHashMap::initContents
void initContents()
Definition PtexHashMap.h:153
PtexHashMap::getTable
static void getTable(void *table, TableHeader *&header, Entry *&entries)
Definition PtexHashMap.h:279
PtexHashMap::lockTableAndGrowIfNeeded
void * lockTableAndGrowIfNeeded(size_t &newMemUsed)
Definition PtexHashMap.h:291
PtexHashMap::operator=
void operator=(const PtexHashMap &)
PtexHashMap::tryInsert
Value tryInsert(Key &key, Value value, size_t &newMemUsed)
Definition PtexHashMap.h:219
StringKey::isEmpty
bool isEmpty() const volatile
Definition PtexHashMap.h:109
StringKey::StringKey
StringKey(const char *val)
Definition PtexHashMap.h:75
StringKey::_ownsVal
uint16_t volatile _ownsVal
Definition PtexHashMap.h:67
StringKey::_len
uint16_t volatile _len
Definition PtexHashMap.h:66
StringKey::hash
uint32_t hash() const volatile
Definition PtexHashMap.h:111
StringKey::matches
bool matches(const StringKey &key) const volatile
Definition PtexHashMap.h:104
StringKey::_val
const char *volatile _val
Definition PtexHashMap.h:65
StringKey::_hash
uint32_t volatile _hash
Definition PtexHashMap.h:68
StringKey::StringKey
StringKey()
Definition PtexHashMap.h:74
StringKey::operator=
void operator=(const StringKey &key)
StringKey::~StringKey
~StringKey()
Definition PtexHashMap.h:83
StringKey::move
void move(volatile StringKey &key) volatile
Definition PtexHashMap.h:95
StringKey::copy
void copy(volatile StringKey &key) volatile
Definition PtexHashMap.h:85
StringKey::StringKey
StringKey(const StringKey &key)
PTEX_NAMESPACE_BEGIN
Definition PtexSeparableKernel.cpp:42
PtexHashMap::TableHeader
Definition PtexHashMap.h:136
PtexHashMap::TableHeader::size
uint32_t size
Definition PtexHashMap.h:138
PtexHashMap::TableHeader::numEntries
uint32_t numEntries
Definition PtexHashMap.h:137