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
49
50inline 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
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
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>
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
154 {
155 size_t memUsed;
156 _table = allocTable(16, memUsed);
157 }
158
160 {
161 TableHeader* header;
162 Entry* entries;
163 getTable(_table, header, entries);
164
165 for (uint32_t i = 0; i < header->numEntries; ++i) {
166 entries[i].key.~Key();
167 if (entries[i].value) delete entries[i].value;
168 }
169 free(_table);
170 for (size_t i = 0; i < _oldTables.size(); ++i) {
171 free(_oldTables[i]);
172 }
173 std::vector<void*>().swap(_oldTables);
174 }
175
176public:
178 {
179 initContents();
180 }
181
183 {
185 }
186
187 void clear()
188 {
190 initContents();
191 }
192
193 uint32_t size() const {
194 return ((TableHeader*)_table)->size;
195 }
196
197 Value get(Key& key) const
198 {
199 const TableHeader* header;
200 const Entry* entries;
201 getTable(_table, header, entries);
202 uint32_t mask = header->numEntries-1;
203 uint32_t hash = key.hash();
204
205 Value result = 0;
206 for (uint32_t i = hash;; ++i) {
207 const Entry& e = entries[i & mask];
208 if (e.key.matches(key)) {
209 result = e.value;
210 break;
211 }
212 if (e.value == 0) {
213 break;
214 }
215 }
216
217 return result;
218 }
219
220 Value tryInsert(Key& key, Value value, size_t& newMemUsed)
221 {
222 void* table = lockTableAndGrowIfNeeded(newMemUsed);
223 TableHeader* header;
224 Entry* entries;
225 getTable(table, header, entries);
226 uint32_t mask = header->numEntries-1;
227 uint32_t hash = key.hash();
228
229 Value result = 0;
230 for (uint32_t i = hash;; ++i) {
231 Entry& e = entries[i & mask];
232 if (e.value == 0) {
233 e.value = value;
234 ++header->size;
235 PtexMemoryFence(); // must write key after value
236 e.key.copy(key);
237 result = e.value;
238 break;
239 }
240 while (e.key.isEmpty()) ;
241 if (e.key.matches(key)) {
242 result = e.value;
243 break;
244 }
245 }
246 unlockTable(table);
247 return result;
248 }
249
250 template <typename Fn>
251 void foreach(Fn& fn) const
252 {
253 const TableHeader* header;
254 const Entry* entries;
255 getTable(_table, header, entries);
256 for (uint32_t i = 0; i < header->numEntries; ++i) {
257 Value v = entries[i].value;
258 if (v) fn(v);
259 }
260 }
261
262private:
263 void* allocTable(int32_t numEntries, size_t& memsize)
264 {
265 memsize = sizeof(TableHeader) + sizeof(Entry) * numEntries;
266 void* table = malloc(memsize);
267 memset(table, 0, memsize);
268 TableHeader* header = new (table) TableHeader;
269 header->numEntries = numEntries;
270 header->size = 0;
271 Entry* entries = (Entry*)((char*)table + sizeof(TableHeader));
272 for (int32_t i = 0; i < numEntries; ++i)
273 {
274 new (&entries[i]) Entry();
275 }
276 return table;
277 }
278
279 static void getTable(const void* table, const TableHeader*& header, const Entry*& entries)
280 {
281 header = (const TableHeader*) table;
282 entries = (const Entry*)((const char*)table + sizeof(TableHeader));
283 }
284
285 static void getTable(void* table, TableHeader*& header, Entry*& entries)
286 {
287 header = (TableHeader*) table;
288 entries = (Entry*)((char*)table + sizeof(TableHeader));
289 }
290
291 void unlockTable(void* table)
292 {
293 _table = table;
294 _lock.unlock();
295 }
296
297 void* lockTableAndGrowIfNeeded(size_t& newMemUsed)
298 {
299 _lock.lock();
300 void* table = _table;
301 TableHeader* header;
302 Entry* entries;
303 getTable(table, header, entries);
304
305 if (header->size*2 >= header->numEntries) {
306 table = grow(table, newMemUsed);
307 }
308 return table;
309 }
310
311 void* grow(void* oldTable, size_t& newMemUsed)
312 {
313 TableHeader* oldHeader;
314 Entry* oldEntries;
315 getTable(oldTable, oldHeader, oldEntries);
316
317 _oldTables.push_back(oldTable);
318 void* newTable = allocTable(oldHeader->numEntries*2, newMemUsed);
319 TableHeader* newHeader;
320 Entry* newEntries;
321 getTable(newTable, newHeader, newEntries);
322 uint32_t mask = newHeader->numEntries-1;
323 for (uint32_t oldIndex = 0; oldIndex < oldHeader->numEntries; ++oldIndex) {
324 Entry& oldEntry = oldEntries[oldIndex];
325 if (oldEntry.value) {
326 for (int newIndex = oldEntry.key.hash();; ++newIndex) {
327 Entry& newEntry = newEntries[newIndex&mask];
328 if (!newEntry.value) {
329 newEntry.key.move(oldEntry.key);
330 newEntry.value = oldEntry.value;
331 break;
332 }
333 }
334 }
335 }
336 newHeader->size = oldHeader->size;
337 return newTable;
338 }
339
340 void* _table;
342 std::vector<void*> _oldTables;
343};
344
346
347#endif
PTEX_NAMESPACE_BEGIN bool memCompare(const char *a, const char *b, int len)
Definition PtexHashMap.h:50
Platform-specific classes, functions, and includes.
PTEX_INLINE void PtexMemoryFence()
#define PTEX_NAMESPACE_END
Definition PtexVersion.h:62
IntKey(int val)
bool matches(const IntKey &key) const volatile
void copy(volatile IntKey &key) volatile
uint32_t hash() volatile const
void move(volatile IntKey &key) volatile
bool isEmpty() volatile const
Key volatile key
Entry(const Entry &)
void operator=(const Entry &)
Value volatile value
uint32_t size() const
void deleteContents()
static void getTable(const void *table, const TableHeader *&header, const Entry *&entries)
void * allocTable(int32_t numEntries, size_t &memsize)
void * grow(void *oldTable, size_t &newMemUsed)
PtexHashMap(const PtexHashMap &)
void unlockTable(void *table)
Value get(Key &key) const
void initContents()
static void getTable(void *table, TableHeader *&header, Entry *&entries)
void * lockTableAndGrowIfNeeded(size_t &newMemUsed)
void operator=(const PtexHashMap &)
Value tryInsert(Key &key, Value value, size_t &newMemUsed)
bool isEmpty() const volatile
StringKey(const char *val)
Definition PtexHashMap.h:75
uint16_t volatile _ownsVal
Definition PtexHashMap.h:67
uint16_t volatile _len
Definition PtexHashMap.h:66
uint32_t hash() const volatile
bool matches(const StringKey &key) const volatile
const char *volatile _val
Definition PtexHashMap.h:65
uint32_t volatile _hash
Definition PtexHashMap.h:68
void operator=(const StringKey &key)
void move(volatile StringKey &key) volatile
Definition PtexHashMap.h:95
void copy(volatile StringKey &key) volatile
Definition PtexHashMap.h:85
StringKey(const StringKey &key)