Annotation of parser3/src/include/pa_hash.h, revision 1.90
1.28 paf 1: /** @file
1.29 paf 2: Parser: hash class decl.
3:
1.84 moko 4: Copyright (c) 2001-2012 Art. Lebedev Studio (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.90 ! moko 20: #define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.89 2015/09/24 21:28:19 moko Exp $"
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.75 misha 76: #endif // PA_HASH_H
77:
78: #ifndef PA_HASH_CLASS
79: #define PA_HASH_CLASS
1.29 paf 80: /**
1.59 paf 81: Simple hash.
1.29 paf 82:
1.59 paf 83: Automatically rehashed when almost is_full.
1.51 paf 84: Contains no 0 values.
85: get returning 0 means there were no such.
86: "put value 0" means "remove"
1.29 paf 87: */
1.75 misha 88: #ifdef HASH_ORDER
89:
90: #undef HASH
91: #undef HASH_STRING
1.79 misha 92: #undef HASH_NEW_PAIR
1.88 moko 93: #undef HASH_ORDER_CLEAR
1.79 misha 94: #undef HASH_FOR_EACH
1.75 misha 95:
96: #define HASH OrderedHash
97: #define HASH_STRING OrderedHashString
1.79 misha 98: #define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref, this->last); this->last=&((*ref)->next)
1.88 moko 99: #define HASH_ORDER_CLEAR() first=0; last=&first
1.79 misha 100:
101: #define HASH_FOR_EACH \
102: for(Pair *pair=this->first; pair; pair=pair->next)
1.75 misha 103:
104: #else
105:
106: #define HASH Hash
107: #define HASH_STRING HashString
1.79 misha 108: #define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref)
1.88 moko 109: #define HASH_ORDER_CLEAR()
1.79 misha 110:
111: #define HASH_FOR_EACH \
112: Pair **ref=this->refs; \
113: for(int index=0; index<this->allocated; index++) \
114: for(Pair *pair=*ref++; pair; pair=pair->link)
1.75 misha 115:
116: #endif
117:
118: template<typename K, typename V> class HASH: public PA_Object {
1.1 paf 119: public:
120:
1.59 paf 121: typedef K key_type;
122: typedef V value_type;
1.88 moko 123: class Pair;
1.3 paf 124:
1.75 misha 125: HASH() {
1.61 paf 126: allocated=Hash_allocates[allocates_index=0];
1.59 paf 127: fpairs_count=fused_refs=0;
1.87 moko 128: refs=new Pair*[allocated];
1.88 moko 129: HASH_ORDER_CLEAR();
1.59 paf 130: }
1.25 paf 131:
1.75 misha 132: HASH(const HASH& source) {
1.59 paf 133: allocates_index=source.allocates_index;
134: allocated=source.allocated;
135: fused_refs=source.fused_refs;
136: fpairs_count=source.fpairs_count;
1.87 moko 137: refs=new Pair*[allocated];
1.81 moko 138: // clone & rehash
1.75 misha 139: #ifdef HASH_ORDER
1.88 moko 140: HASH_ORDER_CLEAR();
1.81 moko 141: for(Pair *pair=source.first; pair; pair=pair->next)
142: {
143: uint index=pair->code%allocated;
144: Pair **ref=&refs[index];
145: HASH_NEW_PAIR(pair->code, pair->key, pair->value);
146: }
147: #else
148: for(int i=0; i<source.allocated; i++)
149: for(Pair *pair=source.refs[i]; pair; pair=pair->link)
150: {
151: Pair **ref=&refs[i];
1.79 misha 152: HASH_NEW_PAIR(pair->code, pair->key, pair->value);
1.59 paf 153: }
1.81 moko 154: #endif
1.43 parser 155: }
156:
1.73 misha 157: #ifdef USE_DESTRUCTORS
1.75 misha 158: ~HASH() {
1.72 misha 159: Pair **ref=refs;
160: for(int index=0; index<allocated; index++)
161: for(Pair *pair=*ref++; pair;){
162: Pair *next=pair->link;
163: delete pair;
164: pair=next;
165: }
1.71 misha 166: delete[] refs;
167: }
1.73 misha 168: #endif
1.71 misha 169:
1.59 paf 170: /// put a [value] under the [key] @returns existed or not
171: bool put(K key, V value) {
172: if(!value) {
173: remove(key);
174: return false;
175: }
176: if(is_full())
177: expand();
178:
179: uint code=hash_code(key);
180: uint index=code%allocated;
181: Pair **ref=&refs[index];
182: for(Pair *pair=*ref; pair; pair=pair->link)
183: if(pair->code==code && pair->key==key) {
184: // found a pair with the same key
185: pair->value=value;
186: return true;
187: }
188:
189: // proper pair not found -- create&link_in new pair
190: if(!*ref) // root cell were fused_refs?
191: fused_refs++; // not, we'll use it and record the fact
1.79 misha 192: HASH_NEW_PAIR(code, key, value);
1.59 paf 193: fpairs_count++;
194: return false;
1.24 paf 195: }
1.10 paf 196:
1.59 paf 197: /// remove the [key] @returns existed or not
198: bool remove(K key) {
199: uint code=hash_code(key);
200: uint index=code%allocated;
1.75 misha 201: for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link){
202: Pair *pair=*ref;
203: if(pair->code==code && pair->key==key) {
1.59 paf 204: // found a pair with the same key
1.75 misha 205: Pair *next=pair->link;
206: #ifdef HASH_ORDER
207: *(pair->prev)=pair->next;
208: if(pair->next)
209: pair->next->prev=pair->prev;
210: else
211: last=pair->prev;
212: #endif
213: delete pair;
1.59 paf 214: *ref=next;
215: --fpairs_count;
216: return true;
217: }
1.75 misha 218: }
1.8 paf 219:
1.59 paf 220: return false;
221: }
1.48 paf 222:
1.70 misha 223: /// return true if key exists
1.69 misha 224: bool contains(K key){
1.67 misha 225: uint code=hash_code(key);
226: uint index=code%allocated;
1.70 misha 227: for(Pair *pair=refs[index]; pair; pair=pair->link){
228: if(pair->code==code && pair->key==key)
1.67 misha 229: return true;
230: }
231:
232: return false;
233: }
234:
1.59 paf 235: /// get associated [value] by the [key]
236: V get(K key) const {
237: uint code=hash_code(key);
238: uint index=code%allocated;
239: for(Pair *pair=refs[index]; pair; pair=pair->link)
240: if(pair->code==code && pair->key==key)
241: return pair->value;
242:
243: return V(0);
1.33 paf 244: }
1.70 misha 245:
1.82 misha 246: #ifdef HASH_ORDER
1.86 misha 247: String::Body first_key() const {
248: return (first) ? String::Body(first->key, first->code) : String::Body();
249: }
250:
1.82 misha 251: V first_value() const {
252: return (first) ? first->value : V(0);
253: }
254:
1.86 misha 255: String::Body last_key() const {
256: if (fpairs_count) {
257: Pair* pair = (Pair*)((char *)last - offsetof(Pair, next));
258: return String::Body(pair->key, pair->code);
259: } else {
260: return String::Body();
261: }
262: }
263:
1.82 misha 264: V last_value() const {
265: return (fpairs_count) ? ((Pair *)((char *)last - offsetof(Pair, next)))->value : V(0);
266: }
1.88 moko 267:
268: void order_clear() {
269: HASH_ORDER_CLEAR();
270: }
271:
272: void order_next(Pair* pair) {
273: pair->prev=last;
274: pair->next=0;
275: *last=pair;
276: last=&(pair->next);
277: }
278:
1.82 misha 279: #endif
280:
1.51 paf 281: /// put a [value] under the [key] if that [key] existed @returns existed or not
1.63 paf 282: bool put_replaced(K key, V value) {
1.59 paf 283: if(!value) {
284: remove(key);
285: return false;
286: }
287: uint code=hash_code(key);
288: uint index=code%allocated;
289: for(Pair *pair=refs[index]; pair; pair=pair->link)
290: if(pair->code==code && pair->key==key) {
291: // found a pair with the same key, replacing
292: pair->value=value;
293: return true;
294: }
295:
296: // proper pair not found
297: return false;
1.64 paf 298: }
299:
1.51 paf 300: /// put a [value] under the [key] if that [key] NOT existed @returns existed or not
1.59 paf 301: bool put_dont_replace(K key, V value) {
302: if(!value) {
303: remove(key);
304: return false;
305: }
306: if(is_full())
307: expand();
308:
309: uint code=hash_code(key);
310: uint index=code%allocated;
311: Pair **ref=&refs[index];
312: for(Pair *pair=*ref; pair; pair=pair->link)
313: if(pair->code==code && pair->key==key) {
314: // found a pair with the same key, NOT replacing
315: return true;
316: }
317:
318: // proper pair not found -- create&link_in new pair
319: if(!*ref) // root cell were fused_refs?
320: fused_refs++; // not, we'll use it and record the fact
1.79 misha 321: HASH_NEW_PAIR(code, key, value);
1.59 paf 322: fpairs_count++;
323: return false;
324: }
1.18 paf 325:
1.79 misha 326: /// put all 'src' values if NO with same key existed
1.75 misha 327: void merge_dont_replace(const HASH& src) {
1.79 misha 328: #ifdef HASH_ORDER
329: for(Pair *pair=src.first; pair; pair=pair->next)
330: #else
1.59 paf 331: for(int i=0; i<src.allocated; i++)
332: for(Pair *pair=src.refs[i]; pair; pair=pair->link)
1.79 misha 333: #endif
1.59 paf 334: put_dont_replace(pair->key, pair->value);
1.36 paf 335: }
1.11 paf 336:
1.29 paf 337: /// number of elements in hash
1.59 paf 338: int count() const { return fpairs_count; }
1.25 paf 339:
1.59 paf 340: /// iterate over all pairs
341: template<typename I> void for_each(void callback(K, V, I), I info) const {
1.79 misha 342: HASH_FOR_EACH
1.76 misha 343: callback(pair->key, pair->value, info);
1.59 paf 344: }
1.45 paf 345:
1.59 paf 346: /// iterate over all pairs
347: template<typename I> void for_each_ref(void callback(K, V&, I), I info) const {
1.79 misha 348: HASH_FOR_EACH
1.76 misha 349: callback(pair->key, pair->value, info);
1.59 paf 350: }
1.38 paf 351:
1.59 paf 352: /// iterate over all pairs until condition becomes true, return that element
353: template<typename I> V first_that(bool callback(K, V, I), I info) const {
1.79 misha 354: HASH_FOR_EACH
1.75 misha 355: if(callback(pair->key, pair->value, info))
356: return pair->value;
1.59 paf 357: return V(0);
358: }
1.27 paf 359:
1.29 paf 360: /// remove all elements
1.59 paf 361: void clear() {
362: memset(refs, 0, sizeof(*refs)*allocated);
1.88 moko 363: fpairs_count=fused_refs=0;
364: HASH_ORDER_CLEAR();
1.59 paf 365: }
1.15 paf 366:
1.74 misha 367: protected:
1.1 paf 368:
1.61 paf 369: /// the index of [allocated] in [Hash_allocates]
1.19 paf 370: int allocates_index;
1.1 paf 371:
1.39 paf 372: /// number of allocated pairs
1.19 paf 373: int allocated;
1.1 paf 374:
1.39 paf 375: /// used pairs
1.59 paf 376: int fused_refs;
1.44 parser 377:
378: /// stored pairs total (including those by links)
1.59 paf 379: int fpairs_count;
1.1 paf 380:
1.39 paf 381: /// pair storage
1.59 paf 382: class Pair: public PA_Allocated {
383: public:
1.1 paf 384: uint code;
1.59 paf 385: K key;
386: V value;
1.1 paf 387: Pair *link;
1.75 misha 388: #ifdef HASH_ORDER
389: Pair **prev;
390: Pair *next;
391:
392: Pair(uint acode, K akey, V avalue, Pair *alink, Pair **aprev) : code(acode), key(akey), value(avalue), link(alink),
393: prev(aprev), next(0) { *aprev=this; }
394: #else
395: Pair(uint acode, K akey, V avalue, Pair *alink) : code(acode), key(akey), value(avalue), link(alink) {}
396: #endif
1.2 paf 397: } **refs;
1.1 paf 398:
1.75 misha 399: #ifdef HASH_ORDER
400: Pair *first;
401: Pair **last;
402: #endif
403:
1.83 moko 404: /// filled to threshold (THRESHOLD_PERCENT=75), needs expanding
405: bool is_full() { return fused_refs + allocated/4 >= allocated; }
1.5 paf 406:
1.39 paf 407: /// allocate larger buffer & rehash
1.59 paf 408: void expand() {
409: int old_allocated=allocated;
410: Pair **old_refs=refs;
411:
1.83 moko 412: if (allocates_index<HASH_ALLOCATES_COUNT-1) allocates_index++;
1.59 paf 413: // allocated bigger refs array
1.61 paf 414: allocated=Hash_allocates[allocates_index];
1.87 moko 415: refs=new Pair*[allocated];
1.59 paf 416:
417: // rehash
418: Pair **old_ref=old_refs;
419: for(int old_index=0; old_index<old_allocated; old_index++)
420: for(Pair *pair=*old_ref++; pair; ) {
421: Pair *next=pair->link;
422:
423: uint new_index=pair->code%allocated;
424: Pair **new_ref=&refs[new_index];
425: pair->link=*new_ref;
426: *new_ref=pair;
427:
428: pair=next;
429: }
430:
431: delete[] old_refs;
432: }
1.4 paf 433:
434: private: //disabled
435:
1.75 misha 436: HASH& operator = (const HASH&) { return *this; }
1.1 paf 437: };
1.59 paf 438:
1.74 misha 439: /**
1.75 misha 440: Simple String::body hash.
441: Allows hash code caching
1.74 misha 442: */
443:
444: #ifdef HASH_CODE_CACHING
445:
1.75 misha 446: template<typename V> class HASH_STRING: public HASH<const CORD,V> {
1.74 misha 447: public:
448:
1.75 misha 449: typedef typename HASH<const CORD,V>::Pair Pair;
1.74 misha 450: typedef const String::Body &K;
451:
452: typedef K key_type;
453:
454: /// put a [value] under the [key] @returns existed or not
455: bool put(K str, V value) {
456: if(!value) {
457: remove(str);
458: return false;
459: }
460: if(this->is_full())
461: this->expand();
462:
463: CORD key=str.get_cord();
464:
465: uint code=str.get_hash_code();
466: uint index=code%this->allocated;
467: Pair **ref=&this->refs[index];
468: for(Pair *pair=*ref; pair; pair=pair->link)
469: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
470: // found a pair with the same key
471: pair->value=value;
472: return true;
473: }
474:
475: // proper pair not found -- create&link_in new pair
476: if(!*ref) // root cell were fused_refs?
477: this->fused_refs++; // not, we'll use it and record the fact
1.79 misha 478: HASH_NEW_PAIR(code, key, value);
1.74 misha 479: this->fpairs_count++;
480: return false;
481: }
482:
483: /// remove the [key] @returns existed or not
484: bool remove(K str) {
485: CORD key=str.get_cord();
486: uint code=str.get_hash_code();
487: uint index=code%this->allocated;
1.75 misha 488: for(Pair **ref=&this->refs[index]; *ref; ref=&(*ref)->link){
489: Pair *pair=*ref;
490: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
1.74 misha 491: // found a pair with the same key
1.75 misha 492: Pair *next=pair->link;
493: #ifdef HASH_ORDER
494: *(pair->prev)=pair->next;
495: if(pair->next)
496: pair->next->prev=pair->prev;
497: else
498: this->last=pair->prev;
499: #endif
500: delete pair;
1.74 misha 501: *ref=next;
502: --this->fpairs_count;
503: return true;
504: }
1.75 misha 505: }
1.74 misha 506:
507: return false;
508: }
509:
510: /// return true if key exists
511: bool contains(K str){
512: CORD key=str.get_cord();
513: uint code=str.get_hash_code();
514: uint index=code%this->allocated;
515: for(Pair *pair=this->refs[index]; pair; pair=pair->link){
516: if(pair->code==code && CORD_cmp(pair->key,key)==0)
517: return true;
518: }
519:
520: return false;
521: }
522:
523: /// get associated [value] by the [key]
524: V get(K str) const {
525: CORD key=str.get_cord();
526: uint code=str.get_hash_code();
527: uint index=code%this->allocated;
528: for(Pair *pair=this->refs[index]; pair; pair=pair->link)
529: if(pair->code==code && CORD_cmp(pair->key,key)==0)
530: return pair->value;
531:
532: return V(0);
533: }
534:
535: /// put a [value] under the [key] if that [key] existed @returns existed or not
536: bool put_replaced(K str, V value) {
537: if(!value) {
538: remove(str);
539: return false;
540: }
541:
542: CORD key=str.get_cord();
543: uint code=str.get_hash_code();
544: uint index=code%this->allocated;
545: for(Pair *pair=this->refs[index]; pair; pair=pair->link)
546: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
547: // found a pair with the same key, replacing
548: pair->value=value;
549: return true;
550: }
551:
552: // proper pair not found
553: return false;
554: }
555:
556: /// put a [value] under the [key] if that [key] NOT existed @returns existed or not
557: bool put_dont_replace(K str, V value) {
558: if(!value) {
559: remove(str);
560: return false;
561: }
562: if(this->is_full())
563: this->expand();
564:
565: CORD key=str.get_cord();
566: uint code=str.get_hash_code();
567: uint index=code%this->allocated;
568: Pair **ref=&this->refs[index];
569: for(Pair *pair=*ref; pair; pair=pair->link)
570: if(pair->code==code && CORD_cmp(pair->key,key)==0) {
571: // found a pair with the same key, NOT replacing
572: return true;
573: }
574:
575: // proper pair not found -- create&link_in new pair
576: if(!*ref) // root cell were fused_refs?
577: this->fused_refs++; // not, we'll use it and record the fact
1.79 misha 578: HASH_NEW_PAIR(code, key, value);
1.74 misha 579: this->fpairs_count++;
580: return false;
581: }
582:
1.79 misha 583: /// put all 'src' values if NO with same key existed
584: void merge_dont_replace(const HASH_STRING& src) {
1.76 misha 585: #ifdef HASH_ORDER
1.79 misha 586: for(Pair *pair=src.first; pair; pair=pair->next)
1.76 misha 587: #else
1.79 misha 588: for(int i=0; i<src.allocated; i++)
589: for(Pair *pair=src.refs[i]; pair; pair=pair->link)
1.76 misha 590: #endif
1.79 misha 591: put_dont_replace(String::Body(pair->key, pair->code), pair->value);
592: }
593:
594: /// iterate over all pairs
595: template<typename I> void for_each(void callback(K, V, I), I info) const {
596: HASH_FOR_EACH
597: callback(String::Body(pair->key, pair->code), pair->value, info);
1.74 misha 598: }
599:
600: /// iterate over all pairs
601: template<typename I> void for_each_ref(void callback(K, V&, I), I info) const {
1.79 misha 602: HASH_FOR_EACH
603: callback(String::Body(pair->key, pair->code), pair->value, info);
1.74 misha 604: }
605:
606: /// iterate over all pairs until condition becomes true, return that element
607: template<typename I> V first_that(bool callback(K, V, I), I info) const {
1.79 misha 608: HASH_FOR_EACH
1.75 misha 609: if(callback(String::Body(pair->key, pair->code), pair->value, info))
610: return pair->value;
1.74 misha 611: return V(0);
612: }
1.80 misha 613:
614: /// simple hash iterator
615: class Iterator {
616: const HASH_STRING<V>& fhash;
617: Pair *fcurrent;
1.90 ! moko 618: #ifndef HASH_ORDER
1.89 moko 619: int i;
1.90 ! moko 620: #endif
1.80 misha 621: public:
622: Iterator(const HASH_STRING<V>& ahash): fhash(ahash) {
1.89 moko 623: #ifdef HASH_ORDER
1.80 misha 624: fcurrent=fhash.first;
1.89 moko 625: #else
626: fcurrent=0;
627: for(i=0; i<fhash.allocated; i++)
628: if (fcurrent=fhash.refs[i])
629: break;
630: #endif
1.80 misha 631: }
632:
633: operator bool () {
634: return fcurrent != 0;
635: }
636:
637: void next() {
1.89 moko 638: #ifdef HASH_ORDER
1.80 misha 639: fcurrent=fcurrent->next;
1.89 moko 640: #else
641: if(fcurrent=fcurrent->link)
642: return;
643: for(i++; i<fhash.allocated; i++)
644: if (fcurrent=fhash.refs[i])
645: break;
646: #endif
1.80 misha 647: }
648:
649: String::Body key(){
650: return String::Body(fcurrent->key, fcurrent->code);
651: }
652:
653: V value(){
654: return fcurrent->value;
655: }
1.88 moko 656:
657: Pair *pair(){
658: return fcurrent;
659: }
1.80 misha 660: };
1.74 misha 661: };
1.78 misha 662: #else //HASH_CODE_CACHING
1.74 misha 663:
1.75 misha 664: template<typename V> class HASH_STRING: public HASH<const String::Body,V>{};
1.74 misha 665:
1.78 misha 666: #endif //HASH_CODE_CACHING
1.74 misha 667:
1.75 misha 668: #ifndef HASH_ORDER
1.74 misha 669: /// Auto-object used to temporarily substituting/removing string hash values
1.85 moko 670: template <typename H, typename V>
1.55 paf 671: class Temp_hash_value {
1.85 moko 672: H *fhash;
673: String::Body fname;
1.59 paf 674: V saved_value;
1.55 paf 675: public:
1.85 moko 676: Temp_hash_value(H *ahash, String::Body aname, V avalue) : fhash(ahash), fname(aname) {
677: if(fhash){
678: saved_value=fhash->get(aname);
679: fhash->put(aname, avalue);
680: }
1.55 paf 681: }
1.85 moko 682: ~Temp_hash_value() {
683: if(fhash)
684: fhash->put(fname, saved_value);
1.55 paf 685: }
686: };
1.75 misha 687: #endif
1.1 paf 688:
1.75 misha 689: #endif //PA_HASH_CLASS
E-mail: