2 docCopyright("Steve Dekorte", 2002)
3 docCopyright("Marc Fauconneau", 2007)
4 docLicense("BSD revised")
7 keys and values are references (they are not copied or freed)
8 key pointers are assumed unique
16 #include "Common_inline.h"
17 #ifdef IO_DECLARE_INLINES
21 #define SHASH_RECORDS_AT_(self, tableIndex, index) (self->records + self->tableSize*tableIndex + index)
22 #define SHASH_RECORDS_AT_HASH_(self, tableIndex, hash) \
23 (self->records + self->tableSize*tableIndex + (hash & self->mask))
25 IOINLINE
unsigned int SHash_count(SHash
*self
)
30 IOINLINE
void SHashRecord_swap(SHashRecord
* r1
, SHashRecord
* r2
)
37 IOINLINE
unsigned int SHash_keysAreEqual_(SHash
*self
, void *key1
, void *key2
)
39 return key2
&& self
->keysEqual(key1
, key2
);
42 // simple hash functions, should be enough for pointers
44 IOINLINE
unsigned int SHash_hash(SHash
*self
, void *key
)
46 intptr_t k
= self
->hashForKey(key
);
50 IOINLINE
unsigned int SHash_hash_more(SHash
*self
, unsigned int hash
)
52 return hash
^ (hash
>> self
->log2tableSize
);
55 // -----------------------------------
57 IOINLINE
void SHash_clean(SHash
*self
)
59 memset(self
->records
, 0, sizeof(SHashRecord
) * self
->tableSize
* 2);
63 IOINLINE SHashRecord
*SHash_recordAt_(SHash
*self
, void *key
)
70 hash
= SHash_hash(self
, key
);
71 record
= SHASH_RECORDS_AT_HASH_(self
, 0, hash
);
72 if (SHash_keysAreEqual_(self
, key
, record
->key
)) { return record
; }
74 // try second location
76 hash
= SHash_hash_more(self
, hash
);
77 record
= SHASH_RECORDS_AT_HASH_(self
, 1, hash
);
78 if (SHash_keysAreEqual_(self
, key
, record
->key
)) { return record
; }
80 return &self
->nullRecord
;
83 IOINLINE
void *SHash_at_(SHash
*self
, void *key
)
85 return SHash_recordAt_(self
, key
)->value
;
88 IOINLINE
int SHashKey_hasKey_(SHash
*self
, void *key
)
90 return SHash_at_(self
, key
) != NULL
;
93 IOINLINE
void SHash_at_put_(SHash
*self
, void *key
, void *value
)
95 SHashRecord thisRecord
;
98 record
= SHash_recordAt_(self
, key
);
100 // already a matching key, replace it
101 if (record
!= &self
->nullRecord
&& SHash_keysAreEqual_(self
, key
, record
->key
))
103 record
->value
= value
;
107 thisRecord
.key
= key
;
108 thisRecord
.value
= value
;
110 record
= SHash_cuckoo_(self
, &thisRecord
);
112 if (!record
) // collision
114 SHash_growWithRecord(self
, &thisRecord
);
115 //printf("grow due to key collision: SHash_%p numKeys %i \ttableSize %i \tratio %f\n", (void *)self, self->numKeys, self->tableSize, (float) self->numKeys / (float) self->tableSize);
119 *record
= thisRecord
;
121 if (self
->numKeys
> SHash_maxKeys(self
))
124 //printf("grow due to full table: SHash_%p numKeys %i \ttableSize %i \tratio %f\n", (void *)self, self->numKeys, self->tableSize, (float) self->numKeys / (float) self->tableSize);
130 IOINLINE
void SHash_removeKey_(SHash
*self
, void *key
)
132 SHashRecord
*record
= SHash_recordAt_(self
, key
);
133 void *rkey
= record
->key
;
135 if (rkey
&& SHash_keysAreEqual_(self
, rkey
, key
))
138 memset(record
, 0, sizeof(SHashRecord
));
142 // --- enumeration --------------------------------------------------
144 #define SHASH_FOREACH(self, pkey, pvalue, code) \
146 SHash *_self = (self);\
147 unsigned int _i, _j, _size = _self->tableSize;\
151 for (_j = 0; _j < 2; _j ++)\
152 for (_i = 0; _i < _size; _i ++)\
154 SHashRecord *_record = SHASH_RECORDS_AT_(_self, _j, _i);\
157 pkey = _record->key;\
158 pvalue = _record->value;\
165 typedef BASEKIT_API void (SHashDoCallback)(void *);
166 IOINLINE void SHash_do_(SHash *self, SHashDoCallback *callback)
167 { SHASH_FOREACH(self, k, v, (*callback)(v)); }
169 IOINLINE void SHash_doOnKeys_(SHash *self, SHashDoCallback *callback)
170 { SHASH_FOREACH(self, k, v, (*callback)(k)); }
172 IOINLINE void SHash_doOnKeyAndValue_(SHash *self, SHashDoCallback *callback)
173 { SHASH_FOREACH(self, k, v, (*callback)(k); (*callback)(v);); }