Annotation of parser3/src/include/pa_hash.h, revision 1.74
1.28 paf 1: /** @file
1.29 paf 2: Parser: hash class decl.
3:
1.74 ! misha 4: Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
1.29 paf 5:
1.54 paf 6: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1 paf 7: */
8:
1.59 paf 9: /*
10: The prime numbers used from zend_hash.c,
11: the part of Zend scripting engine library,
12: Copyrighted (C) 1999-2000 Zend Technologies Ltd.
13: http://www.zend.com/license/0_92.txt
14: For more information about Zend please visit http://www.zend.com/
15: */
16:
1.1 paf 17: #ifndef PA_HASH_H
18: #define PA_HASH_H
1.56 paf 19:
1.74 ! misha 20: static const char * const IDENT_HASH_H="$Date: 2009-04-18 00:33:56 $";
1.1 paf 21:
1.59 paf 22: #include "pa_memory.h"
1.1 paf 23: #include "pa_types.h"
1.74 ! misha 24: #include "pa_string.h"
1.59 paf 25:
26: const int HASH_ALLOCATES_COUNT=29;
1.1 paf 27:
1.61 paf 28: /** Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster
29:
30: paf: HPUX ld could not handle static member: unsatisfied symbols
31: */
32: static uint Hash_allocates[HASH_ALLOCATES_COUNT]={
33: 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963,
34: 16229, 32531, 65407, 130987, 262237, 524521, 1048793,
35: 2097397, 4194103, 8388857, 16777447, 33554201, 67108961,
36: 134217487, 268435697, 536870683, 1073741621, 2147483399};
37:
1.68 misha 38: /// useful generic hash function
39: inline void generic_hash_code(uint& result, char c) {
40: result=(result<<4)+c;
41: if(uint g=(result&0xF0000000)) {
42: result=result^(g>>24);
43: result=result^g;
44: }
45: }
46: /// useful generic hash function
47: inline void generic_hash_code(uint& result, const char* s) {
48: while(char c=*s++) {
49: result=(result<<4)+c;
50: if(uint g=(result&0xF0000000)) {
51: result=result^(g>>24);
52: result=result^g;
53: }
54: }
55: }
56:
57: /// useful generic hash function
58: inline void generic_hash_code(uint& result, const char* buf, size_t size) {
59: const char* end=buf+size;
60: while(buf<end) {
61: result=(result<<4)+*buf++;
62: if(uint g=(result&0xF0000000)) {
63: result=result^(g>>24);
64: result=result^g;
65: }
66: }
67: }
68:
69: /// simple hash code of int. used by EXIF mapping
70: inline uint hash_code(int self) {
71: uint result=0;
72: generic_hash_code(result, (const char*)&self, sizeof(self));
73: return result;
74: }
75:
1.29 paf 76: /**
1.59 paf 77: Simple hash.
1.29 paf 78:
1.59 paf 79: Automatically rehashed when almost is_full.
1.51 paf 80: Contains no 0 values.
81: get returning 0 means there were no such.
82: "put value 0" means "remove"
1.29 paf 83: */
1.59 paf 84: template<typename K, typename V> class Hash: public PA_Object {
1.1 paf 85: public:
86:
1.59 paf 87: typedef K key_type;
88: typedef V value_type;
1.3 paf 89:
1.59 paf 90: Hash() {
1.61 paf 91: allocated=Hash_allocates[allocates_index=0];
1.59 paf 92: threshold=allocated*THRESHOLD_PERCENT/100;
93: fpairs_count=fused_refs=0;
94: refs=new(UseGC) Pair*[allocated];
95: }
1.25 paf 96:
1.59 paf 97: Hash(const Hash& source) {
98: allocates_index=source.allocates_index;
99: allocated=source.allocated;
100: threshold=source.threshold;
101: fused_refs=source.fused_refs;
102: fpairs_count=source.fpairs_count;
103: refs=new(UseGC) Pair*[allocated];
104:
105: // clone & rehash
106: Pair **old_ref=source.refs;
107: for(int index=0; index<allocated; index++)
108: for(Pair *pair=*old_ref++; pair; ) {
109: Pair *next=pair->link;
1.45 paf 110:
1.59 paf 111: Pair **new_ref=&refs[index];
112: *new_ref=new Pair(pair->code, pair->key, pair->value, *new_ref);
1.38 paf 113:
1.59 paf 114: pair=next;
115: }
1.43 parser 116: }
117:
1.73 misha 118: #ifdef USE_DESTRUCTORS
1.71 misha 119: ~Hash() {
1.72 misha 120: Pair **ref=refs;
121: for(int index=0; index<allocated; index++)
122: for(Pair *pair=*ref++; pair;){
123: Pair *next=pair->link;
124: delete pair;
125: pair=next;
126: }
1.71 misha 127: delete[] refs;
128: }
1.73 misha 129: #endif
1.71 misha 130:
1.59 paf 131: /// put a [value] under the [key] @returns existed or not
132: bool put(K key, V value) {
133: if(!value) {
134: remove(key);
135: return false;
136: }
137: if(is_full())
138: expand();
139:
140: uint code=hash_code(key);
141: uint index=code%allocated;
142: Pair **ref=&refs[index];
143: for(Pair *pair=*ref; pair; pair=pair->link)
144: if(pair->code==code && pair->key==key) {
145: // found a pair with the same key
146: pair->value=value;
147: return true;
148: }
149:
150: // proper pair not found -- create&link_in new pair
151: if(!*ref) // root cell were fused_refs?
152: fused_refs++; // not, we'll use it and record the fact
153: *ref=new Pair(code, key, value, *ref);
154: fpairs_count++;
155: return false;
1.24 paf 156: }
1.10 paf 157:
1.63 paf 158: /// put a [value] under the [key] @returns existed or not
1.65 paf 159: template<typename R, typename F, typename I> R replace_maybe_append(K key, V value, F prevent, I info) {
160: if(!value) {
161: // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel)
162: remove(key);
163: // this has nothing to do with properties, doing no special property handling here
164: return 0;
165: }
1.64 paf 166:
1.63 paf 167: if(is_full())
168: expand();
169:
170: uint code=hash_code(key);
171: uint index=code%allocated;
172: Pair **ref=&refs[index];
173: for(Pair *pair=*ref; pair; pair=pair->link)
174: if(pair->code==code && pair->key==key) {
175: // found a pair with the same key
1.65 paf 176: pair->value=value;
177: return reinterpret_cast<R>(1);
178: }
179:
180: // proper pair not found
181: // prevent-function intercepted append?
182: if(R result=prevent(value, info))
183: return result;
184:
185: //create&link_in new pair
186: if(!*ref) // root cell were fused_refs?
187: fused_refs++; // not, we'll use it and record the fact
188: *ref=new Pair(code, key, value, *ref);
189: fpairs_count++;
190: return 0;
191: }
1.63 paf 192:
1.65 paf 193: /// put a [value] under the [key] @returns existed or not
194: template<typename R, typename F1, typename F2, typename I>
195: R maybe_replace_maybe_append(K key, V value, F1 prevent_replace, F2 prevent_append, I info)
196: {
197: if(!value) {
198: // they can come here from Temp_value_element::dctor to restore some empty value
199: remove(key);
200: // this has nothing to do with properties, doing no special property handling here
201: return 0;
202: }
203:
204: if(is_full())
205: expand();
206:
207: uint code=hash_code(key);
208: uint index=code%allocated;
209: Pair **ref=&refs[index];
210: for(Pair *pair=*ref; pair; pair=pair->link)
211: if(pair->code==code && pair->key==key) {
212: // found a pair with the same key
213:
214: // prevent-function intercepted replace?
215: if(R result=prevent_replace(pair->value, info))
1.63 paf 216: return result;
217:
218: pair->value=value;
219: return reinterpret_cast<R>(1);
220: }
221:
1.65 paf 222: // proper pair not found
223: // prevent-function intercepted append?
224: if(R result=prevent_append(value, info))
225: return result;
226:
227: //create&link_in new pair
1.63 paf 228: if(!*ref) // root cell were fused_refs?
229: fused_refs++; // not, we'll use it and record the fact
230: *ref=new Pair(code, key, value, *ref);
231: fpairs_count++;
232: return 0;
233: }
234:
1.65 paf 235: /// put a [value] under the [key] @returns existed or not
236: template<typename R, typename F1, typename I>
237: R maybe_replace_never_append(K key, V value, F1 prevent_replace, I info)
238: {
239: if(!value) {
240: // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel)
241: remove(key);
242: // this has nothing to do with properties, doing no special property handling here
243: return 0;
244: }
245:
246: if(is_full())
247: expand();
248:
249: uint code=hash_code(key);
250: uint index=code%allocated;
251: Pair **ref=&refs[index];
252: for(Pair *pair=*ref; pair; pair=pair->link)
253: if(pair->code==code && pair->key==key) {
254: // found a pair with the same key
255:
256: // prevent-function intercepted replace?
257: if(R result=prevent_replace(pair->value, info))
258: return result;
259:
260: pair->value=value;
261: return reinterpret_cast<R>(1);
262: }
263:
264: return 0;
265: }
266:
1.59 paf 267: /// remove the [key] @returns existed or not
268: bool remove(K key) {
269: uint code=hash_code(key);
270: uint index=code%allocated;
271: for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link)
272: if((*ref)->code==code && (*ref)->key==key) {
273: // found a pair with the same key
274: Pair *next=(*ref)->link;
275: delete *ref;
276: *ref=next;
277: --fpairs_count;
278: return true;
279: }
1.8 paf 280:
1.59 paf 281: return false;
282: }
1.48 paf 283:
1.70 misha 284: /// return true if key exists
1.69 misha 285: bool contains(K key){
1.67 misha 286: uint code=hash_code(key);
287: uint index=code%allocated;
1.70 misha 288: for(Pair *pair=refs[index]; pair; pair=pair->link){
289: if(pair->code==code && pair->key==key)
1.67 misha 290: return true;
291: }
292:
293: return false;
294: }
295:
1.59 paf 296: /// get associated [value] by the [key]
297: V get(K key) const {
298: uint code=hash_code(key);
299: uint index=code%allocated;
300: for(Pair *pair=refs[index]; pair; pair=pair->link)
301: if(pair->code==code && pair->key==key)
302: return pair->value;
303:
304: return V(0);
1.33 paf 305: }
1.70 misha 306:
1.51 paf 307: /// put a [value] under the [key] if that [key] existed @returns existed or not
1.63 paf 308: bool put_replaced(K key, V value) {
1.59 paf 309: if(!value) {
310: remove(key);
311: return false;
312: }
313: uint code=hash_code(key);
314: uint index=code%allocated;
315: for(Pair *pair=refs[index]; pair; pair=pair->link)
316: if(pair->code==code && pair->key==key) {
317: // found a pair with the same key, replacing
318: pair->value=value;
319: return true;
320: }
321:
322: // proper pair not found
323: return false;
1.64 paf 324: }
325:
326: /// put a [value] under the [key] if that [key] existed @returns existed or not
327: template<typename R, typename F> R maybe_put_replaced(K key, V value, F prevent) {
1.65 paf 328: if(!value) {
329: // they can come here from Temp_value_element::dctor to restore some empty value
330: remove(key);
331: // this has nothing to do with properties, doing no special property handling here
332: return 0;
333: }
1.64 paf 334:
335: uint code=hash_code(key);
336: uint index=code%allocated;
337: for(Pair *pair=refs[index]; pair; pair=pair->link)
338: if(pair->code==code && pair->key==key) {
339: // found a pair with the same key, replacing
340: // prevent-function intercepted put?
341: if(R result=prevent(pair->value))
342: return result;
343:
344: pair->value=value;
345: return reinterpret_cast<R>(1);
346: }
347:
348: // proper pair not found
349: return 0;
1.59 paf 350: }
1.18 paf 351:
1.51 paf 352: /// put a [value] under the [key] if that [key] NOT existed @returns existed or not
1.59 paf 353: bool put_dont_replace(K key, V value) {
354: if(!value) {
355: remove(key);
356: return false;
357: }
358: if(is_full())
359: expand();
360:
361: uint code=hash_code(key);
362: uint index=code%allocated;
363: Pair **ref=&refs[index];
364: for(Pair *pair=*ref; pair; pair=pair->link)
365: if(pair->code==code && pair->key==key) {
366: // found a pair with the same key, NOT replacing
367: return true;
368: }
369:
370: // proper pair not found -- create&link_in new pair
371: if(!*ref) // root cell were fused_refs?
372: fused_refs++; // not, we'll use it and record the fact
373: *ref=new Pair(code, key, value, *ref);
374: fpairs_count++;
375: return false;
376: }
1.18 paf 377:
1.59 paf 378: /** put all 'src' values if NO with same key existed
379: @todo optimize this.allocated==src.allocated case
380: */
381: void merge_dont_replace(const Hash& src) {
382: for(int i=0; i<src.allocated; i++)
383: for(Pair *pair=src.refs[i]; pair; pair=pair->link)
384: put_dont_replace(pair->key, pair->value);
1.36 paf 385: }
1.11 paf 386:
1.29 paf 387: /// number of elements in hash
1.59 paf 388: int count() const { return fpairs_count; }
1.25 paf 389:
1.59 paf 390: /// iterate over all pairs
391: template<typename I> void for_each(void callback(K, V, I), I info) const {
392: Pair **ref=refs;
393: for(int index=0; index<allocated; index++)
394: for(Pair *pair=*ref++; pair; pair=pair->link)
395: callback(pair->key, pair->value, info);
396: }
1.45 paf 397:
1.59 paf 398: /// iterate over all pairs
399: template<typename I> void for_each_ref(void callback(K, V&, I), I info) const {
400: Pair **ref=refs;
401: for(int index=0; index<allocated; index++)
402: for(Pair *pair=*ref++; pair; pair=pair->link)
403: callback(pair->key, pair->value, info);
404: }
1.38 paf 405:
1.59 paf 406: /// iterate over all pairs until condition becomes true, return that element
407: template<typename I> V first_that(bool callback(K, V, I), I info) const {
408: Pair **ref=refs;
409: for(int index=0; index<allocated; index++)
410: for(Pair *pair=*ref++; pair; pair=pair->link)
411: if(callback(pair->key, pair->value, info))
412: return pair->value;
413:
414: return V(0);
415: }
1.27 paf 416:
1.29 paf 417: /// remove all elements
1.59 paf 418: void clear() {
419: memset(refs, 0, sizeof(*refs)*allocated);
420: fpairs_count=fused_refs=0;
421: }
1.15 paf 422:
1.74 ! misha 423: protected:
1.1 paf 424:
1.39 paf 425: /// expand when these %% of allocated exausted
1.1 paf 426: enum {
427: THRESHOLD_PERCENT=75
428: };
1.9 paf 429:
1.61 paf 430: /// the index of [allocated] in [Hash_allocates]
1.19 paf 431: int allocates_index;
1.1 paf 432:
1.39 paf 433: /// number of allocated pairs
1.19 paf 434: int allocated;
1.1 paf 435:
1.59 paf 436: /// helper: expanding when fused_refs == threshold
1.1 paf 437: int threshold;
438:
1.39 paf 439: /// used pairs
1.59 paf 440: int fused_refs;
1.44 parser 441:
442: /// stored pairs total (including those by links)
1.59 paf 443: int fpairs_count;
1.1 paf 444:
1.39 paf 445: /// pair storage
1.59 paf 446: class Pair: public PA_Allocated {
447: public:
1.1 paf 448: uint code;
1.59 paf 449: K key;
450: V value;
1.1 paf 451: Pair *link;
1.2 paf 452:
1.59 paf 453: Pair(uint acode, K akey, V avalue, Pair *alink) :
1.1 paf 454: code(acode),
455: key(akey),
456: value(avalue),
1.2 paf 457: link(alink) {}
458: } **refs;
1.1 paf 459:
1.39 paf 460: /// filled to threshold: needs expanding
1.59 paf 461: bool is_full() { return fused_refs==threshold; }
1.5 paf 462:
1.39 paf 463: /// allocate larger buffer & rehash
1.59 paf 464: void expand() {
465: int old_allocated=allocated;
466: Pair **old_refs=refs;
467:
468: allocates_index=allocates_index+1<HASH_ALLOCATES_COUNT?allocates_index+1:HASH_ALLOCATES_COUNT-1;
469: // allocated bigger refs array
1.61 paf 470: allocated=Hash_allocates[allocates_index];
1.59 paf 471: threshold=allocated*THRESHOLD_PERCENT/100;
472: refs=new(UseGC) Pair*[allocated];
473:
474: // rehash
475: Pair **old_ref=old_refs;
476: for(int old_index=0; old_index<old_allocated; old_index++)
477: for(Pair *pair=*old_ref++; pair; ) {
478: Pair *next=pair->link;
479:
480: uint new_index=pair->code%allocated;
481: Pair **new_ref=&refs[new_index];
482: pair->link=*new_ref;
483: *new_ref=pair;
484:
485: pair=next;
486: }
487:
488: delete[] old_refs;
489: }
1.4 paf 490:
491: private: //disabled
492:
1.12 paf 493: Hash& operator = (const Hash&) { return *this; }
1.1 paf 494: };
1.59 paf 495:
1.74 ! misha 496: /**
! 497: Simple String::body hash.
! 498: Allows hash code caching
! 499: */
! 500:
! 501: #ifdef HASH_CODE_CACHING
! 502:
! 503: template<typename V> class HashString: public Hash<const CORD,V> {
! 504: public:
! 505:
! 506: typedef typename Hash<const CORD,V>::Pair Pair;
! 507: typedef const String::Body &K;
! 508:
! 509: typedef K key_type;
! 510:
! 511: /// put a [value] under the [key] @returns existed or not
! 512: bool put(K str, V value) {
! 513: if(!value) {
! 514: remove(str);
! 515: return false;
! 516: }
! 517: if(this->is_full())
! 518: this->expand();
! 519:
! 520: CORD key=str.get_cord();
! 521:
! 522: uint code=str.get_hash_code();
! 523: uint index=code%this->allocated;
! 524: Pair **ref=&this->refs[index];
! 525: for(Pair *pair=*ref; pair; pair=pair->link)
! 526: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 527: // found a pair with the same key
! 528: pair->value=value;
! 529: return true;
! 530: }
! 531:
! 532: // proper pair not found -- create&link_in new pair
! 533: if(!*ref) // root cell were fused_refs?
! 534: this->fused_refs++; // not, we'll use it and record the fact
! 535: *ref=new Pair(code, key, value, *ref);
! 536: this->fpairs_count++;
! 537: return false;
! 538: }
! 539:
! 540: /// put a [value] under the [key] @returns existed or not
! 541: template<typename R, typename F, typename I> R replace_maybe_append(K str, V value, F prevent, I info) {
! 542: if(!value) {
! 543: // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel)
! 544: remove(str);
! 545: // this has nothing to do with properties, doing no special property handling here
! 546: return 0;
! 547: }
! 548:
! 549: if(this->is_full())
! 550: this->expand();
! 551:
! 552: CORD key=str.get_cord();
! 553:
! 554: uint code=str.get_hash_code();
! 555: uint index=code%this->allocated;
! 556: Pair **ref=&this->refs[index];
! 557: for(Pair *pair=*ref; pair; pair=pair->link)
! 558: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 559: // found a pair with the same key
! 560: pair->value=value;
! 561: return reinterpret_cast<R>(1);
! 562: }
! 563:
! 564: // proper pair not found
! 565: // prevent-function intercepted append?
! 566: if(R result=prevent(value, info))
! 567: return result;
! 568:
! 569: //create&link_in new pair
! 570: if(!*ref) // root cell were fused_refs?
! 571: this->fused_refs++; // not, we'll use it and record the fact
! 572: *ref=new Pair(code, key, value, *ref);
! 573: this->fpairs_count++;
! 574: return 0;
! 575: }
! 576:
! 577: /// put a [value] under the [key] @returns existed or not
! 578: template<typename R, typename F1, typename F2, typename I>
! 579: R maybe_replace_maybe_append(K str, V value, F1 prevent_replace, F2 prevent_append, I info) {
! 580: if(!value) {
! 581: // they can come here from Temp_value_element::dctor to restore some empty value
! 582: remove(str);
! 583: // this has nothing to do with properties, doing no special property handling here
! 584: return 0;
! 585: }
! 586:
! 587: if(this->is_full())
! 588: this->expand();
! 589:
! 590: CORD key=str.get_cord();
! 591:
! 592: uint code=str.get_hash_code();
! 593: uint index=code%this->allocated;
! 594: Pair **ref=&this->refs[index];
! 595: for(Pair *pair=*ref; pair; pair=pair->link)
! 596: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 597: // found a pair with the same key
! 598:
! 599: // prevent-function intercepted replace?
! 600: if(R result=prevent_replace(pair->value, info))
! 601: return result;
! 602:
! 603: pair->value=value;
! 604: return reinterpret_cast<R>(1);
! 605: }
! 606:
! 607: // proper pair not found
! 608: // prevent-function intercepted append?
! 609: if(R result=prevent_append(value, info))
! 610: return result;
! 611:
! 612: //create&link_in new pair
! 613: if(!*ref) // root cell were fused_refs?
! 614: this->fused_refs++; // not, we'll use it and record the fact
! 615: *ref=new Pair(code, key, value, *ref);
! 616: this->fpairs_count++;
! 617: return 0;
! 618: }
! 619:
! 620: /// put a [value] under the [key] @returns existed or not
! 621: template<typename R, typename F1, typename I>
! 622: R maybe_replace_never_append(K str, V value, F1 prevent_replace, I info) {
! 623: if(!value) {
! 624: // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel)
! 625: remove(str);
! 626: // this has nothing to do with properties, doing no special property handling here
! 627: return 0;
! 628: }
! 629:
! 630: if(this->is_full())
! 631: this->expand();
! 632:
! 633: CORD key=str.get_cord();
! 634:
! 635: uint code=str.get_hash_code();
! 636: uint index=code%this->allocated;
! 637: Pair **ref=&this->refs[index];
! 638: for(Pair *pair=*ref; pair; pair=pair->link)
! 639: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 640: // found a pair with the same key
! 641:
! 642: // prevent-function intercepted replace?
! 643: if(R result=prevent_replace(pair->value, info))
! 644: return result;
! 645:
! 646: pair->value=value;
! 647: return reinterpret_cast<R>(1);
! 648: }
! 649:
! 650: return 0;
! 651:
! 652: }
! 653:
! 654: /// remove the [key] @returns existed or not
! 655: bool remove(K str) {
! 656: CORD key=str.get_cord();
! 657: uint code=str.get_hash_code();
! 658: uint index=code%this->allocated;
! 659: for(Pair **ref=&this->refs[index]; *ref; ref=&(*ref)->link)
! 660: if((*ref)->code==code && CORD_cmp((*ref)->key,key)==0) {
! 661: // found a pair with the same key
! 662: Pair *next=(*ref)->link;
! 663: delete *ref;
! 664: *ref=next;
! 665: --this->fpairs_count;
! 666: return true;
! 667: }
! 668:
! 669: return false;
! 670: }
! 671:
! 672: /// return true if key exists
! 673: bool contains(K str){
! 674: CORD key=str.get_cord();
! 675: uint code=str.get_hash_code();
! 676: uint index=code%this->allocated;
! 677: for(Pair *pair=this->refs[index]; pair; pair=pair->link){
! 678: if(pair->code==code && CORD_cmp(pair->key,key)==0)
! 679: return true;
! 680: }
! 681:
! 682: return false;
! 683: }
! 684:
! 685: /// get associated [value] by the [key]
! 686: V get(K str) const {
! 687: CORD key=str.get_cord();
! 688: uint code=str.get_hash_code();
! 689: uint index=code%this->allocated;
! 690: for(Pair *pair=this->refs[index]; pair; pair=pair->link)
! 691: if(pair->code==code && CORD_cmp(pair->key,key)==0)
! 692: return pair->value;
! 693:
! 694: return V(0);
! 695: }
! 696:
! 697: /// put a [value] under the [key] if that [key] existed @returns existed or not
! 698: bool put_replaced(K str, V value) {
! 699: if(!value) {
! 700: remove(str);
! 701: return false;
! 702: }
! 703:
! 704: CORD key=str.get_cord();
! 705: uint code=str.get_hash_code();
! 706: uint index=code%this->allocated;
! 707: for(Pair *pair=this->refs[index]; pair; pair=pair->link)
! 708: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 709: // found a pair with the same key, replacing
! 710: pair->value=value;
! 711: return true;
! 712: }
! 713:
! 714: // proper pair not found
! 715: return false;
! 716: }
! 717:
! 718: /// put a [value] under the [key] if that [key] existed @returns existed or not
! 719: template<typename R, typename F> R maybe_put_replaced(K str, V value, F prevent) {
! 720: if(!value) {
! 721: // they can come here from Temp_value_element::dctor to restore some empty value
! 722: remove(str);
! 723: // this has nothing to do with properties, doing no special property handling here
! 724: return 0;
! 725: }
! 726:
! 727: CORD key=str.get_cord();
! 728: uint code=str.get_hash_code();
! 729: uint index=code%this->allocated;
! 730: for(Pair *pair=this->refs[index]; pair; pair=pair->link)
! 731: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 732: // found a pair with the same key, replacing
! 733: // prevent-function intercepted put?
! 734: if(R result=prevent(pair->value))
! 735: return result;
! 736:
! 737: pair->value=value;
! 738: return reinterpret_cast<R>(1);
! 739: }
! 740:
! 741: // proper pair not found
! 742: return 0;
! 743: }
! 744:
! 745: /// put a [value] under the [key] if that [key] NOT existed @returns existed or not
! 746: bool put_dont_replace(K str, V value) {
! 747: if(!value) {
! 748: remove(str);
! 749: return false;
! 750: }
! 751: if(this->is_full())
! 752: this->expand();
! 753:
! 754: CORD key=str.get_cord();
! 755: uint code=str.get_hash_code();
! 756: uint index=code%this->allocated;
! 757: Pair **ref=&this->refs[index];
! 758: for(Pair *pair=*ref; pair; pair=pair->link)
! 759: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
! 760: // found a pair with the same key, NOT replacing
! 761: return true;
! 762: }
! 763:
! 764: // proper pair not found -- create&link_in new pair
! 765: if(!*ref) // root cell were fused_refs?
! 766: this->fused_refs++; // not, we'll use it and record the fact
! 767: *ref=new Pair(code, key, value, *ref);
! 768: this->fpairs_count++;
! 769: return false;
! 770: }
! 771:
! 772: /// iterate over all pairs
! 773: template<typename I> void for_each(void callback(K, V, I), I info) const {
! 774: Pair **ref=this->refs;
! 775: for(int index=0; index<this->allocated; index++)
! 776: for(Pair *pair=*ref++; pair; pair=pair->link)
! 777: callback(String::Body(pair->key, pair->code), pair->value, info);
! 778: }
! 779:
! 780: /// iterate over all pairs
! 781: template<typename I> void for_each_ref(void callback(K, V&, I), I info) const {
! 782: Pair **ref=this->refs;
! 783: for(int index=0; index<this->allocated; index++)
! 784: for(Pair *pair=*ref++; pair; pair=pair->link)
! 785: callback(String::Body(pair->key, pair->code), pair->value, info);
! 786: }
! 787:
! 788: /// iterate over all pairs until condition becomes true, return that element
! 789: template<typename I> V first_that(bool callback(K, V, I), I info) const {
! 790: Pair **ref=this->refs;
! 791: for(int index=0; index<this->allocated; index++)
! 792: for(Pair *pair=*ref++; pair; pair=pair->link)
! 793: if(callback(String::Body(pair->key, pair->code), pair->value, info))
! 794: return pair->value;
! 795: return V(0);
! 796: }
! 797: };
! 798: #else
! 799:
! 800: template<typename V> class HashString: public Hash<const String::Body,V>{};
! 801:
! 802: #endif
! 803:
! 804: /// Auto-object used to temporarily substituting/removing string hash values
1.59 paf 805: template <typename K, typename V>
1.55 paf 806: class Temp_hash_value {
1.74 ! misha 807: HashString<V> &fhash;
1.59 paf 808: K fname;
809: V saved_value;
1.55 paf 810: public:
1.74 ! misha 811: Temp_hash_value(HashString<V>& ahash, K aname, V avalue) :
1.55 paf 812: fhash(ahash),
813: fname(aname),
814: saved_value(ahash.get(aname)) {
815: fhash.put(aname, avalue);
816: }
817: ~Temp_hash_value() {
818: fhash.put(fname, saved_value);
819: }
820: };
1.1 paf 821:
822: #endif
E-mail: