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 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:
177 {
178 initContents();
179 }
180
182 {
184 }
185
186 void clear()
187 {
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;
336 std::vector<void*> _oldTables;
337};
338
340
341#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)