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 PHASH_RECORDS_AT_(self, tableIndex, index) (self->records + self->tableSize*tableIndex + index)
22 #define PHASH_RECORDS_AT_HASH_(self, tableIndex, hash) \
23 (self->records + self->tableSize*tableIndex + (hash & self->mask))
25 IOINLINE
unsigned int PHash_count(PHash
*self
)
30 IOINLINE
void PHashRecord_swap(PHashRecord
* r1
, PHashRecord
* r2
)
37 #define PHashKey_value(k) k
40 IOINLINE void *PHashKey_value(void *key)
46 IOINLINE
unsigned int PHashKey_isEqual_(void *key1
, void *key2
)
48 // return key2 && (PHashKey_value(key1) == PHashKey_value(key2));
52 // simple hash functions, should be enough for pointers
53 IOINLINE
unsigned int PHash_hash(PHash
*self
, void *key
)
55 intptr_t k
= (intptr_t)PHashKey_value(key
);
59 IOINLINE
unsigned int PHash_hash_more(PHash
*self
, unsigned int hash
)
61 return hash
^ (hash
>> self
->log2tableSize
);
64 // -----------------------------------
66 IOINLINE
void PHash_clean(PHash
*self
)
68 memset(self
->records
, 0, sizeof(PHashRecord
) * self
->tableSize
* 2);
72 IOINLINE PHashRecord
*PHash_recordAt_(PHash
*self
, void *key
)
77 hash
= PHash_hash(self
, key
);
78 record
= PHASH_RECORDS_AT_HASH_(self
, 0, hash
);
80 // we try the second location
81 hash
= PHash_hash_more(self
, hash
);
82 record
= (key
== record
->key
) ? record
: PHASH_RECORDS_AT_HASH_(self
, 1, hash
);
84 return (key
== record
->key
) ? record
: &self
->nullRecord
;
87 IOINLINE
void *PHash_at_(PHash
*self
, void *key
)
89 return PHash_recordAt_(self
, key
)->value
;
92 IOINLINE
unsigned char PHash_at_update_(PHash
*self
, void *key
, void *value
)
94 PHashRecord
*record
= PHash_recordAt_(self
, key
);
98 // already a matching key, replace it
99 if (PHashKey_isEqual_(key
, record
->key
))
101 if (record
->value
== value
)
103 return 0; // return 0 if no change
106 record
->value
= value
;
114 IOINLINE
void PHash_at_put_(PHash
*self
, void *key
, void *value
)
116 PHashRecord thisRecord
;
119 record
= PHash_recordAt_(self
, key
);
121 // already a matching key, replace it
122 if (record
!= &self
->nullRecord
&& PHashKey_isEqual_(key
, record
->key
))
124 record
->value
= value
;
128 thisRecord
.key
= key
;
129 thisRecord
.value
= value
;
131 record
= PHash_cuckoo_(self
, &thisRecord
);
133 if (!record
) // collision
135 PHash_growWithRecord(self
, &thisRecord
);
139 *record
= thisRecord
;
141 if (self
->numKeys
> PHash_maxKeys(self
))
146 IOINLINE
void PHash_removeKey_(PHash
*self
, void *key
)
148 PHashRecord
*record
= PHash_recordAt_(self
, key
);
149 void *rkey
= record
->key
;
151 if (rkey
&& PHashKey_value(rkey
) == PHashKey_value(key
))
154 memset(record
, 0, sizeof(PHashRecord
));
158 // --- enumeration --------------------------------------------------
160 #define PHASH_FOREACH(self, pkey, pvalue, code) \
162 PHash *_self = (self);\
163 unsigned int _i, _j, _size = _self->tableSize;\
167 for (_j = 0; _j < 2; _j ++)\
168 for (_i = 0; _i < _size; _i ++)\
170 PHashRecord *_record = PHASH_RECORDS_AT_(_self, _j, _i);\
173 pkey = _record->key;\
174 pvalue = _record->value;\
181 typedef BASEKIT_API void (PHashDoCallback)(void *);
183 IOINLINE void PHash_do_(PHash *self, PHashDoCallback *callback)
184 { PHASH_FOREACH(self, k, v, (*callback)(v)); }
186 IOINLINE void *PHash_detect_(PHash *self, PHashDetectCallback *callback)
187 { PHASH_FOREACH(self, k, v, if ((*callback)(v)) return k; ); return NULL; }
189 IOINLINE void PHash_doOnKeys_(PHash *self, PHashDoCallback *callback)
190 { PHASH_FOREACH(self, k, v, (*callback)(k)); }
192 IOINLINE void PHash_doOnKeyAndValue_(PHash *self, PHashDoCallback *callback)
193 { PHASH_FOREACH(self, k, v, (*callback)(k); (*callback)(v);); }