forked from LeenkxTeam/LNXSDK
829 lines
22 KiB
C++
829 lines
22 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HXCPP_TELEMETRY
|
|
extern void __hxt_new_hash(void* obj, int size);
|
|
#endif
|
|
|
|
namespace hx
|
|
{
|
|
|
|
|
|
inline unsigned int HashCalcHash(int inKey) { return inKey; }
|
|
inline unsigned int HashCalcHash(cpp::Int64 inKey) { return (unsigned int)((inKey >> 32) ^ inKey); }
|
|
inline unsigned int HashCalcHash(const String &inKey) { return inKey.hash(); }
|
|
inline unsigned int HashCalcHash(const Dynamic &inKey)
|
|
{
|
|
return __hxcpp_obj_hash(inKey);
|
|
}
|
|
|
|
inline void HashClear(int &ioValue) { }
|
|
inline void HashClear(Dynamic &ioValue) { ioValue=null(); }
|
|
inline void HashClear(String &ioValue) { ioValue=String(); }
|
|
inline void HashClear(Float &ioValue) { }
|
|
inline void HashClear(cpp::Int64 &ioValue) { }
|
|
|
|
template<typename T>
|
|
struct NeedsMarking { enum { Yes = 0 }; };
|
|
template<> struct NeedsMarking<Dynamic> { enum { Yes = 1 }; };
|
|
template<> struct NeedsMarking<String> { enum { Yes = 1 }; };
|
|
|
|
// An int element has key = hash
|
|
template<typename VALUE>
|
|
struct TIntElement
|
|
{
|
|
typedef int Key;
|
|
typedef VALUE Value;
|
|
|
|
enum { IgnoreHash = 1 };
|
|
enum { WeakKeys = 0 };
|
|
enum { ManageKeys = 0 };
|
|
|
|
typedef TIntElement<int> IntValue;
|
|
typedef TIntElement<Float> FloatValue;
|
|
typedef TIntElement<Dynamic> DynamicValue;
|
|
typedef TIntElement<String> StringValue;
|
|
typedef TIntElement<cpp::Int64> Int64Value;
|
|
|
|
public:
|
|
inline void setKey(int inKey, unsigned int )
|
|
{
|
|
key = inKey;
|
|
}
|
|
inline unsigned int getHash() { return key; }
|
|
|
|
Value value;
|
|
Key key;
|
|
TIntElement<VALUE> *next;
|
|
};
|
|
|
|
//
|
|
template<typename VALUE>
|
|
struct TInt64Element
|
|
{
|
|
typedef cpp::Int64 Key;
|
|
typedef VALUE Value;
|
|
|
|
enum { IgnoreHash = 0 };
|
|
enum { WeakKeys = 0 };
|
|
enum { ManageKeys = 1 };
|
|
|
|
typedef TInt64Element<int> IntValue;
|
|
typedef TInt64Element<Float> FloatValue;
|
|
typedef TInt64Element<Dynamic> DynamicValue;
|
|
typedef TInt64Element<String> StringValue;
|
|
typedef TInt64Element<cpp::Int64> Int64Value;
|
|
|
|
public:
|
|
inline void setKey(cpp::Int64 inKey, unsigned int inHash)
|
|
{
|
|
key = inKey;
|
|
hash = inHash;
|
|
}
|
|
inline unsigned int getHash() { return hash; }
|
|
|
|
Value value;
|
|
Key key;
|
|
unsigned int hash;
|
|
TInt64Element<VALUE> *next;
|
|
};
|
|
|
|
// An string element gets hash from string or calculates it
|
|
template<typename VALUE>
|
|
struct TStringElement
|
|
{
|
|
typedef String Key;
|
|
typedef VALUE Value;
|
|
|
|
enum { IgnoreHash = 0 };
|
|
enum { WeakKeys = 0 };
|
|
enum { ManageKeys = 1 };
|
|
|
|
typedef TStringElement<int> IntValue;
|
|
typedef TStringElement<Float> FloatValue;
|
|
typedef TStringElement<Dynamic> DynamicValue;
|
|
typedef TStringElement<String> StringValue;
|
|
typedef TStringElement<cpp::Int64> Int64Value;
|
|
|
|
|
|
public:
|
|
inline void setKey(String inKey, unsigned int inHash)
|
|
{
|
|
key = inKey;
|
|
hash = inHash;
|
|
}
|
|
inline unsigned int getHash() { return hash; }
|
|
|
|
Value value;
|
|
Key key;
|
|
unsigned int hash;
|
|
TStringElement<VALUE> *next;
|
|
};
|
|
|
|
|
|
struct TWeakStringSet
|
|
{
|
|
typedef null Value;
|
|
typedef String Key;
|
|
|
|
enum { IgnoreHash = 0 };
|
|
enum { WeakKeys = 1 };
|
|
enum { ManageKeys = 1 };
|
|
|
|
typedef TWeakStringSet IntValue;
|
|
typedef TWeakStringSet FloatValue;
|
|
typedef TWeakStringSet DynamicValue;
|
|
typedef TWeakStringSet StringValue;
|
|
typedef TWeakStringSet Int64Value;
|
|
|
|
|
|
public:
|
|
inline void setKey(String inKey, unsigned int inHash)
|
|
{
|
|
key = inKey;
|
|
hash = inHash;
|
|
}
|
|
inline unsigned int getHash() { return hash; }
|
|
|
|
Key key;
|
|
unsigned int hash;
|
|
Value value;
|
|
TWeakStringSet *next;
|
|
};
|
|
|
|
|
|
struct TNonGcStringSet
|
|
{
|
|
typedef null Value;
|
|
typedef String Key;
|
|
|
|
enum { IgnoreHash = 0 };
|
|
enum { WeakKeys = 1 };
|
|
enum { ManageKeys = 0 };
|
|
|
|
typedef TNonGcStringSet IntValue;
|
|
typedef TNonGcStringSet FloatValue;
|
|
typedef TNonGcStringSet DynamicValue;
|
|
typedef TNonGcStringSet StringValue;
|
|
typedef TNonGcStringSet Int64Value;
|
|
|
|
|
|
public:
|
|
inline void setKey(String inKey, unsigned int inHash)
|
|
{
|
|
key = inKey;
|
|
hash = inHash;
|
|
}
|
|
inline unsigned int getHash() { return hash; }
|
|
|
|
Key key;
|
|
unsigned int hash;
|
|
Value value;
|
|
TNonGcStringSet *next;
|
|
};
|
|
|
|
|
|
|
|
|
|
// An Dyanamic element must use the GC code to get a hash
|
|
template<typename VALUE,bool WEAK>
|
|
struct TDynamicElement
|
|
{
|
|
typedef Dynamic Key;
|
|
typedef VALUE Value;
|
|
|
|
enum { IgnoreHash = 0 };
|
|
enum { WeakKeys = WEAK };
|
|
enum { ManageKeys = 1 };
|
|
|
|
typedef TDynamicElement<int,WEAK> IntValue;
|
|
typedef TDynamicElement<Float,WEAK> FloatValue;
|
|
typedef TDynamicElement<Dynamic,WEAK> DynamicValue;
|
|
typedef TDynamicElement<String,WEAK> StringValue;
|
|
typedef TDynamicElement<cpp::Int64,WEAK> Int64Value;
|
|
|
|
public:
|
|
inline void setKey(Dynamic inKey, unsigned int inHash)
|
|
{
|
|
key = inKey;
|
|
hash = inHash;
|
|
}
|
|
inline unsigned int getHash() { return hash; }
|
|
|
|
Value value;
|
|
Key key;
|
|
unsigned int hash;
|
|
TDynamicElement<VALUE,WEAK> *next;
|
|
};
|
|
|
|
|
|
|
|
|
|
enum HashStore
|
|
{
|
|
hashInt,
|
|
hashFloat,
|
|
hashString,
|
|
hashObject,
|
|
hashNull,
|
|
hashInt64
|
|
};
|
|
template<typename T> struct StoreOf{ enum {store=hashObject}; };
|
|
template<> struct StoreOf<int> { enum {store=hashInt}; };
|
|
template<> struct StoreOf< ::String> { enum {store=hashString}; };
|
|
template<> struct StoreOf<Float> { enum {store=hashFloat}; };
|
|
template<> struct StoreOf<null> { enum {store=hashNull}; };
|
|
template<> struct StoreOf<cpp::Int64> { enum {store=hashInt64}; };
|
|
|
|
namespace
|
|
{
|
|
inline void CopyValue(Dynamic &outValue, const Dynamic &inValue) { outValue = inValue; }
|
|
inline void CopyValue(String &outValue, const String &inValue) { outValue = inValue; }
|
|
inline void CopyValue(String &outValue, Float inValue) { }
|
|
inline void CopyValue(String &outValue, const Dynamic &inValue) { outValue = inValue; }
|
|
inline void CopyValue(int &outValue, int inValue) { outValue = inValue; }
|
|
inline void CopyValue(int &outValue, cpp::Int64 inValue) { }
|
|
inline void CopyValue(int &outValue, Float inValue) { outValue = inValue; }
|
|
inline void CopyValue(int &outValue, const Dynamic &inValue) { outValue = inValue; }
|
|
inline void CopyValue(int &outValue, const String &inValue) { }
|
|
inline void CopyValue(Float &outValue, Float inValue) { outValue = inValue; }
|
|
inline void CopyValue(Float &outValue, const Dynamic &inValue) { outValue = inValue; }
|
|
inline void CopyValue(Float &outValue, const String &inValue) { }
|
|
inline void CopyValue(cpp::Int64 &outValue, cpp::Int64 inValue) { outValue = inValue; }
|
|
inline void CopyValue(cpp::Int64 &outValue, int inValue) { outValue = inValue; }
|
|
inline void CopyValue(cpp::Int64 &outValue, Float inValue) { }
|
|
inline void CopyValue(cpp::Int64 &outValue, const Dynamic &inValue) { outValue = inValue; }
|
|
inline void CopyValue(cpp::Int64 &outValue, const String &inValue) { }
|
|
inline void CopyValue(null &, const null &) { }
|
|
template<typename T> inline void CopyValue(T &outValue, const null &) { }
|
|
template<typename T> inline void CopyValue(null &, const T &) { }
|
|
}
|
|
|
|
|
|
struct HashRoot : public Object
|
|
{
|
|
HashStore store;
|
|
int size;
|
|
int mask;
|
|
int bucketCount;
|
|
|
|
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdHash };
|
|
|
|
virtual void updateAfterGc() = 0;
|
|
|
|
inline int getSize() { return size; }
|
|
};
|
|
|
|
template<typename KEY>
|
|
struct HashBase : public HashRoot
|
|
{
|
|
HashBase(int inStore)
|
|
{
|
|
store = (HashStore)inStore;
|
|
size = 0;
|
|
mask = 0;
|
|
bucketCount = 0;
|
|
}
|
|
|
|
|
|
virtual bool query(KEY inKey,int &outValue) = 0;
|
|
virtual bool query(KEY inKey,::String &outValue) = 0;
|
|
virtual bool query(KEY inKey,Float &outValue) = 0;
|
|
virtual bool query(KEY inKey,Dynamic &outValue) = 0;
|
|
virtual bool query(KEY inKey,cpp::Int64 &outValue) = 0;
|
|
|
|
virtual void set(KEY inKey, const int &inValue) = 0;
|
|
virtual void set(KEY inKey, const ::String &inValue) = 0;
|
|
virtual void set(KEY inKey, const Float &inValue) = 0;
|
|
virtual void set(KEY inKey, const Dynamic &inValue) = 0;
|
|
virtual void set(KEY inKey, const cpp::Int64 &inValue) = 0;
|
|
|
|
virtual void clear() = 0;
|
|
|
|
virtual HashBase<KEY> *convertStore(HashStore inStore) = 0;
|
|
|
|
virtual bool remove(KEY inKey) = 0;
|
|
virtual bool exists(KEY inKey) = 0;
|
|
virtual Array<KEY> keys() = 0;
|
|
virtual Dynamic values() = 0;
|
|
|
|
virtual ::String toStringRaw() { return toString(); }
|
|
};
|
|
|
|
extern void RegisterWeakHash(HashBase<Dynamic> *);
|
|
extern void RegisterWeakHash(HashBase< ::String> *);
|
|
|
|
inline void RegisterWeakHash(HashBase<int> *) { };
|
|
inline void RegisterWeakHash(HashBase<cpp::Int64> *) { };
|
|
|
|
|
|
template<typename T>
|
|
struct ArrayValueOf{ typedef T Value; };
|
|
template<> struct ArrayValueOf<null> { typedef Dynamic Value; };
|
|
|
|
template<typename ELEMENT>
|
|
struct Hash : public HashBase< typename ELEMENT::Key >
|
|
{
|
|
using HashRoot::size;
|
|
using HashRoot::mask;
|
|
using HashRoot::bucketCount;
|
|
using HashRoot::getSize;
|
|
|
|
typedef typename ELEMENT::Key Key;
|
|
typedef typename ELEMENT::Value Value;
|
|
typedef typename ArrayValueOf<Value>::Value ArrayValue;
|
|
|
|
typedef ELEMENT Element;
|
|
enum { IgnoreHash = Element::IgnoreHash };
|
|
|
|
|
|
ELEMENT **bucket;
|
|
|
|
|
|
Hash() : HashBase<Key>( StoreOf<Value>::store )
|
|
{
|
|
bucket = 0;
|
|
if (ELEMENT::WeakKeys && Element::ManageKeys)
|
|
RegisterWeakHash(this);
|
|
}
|
|
|
|
template<typename T>
|
|
bool TIsWeakRefValid(T &) { return true; }
|
|
bool TIsWeakRefValid(Dynamic &key) { return IsWeakRefValid(key.mPtr); }
|
|
bool TIsWeakRefValid(String &key) { return IsWeakRefValid(key.raw_ptr()); }
|
|
|
|
|
|
void updateAfterGc()
|
|
{
|
|
if (Element::WeakKeys && Element::ManageKeys)
|
|
{
|
|
for(int b=0;b<bucketCount;b++)
|
|
{
|
|
Element **headPtr = &bucket[b];
|
|
while(*headPtr)
|
|
{
|
|
Element &el = **headPtr;
|
|
if (!TIsWeakRefValid(el.key))
|
|
{
|
|
*headPtr = el.next;
|
|
size--;
|
|
}
|
|
else
|
|
headPtr = &el.next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void rebucket(int inNewCount)
|
|
{
|
|
#ifdef HXCPP_TELEMETRY
|
|
bool is_new = bucket==0;
|
|
#endif
|
|
mask = inNewCount-1;
|
|
//printf("expand %d -> %d\n",bucketCount, inNewCount);
|
|
bucket = (Element **)InternalRealloc(bucketCount*sizeof(ELEMENT *), bucket,inNewCount*sizeof(ELEMENT *));
|
|
HX_OBJ_WB_GET(this, bucket);
|
|
//for(int b=bucketCount;b<inNewCount;b++)
|
|
// bucket[b] = 0;
|
|
|
|
#ifdef HXCPP_TELEMETRY
|
|
if (is_new) __hxt_new_hash(bucket, inNewCount*sizeof(ELEMENT *));
|
|
#endif
|
|
|
|
|
|
for(int b=0;b<bucketCount;b++)
|
|
{
|
|
Element **head = &bucket[b];
|
|
while(*head)
|
|
{
|
|
Element &e = **head;
|
|
int newBucket = e.getHash()&mask;
|
|
if ( newBucket != b )
|
|
{
|
|
*head = e.next;
|
|
e.next = bucket[newBucket];
|
|
bucket[newBucket] = &e;
|
|
}
|
|
else
|
|
head = &e.next;
|
|
}
|
|
}
|
|
|
|
bucketCount = inNewCount;
|
|
}
|
|
|
|
void reserve(int inSize)
|
|
{
|
|
if (inSize<8)
|
|
inSize = 8;
|
|
|
|
expandBuckets(inSize);
|
|
}
|
|
|
|
void compact()
|
|
{
|
|
int origSize = bucketCount;
|
|
int newSize = bucketCount>>1;
|
|
// printf("compact -> %d\n", newSize);
|
|
mask = newSize-1;
|
|
for(int b=newSize; b<bucketCount; b++)
|
|
{
|
|
Element *head = bucket[b];
|
|
if (head)
|
|
{
|
|
Element *oldHead = bucket[b-newSize];
|
|
bucket[b-newSize] = head;
|
|
|
|
if (oldHead)
|
|
{
|
|
// Append to last element
|
|
Element **lastPtr = &(head->next);
|
|
while(*lastPtr)
|
|
lastPtr = & (*lastPtr)->next;
|
|
*lastPtr = oldHead;
|
|
}
|
|
bucket[b] = 0;
|
|
}
|
|
}
|
|
bucketCount = newSize;
|
|
bucket = (Element **)InternalRealloc(origSize*sizeof(ELEMENT *),bucket, sizeof(ELEMENT *)*bucketCount );
|
|
HX_OBJ_WB_GET(this, bucket);
|
|
}
|
|
|
|
bool remove(Key inKey)
|
|
{
|
|
if (!bucket)
|
|
return false;
|
|
unsigned int hash = HashCalcHash(inKey);
|
|
Element **head = bucket + (hash&mask);
|
|
while(*head)
|
|
{
|
|
Element &el = **head;
|
|
if ( (IgnoreHash || el.getHash()==hash) && el.key==inKey)
|
|
{
|
|
*head = el.next;
|
|
size--;
|
|
if (bucketCount>8 && size < (bucketCount>>1) )
|
|
compact();
|
|
return true;
|
|
}
|
|
head = &el.next;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ELEMENT *allocElement()
|
|
{
|
|
ELEMENT *result = (ELEMENT *)InternalNew( sizeof(ELEMENT), false );
|
|
size++;
|
|
expandBuckets(size);
|
|
return result;
|
|
}
|
|
|
|
inline void expandBuckets(int inSize)
|
|
{
|
|
// Trades memory vs bucket occupancy - more memory is used for elements anyhow, so not too critical
|
|
enum { LOG_ELEMS_PER_BUCKET = 1 };
|
|
if ( inSize > (bucketCount<<LOG_ELEMS_PER_BUCKET) )
|
|
{
|
|
int newCount = bucketCount;
|
|
if (newCount==0)
|
|
newCount = 2;
|
|
else
|
|
while( inSize > (newCount<<LOG_ELEMS_PER_BUCKET) )
|
|
newCount<<=1;
|
|
if (newCount!=bucketCount)
|
|
rebucket(newCount);
|
|
}
|
|
}
|
|
|
|
Element *find(int inHash, Key inKey)
|
|
{
|
|
if (!bucket) return 0;
|
|
Element *head = bucket[inHash & mask];
|
|
while(head)
|
|
{
|
|
if ( (IgnoreHash || head->getHash()==inHash) && head->key==inKey)
|
|
return head;
|
|
head = head->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool exists(Key inKey) { return find( HashCalcHash(inKey), inKey ); }
|
|
|
|
|
|
HashBase<Key> *convertStore(HashStore inStore)
|
|
{
|
|
switch(inStore)
|
|
{
|
|
case hashInt:
|
|
return TConvertStore< typename ELEMENT::IntValue >();
|
|
case hashFloat:
|
|
return TConvertStore< typename ELEMENT::FloatValue >();
|
|
case hashString:
|
|
return TConvertStore< typename ELEMENT::StringValue >();
|
|
case hashObject:
|
|
return TConvertStore< typename ELEMENT::DynamicValue >();
|
|
case hashInt64:
|
|
return TConvertStore< typename ELEMENT::Int64Value >();
|
|
case hashNull:
|
|
;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<typename OUT_VALUE>
|
|
bool TQuery(Key inKey,OUT_VALUE &outValue)
|
|
{
|
|
Element *result = find( HashCalcHash(inKey), inKey );
|
|
if (!result)
|
|
return false;
|
|
CopyValue(outValue,result->value);
|
|
return true;
|
|
}
|
|
|
|
bool query(Key inKey,int &outValue) { return TQuery(inKey,outValue); }
|
|
bool query(Key inKey,::String &outValue) { return TQuery(inKey,outValue); }
|
|
bool query(Key inKey,Float &outValue) { return TQuery(inKey,outValue); }
|
|
bool query(Key inKey,Dynamic &outValue) { return TQuery(inKey,outValue); }
|
|
bool query(Key inKey,cpp::Int64 &outValue) { return TQuery(inKey, outValue); }
|
|
|
|
|
|
Value get(Key inKey)
|
|
{
|
|
Element *result = find( HashCalcHash(inKey), inKey );
|
|
if (result)
|
|
return result->value;
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<typename Finder>
|
|
bool findEquivalentKey(Key &outKey, int inHash, const Finder &inFinder)
|
|
{
|
|
if (!bucket) return false;
|
|
Element *head = bucket[inHash & mask];
|
|
while(head)
|
|
{
|
|
if ( (IgnoreHash || head->getHash()==inHash) && inFinder==head->key)
|
|
{
|
|
outKey = head->key;
|
|
return true;
|
|
}
|
|
head = head->next;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool IsNursery(const void *inPtr)
|
|
{
|
|
return inPtr && !(((unsigned char *)inPtr)[ HX_ENDIAN_MARK_ID_BYTE]);
|
|
}
|
|
|
|
template<typename SET>
|
|
void TSet(Key inKey, const SET &inValue)
|
|
{
|
|
unsigned int hash = HashCalcHash(inKey);
|
|
Element *el = find(hash,inKey);
|
|
if (el)
|
|
{
|
|
CopyValue(el->value,inValue);
|
|
if (hx::ContainsPointers<Value>()) {
|
|
HX_OBJ_WB_GET(this,hx::PointerOf(el->value))
|
|
}
|
|
return;
|
|
}
|
|
el = allocElement();
|
|
el->setKey(inKey,hash);
|
|
CopyValue(el->value,inValue);
|
|
el->next = bucket[hash&mask];
|
|
bucket[hash&mask] = el;
|
|
|
|
#ifdef HXCPP_GC_GENERATIONAL
|
|
unsigned char &mark = ((unsigned char *)(this))[ HX_ENDIAN_MARK_ID_BYTE];
|
|
if (mark == hx::gByteMarkID)
|
|
{
|
|
// Look for nursery objects...
|
|
if ( IsNursery(el) || IsNursery(hx::PointerOf(el->key)) ||
|
|
(hx::ContainsPointers<Value>() && IsNursery(hx::PointerOf(el->value)) ) )
|
|
{
|
|
mark|=HX_GC_REMEMBERED;
|
|
(HX_CTX_GET)->pushReferrer(this);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void set(Key inKey, const int &inValue) { TSet(inKey, inValue); }
|
|
void set(Key inKey, const ::String &inValue) { TSet(inKey, inValue); }
|
|
void set(Key inKey, const Float &inValue) { TSet(inKey, inValue); }
|
|
void set(Key inKey, const Dynamic &inValue) { TSet(inKey, inValue); }
|
|
void set(Key inKey, const null &inValue) { TSet(inKey, inValue); }
|
|
void set(Key inKey, const cpp::Int64 &inValue) { TSet(inKey, inValue); }
|
|
|
|
void clear()
|
|
{
|
|
bucket = 0;
|
|
size = 0;
|
|
mask = 0;
|
|
bucketCount = 0;
|
|
}
|
|
|
|
|
|
template<typename F>
|
|
void iterate(F &inFunc)
|
|
{
|
|
for(int b=0;b<bucketCount;b++)
|
|
{
|
|
Element *el = bucket[b];
|
|
while(el)
|
|
{
|
|
inFunc(el);
|
|
el = el->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Convert
|
|
template<typename NEW>
|
|
struct Converter
|
|
{
|
|
NEW *result;
|
|
|
|
Converter(NEW *inResult) : result(inResult) { }
|
|
|
|
void operator()(typename Hash::Element *elem)
|
|
{
|
|
result->set(elem->key,elem->value);
|
|
}
|
|
};
|
|
|
|
|
|
template<typename NEW_ELEM>
|
|
HashBase<Key> *TConvertStore()
|
|
{
|
|
Hash<NEW_ELEM> *result = new Hash<NEW_ELEM>();
|
|
|
|
result->reserve(getSize()*3/2);
|
|
|
|
Converter< Hash<NEW_ELEM> > converter(result);
|
|
|
|
iterate(converter);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
// Keys ...
|
|
struct KeyBuilder
|
|
{
|
|
Array<Key> array;
|
|
|
|
KeyBuilder(int inReserve = 0)
|
|
{
|
|
array = Array<Key>(0,inReserve);
|
|
}
|
|
void operator()(typename Hash::Element *elem)
|
|
{
|
|
array->push(elem->key);
|
|
}
|
|
};
|
|
Array<Key> keys()
|
|
{
|
|
KeyBuilder builder(getSize());
|
|
iterate(builder);
|
|
return builder.array;;
|
|
}
|
|
|
|
|
|
// Values...
|
|
struct ValueBuilder
|
|
{
|
|
Array<ArrayValue> array;
|
|
ValueBuilder(int inReserve = 0)
|
|
{
|
|
array = Array<ArrayValue>(0,inReserve);
|
|
}
|
|
|
|
void operator()(typename Hash::Element *elem)
|
|
{
|
|
array->push(elem->value);
|
|
}
|
|
};
|
|
Dynamic values()
|
|
{
|
|
ValueBuilder builder(getSize());
|
|
iterate(builder);
|
|
return builder.array;;
|
|
}
|
|
|
|
|
|
// Strings ...
|
|
struct StringBuilder
|
|
{
|
|
Array<String> array;
|
|
bool raw;
|
|
|
|
StringBuilder(int inReserve = 0,bool inRaw=false)
|
|
{
|
|
raw = inRaw;
|
|
array = Array<String>(0,inReserve*4+1);
|
|
if (!raw) {
|
|
#if (HXCPP_API_LEVEL >= 430)
|
|
array->push(HX_CSTRING("["));
|
|
#else
|
|
array->push(HX_CSTRING("{ "));
|
|
#endif
|
|
}
|
|
}
|
|
void operator()(typename Hash::Element *elem)
|
|
{
|
|
if (array->length>1)
|
|
array->push(HX_CSTRING(", "));
|
|
array->push(String(elem->key));
|
|
array->push(HX_CSTRING(" => "));
|
|
array->push(String(elem->value));
|
|
}
|
|
::String toString()
|
|
{
|
|
if (!raw) {
|
|
#if (HXCPP_API_LEVEL >= 430)
|
|
array->push(HX_CSTRING("]"));
|
|
#else
|
|
array->push(HX_CSTRING(" }"));
|
|
#endif
|
|
}
|
|
return array->length==0 ? String() : array->join(HX_CSTRING(""));
|
|
}
|
|
};
|
|
|
|
String toString()
|
|
{
|
|
StringBuilder builder(getSize());
|
|
iterate(builder);
|
|
return builder.toString();
|
|
}
|
|
|
|
|
|
String toStringRaw()
|
|
{
|
|
StringBuilder builder(getSize(),true);
|
|
iterate(builder);
|
|
return builder.toString();
|
|
}
|
|
|
|
|
|
// Mark ...
|
|
struct HashMarker
|
|
{
|
|
hx::MarkContext *__inCtx;
|
|
HashMarker(hx::MarkContext *ctx) : __inCtx(ctx) { }
|
|
void operator()(typename Hash::Element *inElem)
|
|
{
|
|
HX_MARK_ARRAY(inElem);
|
|
if (!Hash::Element::WeakKeys)
|
|
{
|
|
HX_MARK_MEMBER(inElem->key);
|
|
}
|
|
HX_MARK_MEMBER(inElem->value);
|
|
}
|
|
};
|
|
|
|
void __Mark(hx::MarkContext *__inCtx)
|
|
{
|
|
HX_MARK_ARRAY(bucket);
|
|
|
|
HashMarker marker(__inCtx);
|
|
iterate(marker);
|
|
}
|
|
|
|
#ifdef HXCPP_VISIT_ALLOCS
|
|
|
|
void __Visit(hx::VisitContext *__inCtx)
|
|
{
|
|
//printf(" visit hash %p\n", this);
|
|
HX_VISIT_ARRAY(bucket);
|
|
for(int b=0;b<bucketCount;b++)
|
|
{
|
|
HX_VISIT_ARRAY(bucket[b]);
|
|
Element *el = bucket[b];
|
|
while(el)
|
|
{
|
|
HX_VISIT_MEMBER(el->key);
|
|
HX_VISIT_MEMBER(el->value);
|
|
HX_VISIT_ARRAY(el->next);
|
|
el = el->next;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
};
|
|
|
|
|
|
} // end namespace hx
|
|
|