Ptex

PtexHashMap.h
Go to the documentation of this file.
1/*
2 PTEX SOFTWARE
3 Copyright 2014 Disney Enterprises, Inc. All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
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
22 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF 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
73 public:
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
121 public:
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
131 template <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 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
176 public:
177 PtexHashMap()
178 {
179 initContents();
180 }
181
182 ~PtexHashMap()
183 {
184 deleteContents();
185 }
186
187 void clear()
188 {
189 deleteContents();
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
262 private:
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;
341 Mutex _lock;
342 std::vector<void*> _oldTables;
343};
344
345 PTEX_NAMESPACE_END
346
347#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:341
PtexHashMap::size
uint32_t size() const
Definition PtexHashMap.h:193
PtexHashMap::deleteContents
void deleteContents()
Definition PtexHashMap.h:159
PtexHashMap< StringKey, PtexCachedReader * >::_table
void * _table
Definition PtexHashMap.h:340
PtexHashMap::getTable
static void getTable(const void *table, const TableHeader *&header, const Entry *&entries)
Definition PtexHashMap.h:279
PtexHashMap::allocTable
void * allocTable(int32_t numEntries, size_t &memsize)
Definition PtexHashMap.h:263
PtexHashMap::grow
void * grow(void *oldTable, size_t &newMemUsed)
Definition PtexHashMap.h:311
PtexHashMap::PtexHashMap
PtexHashMap(const PtexHashMap &)
PtexHashMap< StringKey, PtexCachedReader * >::_oldTables
std::vector< void * > _oldTables
Definition PtexHashMap.h:342
PtexHashMap::clear
void clear()
Definition PtexHashMap.h:187
PtexHashMap::~PtexHashMap
~PtexHashMap()
Definition PtexHashMap.h:182
PtexHashMap::unlockTable
void unlockTable(void *table)
Definition PtexHashMap.h:291
PtexHashMap::get
Value get(Key &key) const
Definition PtexHashMap.h:197
PtexHashMap::PtexHashMap
PtexHashMap()
Definition PtexHashMap.h:177
PtexHashMap::initContents
void initContents()
Definition PtexHashMap.h:153
PtexHashMap::getTable
static void getTable(void *table, TableHeader *&header, Entry *&entries)
Definition PtexHashMap.h:285
PtexHashMap::lockTableAndGrowIfNeeded
void * lockTableAndGrowIfNeeded(size_t &newMemUsed)
Definition PtexHashMap.h:297
PtexHashMap::operator=
void operator=(const PtexHashMap &)
PtexHashMap::tryInsert
Value tryInsert(Key &key, Value value, size_t &newMemUsed)
Definition PtexHashMap.h:220
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