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