PtexExtractor/ptex/PtexDict.h

PtexExtractor/ptex/PtexDict.h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef PtexDict_h
#define PtexDict_h
template<class T>
class PtexDict
{
class Entry;
public: // Public Types
class iterator;
class const_iterator;
friend class iterator;
friend class const_iterator;
typedef const char* key_type;
typedef T mapped_type;
struct value_type {
public:
value_type(): first(0), second() {}
value_type(key_type f, const T& s): first(f), second(s) {}
const key_type first;
T second;
};
public: // Public Member Interfce
PtexDict() : _numEntries(0), _numBuckets(0), _bucketMask(0), _buckets(0) {}
virtual ~PtexDict() { clear(); }
T& operator[](const char* key);
iterator begin()
{
iterator iter;
iter._d = this;
for (iter._b = 0; iter._b < _numBuckets; iter._b++) {
iter._e = &_buckets[iter._b];
if (*iter._e) return iter;
}
iter._e = 0;
return iter;
}
inline iterator end() { return iterator( 0, this, 0 ); }
const_iterator begin() const
{
const_iterator iter;
iter._d = this;
for (iter._b = 0; iter._b < _numBuckets; iter._b++) {
iter._e = &_buckets[iter._b];
if (*iter._e) return iter;
}
iter._e = 0;
return iter;
}
inline const_iterator end() const { return const_iterator( 0, this, 0 ); }
iterator find(const char* key);
const_iterator find(const char* key) const;
bool erase(const char* key);
iterator erase(iterator iter);
void clear();
int size() const { return _numEntries; }
private: // Private Member Interface
struct Entry {
public: // Public Member Interface
Entry() : _next(0), _hashval(0), _keylen(0),
_val(_key,T()), _pad(0) {}
private: // Private Member Interface
Entry(const Entry&);
Entry& operator=(const Entry&);
public:
Entry* _next;
int _hashval;
int _keylen;
value_type _val;
union {
int _pad;
char _key[1];
};
};
PtexDict(const PtexDict&);
PtexDict& operator=(const PtexDict&);
int hash(const char* key, int& keylen) const
{
// this is similar to perl's hash function
int hashval = 0;
const char* cp = key;
char c;
while ((c = *cp++)) hashval = hashval * 33 + c;
keylen = int(cp-key)-1;
return hashval;
}
Entry** locate(const char* key, int& keylen, int& hashval) const
{
hashval = hash(key, keylen);
if (!_buckets) return 0;
for (Entry** e = &_buckets[hashval & _bucketMask]; *e; e=&(*e)->_next)
if ((*e)->_hashval == hashval && (*e)->_keylen == keylen &&
streq(key, (*e)->_key, keylen))
return e;
return 0;
}
static inline bool streq(const char* s1, const char* s2, int len)
{
// first make sure s1 is quad-aligned (s2 is always aligned)
if (((intptr_t)s1 & 3) == 0) {
int len4 = len >> 2;
while (len4--) {
if (*(int*)s1 != *(int*)s2) return 0;
s1 += 4; s2 += 4;
}
len &= 3;
}
while (len--) if (*s1++ != *s2++) return 0;
return 1;
}
void grow();
private: // Private Member data
int _numEntries;
int _numBuckets;
int _bucketMask;
Entry** _buckets;
};
template<class T>
class PtexDict<T>::iterator {
public:
iterator() : _d(0), _e(0), _b(0) {}
iterator(const iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
inline iterator& operator=(const iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
inline value_type& operator*() const { return getValue(); }
inline value_type* operator->() const { return &getValue(); }
inline operator bool() { return _e != 0; }
inline bool operator==(const iterator& iter) const
{ return iter._e == _e; }
inline bool operator!=(const iterator& iter) const
{ return iter._e != _e; }
inline bool operator==(const const_iterator& iter) const
{ return iter._e == _e; }
inline bool operator!=(const const_iterator& iter) const
{ return iter._e != _e; }
iterator& operator++(int);
private: // Private interface
iterator( Entry** e, const PtexDict* d, int b): _d(d), _e(e), _b(b) {}
inline value_type& getValue() const{
if (_e) return (*_e)->_val;
else return _defaultVal;
}
friend class PtexDict;
friend class const_iterator;
const PtexDict* _d;
Entry** _e;
int _b;
static value_type _defaultVal;
};
// define the static type for the iterator
template<class T> typename PtexDict<T>::value_type PtexDict<T>::iterator::_defaultVal;
template<class T>
class PtexDict<T>::const_iterator {
public:
const_iterator() : _d(0), _e(0), _b(0) {}
const_iterator(const const_iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
const_iterator(const iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
inline const_iterator& operator=(const const_iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
inline const_iterator& operator=(iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
inline const value_type& operator*() const { return getValue(); }
inline const value_type* operator->() const { return &getValue(); }
inline operator bool() { return _e != 0; }
inline bool operator==(const iterator& iter) const
{ return iter._e == _e; }
inline bool operator!=(const iterator& iter) const
{ return iter._e != _e; }
inline bool operator==(const const_iterator& iter) const
{ return iter._e == _e; }
inline bool operator!=(const const_iterator& iter) const
{ return iter._e != _e; }
const_iterator& operator++(int);
private: // Private interface
const_iterator( Entry** e, const PtexDict* d, int b): _d(d),_e(e),_b(b) {}
inline const value_type& getValue() const{
if (_e) return (*_e)->_val;
else return _defaultVal;
}
friend class PtexDict;
friend class iterator;
const PtexDict* _d;
Entry** _e;
int _b;
static value_type _defaultVal;
};
// define the static type for the iterator
template<class T> typename PtexDict<T>::value_type PtexDict<T>::const_iterator::_defaultVal;
template<class T>
typename PtexDict<T>::iterator& PtexDict<T>::iterator::operator++(int)
{
if (_e) {
// move to next entry
_e = &(*_e)->_next;
if (!*_e) {
// move to next non-empty bucket
for (_b++; _b < _d->_numBuckets; _b++) {
_e = &_d->_buckets[_b];
if (*_e) return *this;
}
_e = 0;
}
}
return *this;
}
template<class T>
typename PtexDict<T>::const_iterator& PtexDict<T>::const_iterator::operator++(int)
{
if (_e) {
// move to next entry
_e = &(*_e)->_next;
if (!*_e) {
// move to next non-empty bucket
for (_b++; _b < _d->_numBuckets; _b++) {
_e = &_d->_buckets[_b];
if (*_e) return *this;
}
_e = 0;
}
}
return *this;
}
template<class T>
typename PtexDict<T>::iterator PtexDict<T>::find(const char* key)
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
if (e) return iterator( e, this, hashval & _bucketMask );
else return end();
}
template<class T>
typename PtexDict<T>::const_iterator PtexDict<T>::find(const char* key) const
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
if (e) return const_iterator( e, this, hashval & _bucketMask );
else return end();
}
template<class T>
T& PtexDict<T>::operator[](const char* key)
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
if (e) return (*e)->_val.second;
// create a new entry
_numEntries++;
if (_numEntries*2 >= _numBuckets) grow();
// allocate a buffer big enough to hold Entry + (the key length )
// Note: the NULL character is already accounted for by Entry::_key's size
void* ebuf = malloc( sizeof(Entry) + (keylen) * sizeof(char) );
Entry* ne = new(ebuf) Entry; // note: placement new
// Store the values in the Entry structure
Entry** slot = &_buckets[hashval & _bucketMask];
ne->_next = *slot; *slot = ne;
ne->_hashval = hashval;
ne->_keylen = keylen;
// copy the string given into the new location
memcpy(ne->_key, key, keylen);
ne->_key[keylen] = '\0';
return ne->_val.second;
}
template<class T>
void PtexDict<T>::grow()
{
if (!_buckets) {
_numBuckets = 16;
_bucketMask = _numBuckets - 1;
_buckets = (Entry**) calloc(_numBuckets, sizeof(Entry*));
} else {
int newsize = _numBuckets * 2;
_bucketMask = newsize - 1;
Entry** newbuckets = (Entry**) calloc(newsize, sizeof(Entry*));
for (int i = 0; i < _numBuckets; i++) {
for (Entry* e = _buckets[i]; e;) {
Entry* _next = e->_next;
Entry** slot = &newbuckets[e->_hashval & _bucketMask];
e->_next = *slot; *slot = e;
e = _next;
}
}
free(_buckets);
_buckets = newbuckets;
_numBuckets = newsize;
}
}
template<class T>
bool PtexDict<T>::erase(const char* key)
{
iterator iter = find(key);
if (!iter) return false;
erase(iter);
return true; // valid entry to remove
}
template<class T>
typename PtexDict<T>::iterator PtexDict<T>::erase(iterator iter)
{
Entry** eptr = iter._e;
if (!eptr) return iter;
// patch around deleted entry
Entry* e = *eptr;
Entry* next = e->_next;
if (!next) iter++; // advance iterator if at end of chain
*eptr = next;
// destroy entry. This is a strange destroy but is necessary because of
// the way Entry() is allocated by using malloc above.
e->~Entry(); // note: explicit dtor call
free(e); // free memory allocated.
_numEntries--;
return iter;
}
template<class T>
void PtexDict<T>::clear()
{
for (iterator i=begin(); i != end(); i = erase(i));
free(_buckets);
_buckets = 0;
_numEntries = 0;
_numBuckets = 0;
}
#endif //PtexDict_h