1 //metadoc PHash copyright Steve Dekorte 2002, Marc Fauconneau 2007
2 //metadoc PHash license BSD revised
3 /*metadoc PHash description
5 keys and values are references (they are not copied or freed)
6 key pointers are assumed unique
12 #include "Common_inline.h"
13 #ifdef IO_DECLARE_INLINES
17 #define PHASH_RECORDS_AT_(self, tableIndex, index) (self->records + self->tableSize*tableIndex + index)
18 #define PHASH_RECORDS_AT_HASH_(self, tableIndex, hash) \
19 (self->records + self->tableSize*tableIndex + (hash & self->mask))
21 IOINLINE
unsigned int PHash_count(PHash
*self
)
26 IOINLINE
void PHashRecord_swap(PHashRecord
* r1
, PHashRecord
* r2
)
33 #define PHashKey_value(k) k
36 IOINLINE void *PHashKey_value(void *key)
42 IOINLINE
unsigned int PHashKey_isEqual_(void *key1
, void *key2
)
44 // return key2 && (PHashKey_value(key1) == PHashKey_value(key2));
48 // simple hash functions, should be enough for pointers
49 IOINLINE
unsigned int PHash_hash(PHash
*self
, void *key
)
51 intptr_t k
= (intptr_t)PHashKey_value(key
);
55 IOINLINE
unsigned int PHash_hash_more(PHash
*self
, unsigned int hash
)
57 return hash
^ (hash
>> self
->log2tableSize
);
60 // -----------------------------------
62 IOINLINE
void PHash_clean(PHash
*self
)
64 memset(self
->records
, 0, sizeof(PHashRecord
) * self
->tableSize
* 2);
68 IOINLINE PHashRecord
*PHash_recordAt_(PHash
*self
, void *key
)
73 hash
= PHash_hash(self
, key
);
74 record
= PHASH_RECORDS_AT_HASH_(self
, 0, hash
);
76 // we try the second location
77 hash
= PHash_hash_more(self
, hash
);
78 record
= (key
== record
->key
) ? record
: PHASH_RECORDS_AT_HASH_(self
, 1, hash
);
80 return (key
== record
->key
) ? record
: &self
->nullRecord
;
83 IOINLINE
void *PHash_at_(PHash
*self
, void *key
)
85 return PHash_recordAt_(self
, key
)->value
;
88 IOINLINE
unsigned char PHash_at_update_(PHash
*self
, void *key
, void *value
)
90 PHashRecord
*record
= PHash_recordAt_(self
, key
);
94 // already a matching key, replace it
95 if (PHashKey_isEqual_(key
, record
->key
))
97 if (record
->value
== value
)
99 return 0; // return 0 if no change
102 record
->value
= value
;
110 IOINLINE
void PHash_at_put_(PHash
*self
, void *key
, void *value
)
112 PHashRecord thisRecord
;
115 record
= PHash_recordAt_(self
, key
);
117 // already a matching key, replace it
118 if (record
!= &self
->nullRecord
&& PHashKey_isEqual_(key
, record
->key
))
120 record
->value
= value
;
124 thisRecord
.key
= key
;
125 thisRecord
.value
= value
;
127 record
= PHash_cuckoo_(self
, &thisRecord
);
129 if (!record
) // collision
131 PHash_growWithRecord(self
, &thisRecord
);
135 *record
= thisRecord
;
137 if (self
->numKeys
> PHash_maxKeys(self
))
142 IOINLINE
void PHash_removeKey_(PHash
*self
, void *key
)
144 PHashRecord
*record
= PHash_recordAt_(self
, key
);
145 void *rkey
= record
->key
;
147 if (rkey
&& PHashKey_value(rkey
) == PHashKey_value(key
))
150 memset(record
, 0, sizeof(PHashRecord
));
154 // --- enumeration --------------------------------------------------
156 #define PHASH_FOREACH(self, pkey, pvalue, code) \
158 PHash *_self = (self);\
159 unsigned int _i, _j, _size = _self->tableSize;\
163 for (_j = 0; _j < 2; _j ++)\
164 for (_i = 0; _i < _size; _i ++)\
166 PHashRecord *_record = PHASH_RECORDS_AT_(_self, _j, _i);\
169 pkey = _record->key;\
170 pvalue = _record->value;\
177 typedef BASEKIT_API void (PHashDoCallback)(void *);
179 IOINLINE void PHash_do_(PHash *self, PHashDoCallback *callback)
180 { PHASH_FOREACH(self, k, v, (*callback)(v)); }
182 IOINLINE void *PHash_detect_(PHash *self, PHashDetectCallback *callback)
183 { PHASH_FOREACH(self, k, v, if ((*callback)(v)) return k; ); return NULL; }
185 IOINLINE void PHash_doOnKeys_(PHash *self, PHashDoCallback *callback)
186 { PHASH_FOREACH(self, k, v, (*callback)(k)); }
188 IOINLINE void PHash_doOnKeyAndValue_(PHash *self, PHashDoCallback *callback)
189 { PHASH_FOREACH(self, k, v, (*callback)(k); (*callback)(v);); }