1 /* @source ajtable ************************************************************
2 **
3 ** AJAX table functions
4 **
5 ** Hash table functions.
6 **
7 ** @author Copyright (C) 1998 Ian Longden
8 ** @version $Revision: 1.74 $
9 ** @modified 2011 pmr Auto-resizing, destructors, table merges
10 ** @modified $Date: 2013/02/17 13:39:44 $ by $Author: mks $
11 ** @@
12 **
13 ** This library is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU Lesser General Public
15 ** License as published by the Free Software Foundation; either
16 ** version 2.1 of the License, or (at your option) any later version.
17 **
18 ** This library is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** Lesser General Public License for more details.
22 **
23 ** You should have received a copy of the GNU Lesser General Public
24 ** License along with this library; if not, write to the Free Software
25 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 ** MA 02110-1301, USA.
27 **
28 ******************************************************************************/
29
30
31 #include "ajlib.h"
32
33 #include "ajtable.h"
34 #include "ajassert.h"
35
36 #include <limits.h>
37 #include <string.h>
38 #include <ctype.h>
39
40
41
42
43 /* ========================================================================= */
44 /* =============================== constants =============================== */
45 /* ========================================================================= */
46
47
48
49
50 /* ========================================================================= */
51 /* =========================== global variables ============================ */
52 /* ========================================================================= */
53
54
55
56
57 /* ========================================================================= */
58 /* ============================= private data ============================== */
59 /* ========================================================================= */
60
61
62
63
64 /* ========================================================================= */
65 /* =========================== private constants =========================== */
66 /* ========================================================================= */
67
68
69
70
71 /* ========================================================================= */
72 /* =========================== private variables =========================== */
73 /* ========================================================================= */
74
75 #ifdef AJ_SAVESTATS
76 static ajuint tableNewCnt = 0U;
77 static ajint tableDelCnt = 0;
78 static ajuint tableMaxNum = 0U;
79 static size_t tableMaxMem = 0;
80 #endif
81
82 static AjPStr tableTmpkeyStr = NULL;
83
84 static ajulong tableFreeNext = 0UL;
85 static ajulong tableFreeMax = 0UL;
86 static AjPTableNode* tableFreeSet = NULL;
87
88
89
90
91 /* ========================================================================= */
92 /* =========================== private functions =========================== */
93 /* ========================================================================= */
94
95 static ajint tableCmpAtom(const void* key1, const void* key2);
96 static void tableDel(void** Pkey, void** Pvalue, void* cl);
97 static void tableDelKey(void** Pkey, void** Pvalue, void* cl);
98 static void tableFreeSetExpand (void);
99 static ajulong tableHashAtom(const void* key, ajulong hashsize);
100 static void tableStrDel(void** Pkey, void** Pvalue, void* cl);
101 static void tableStrDelKey(void** Pkey, void** Pvalue, void* cl);
102
103 static void tableDelStr(void** Pstr);
104 static const char* tableType(const AjPTable table);
105 static void tableStrFromKey(const AjPTable table, const void* key,
106 AjPStr* Pstr);
107
108
109
110
111 /* ========================================================================= */
112 /* ======================= All functions by section ======================== */
113 /* ========================================================================= */
114
115
116
117
118 /* @filesection ajtable *******************************************************
119 **
120 ** @nam1rule aj Function belongs to the AJAX library.
121 **
122 ** @suffix C [char*] C character string
123 ** @suffix S [AjPStr] string object
124 ** @suffix Len [ajuint] size of hash table
125 **
126 ******************************************************************************/
127
128
129
130
131 /* @datasection [AjPTable] Hash tables ****************************************
132 **
133 ** Function is for manipulating hash tables with any value type.
134 **
135 ** Some functions are specially designed to understand string (AjPStr) values.
136 **
137 ** @nam2rule Table
138 **
139 ******************************************************************************/
140
141
142
143
144 /* @section Constructors ******************************************************
145 **
146 ** Constructors for hash tables
147 **
148 ** @fdata [AjPTable]
149 **
150 ** @fcategory new
151 **
152 ** @nam3rule New Constructor
153 ** @nam4rule Function Functions defined by caller
154 **
155 ** @argrule New size [ajulong] Number of key values
156 ** @argrule Function cmp [ajint function] Comparison function returning
157 ** +1, zero or -1
158 ** @argrule Function hash [ajulong function] Hash function for keys
159 ** @argrule Function keydel [void function] key destructor function
160 ** @argrule Function valdel [void function] value destructor function
161 **
162 ** @valrule * [AjPTable] New hash table
163 **
164 ******************************************************************************/
165
166
167
168
169 /* @func ajTableNew ***********************************************************
170 **
171 ** creates, initialises, and returns a new, empty table that expects
172 ** a specified number of key-value pairs.
173 **
174 ** Current method defines the table size as the number of entries divided by 4
175 ** to avoid a huge table.
176 **
177 ** @param [r] size [ajulong] number of key-value pairs
178 **
179 ** @return [AjPTable] new table.
180 **
181 **
182 ** @release 1.0.0
183 ** @@
184 **
185 ******************************************************************************/
186
ajTableNew(ajulong size)187 AjPTable ajTableNew(ajulong size)
188 {
189 AjPTable table = NULL;
190
191 table = ajTableNewFunctionLen(size, &tableCmpAtom, &tableHashAtom,
192 NULL, NULL);
193 table->Type = ajETableTypeUser;
194
195 return table;
196 }
197
198
199
200
201 /* @func ajTableNewFunctionLen ************************************************
202 **
203 ** creates, initialises, and returns a new, empty table that expects
204 ** a specified number of key-value pairs.
205 **
206 ** Current method defines the table size as the number of entries divided by 4
207 ** to avoid a huge table.
208 **
209 ** @param [r] size [ajulong] number of key-value pairs
210 ** @param [fN] cmp [ajint function] function for comparing
211 ** @param [fN] hash [ajulong function] function for hashing keys
212 ** @param [fN] keydel [void function] key destructor function
213 ** @param [fN] valdel [void function] value destructor function
214 **
215 ** @return [AjPTable] new table.
216 **
217 **
218 ** @release 5.0.0
219 ** @@
220 **
221 ******************************************************************************/
222
ajTableNewFunctionLen(ajulong size,ajint (* cmp)(const void * key1,const void * key2),ajulong (* hash)(const void * key,ajulong hashsize),void (* keydel)(void ** Pkey),void (* valdel)(void ** Pvalue))223 AjPTable ajTableNewFunctionLen(ajulong size,
224 ajint (*cmp)(const void* key1,
225 const void* key2),
226 ajulong (*hash)(const void* key,
227 ajulong hashsize),
228 void (*keydel)(void** Pkey),
229 void (*valdel)(void** Pvalue))
230 {
231 ajulong hint = 0UL;
232 ajulong i = 0UL;
233 ajulong iprime = 0UL;
234
235 AjPTable table = NULL;
236
237 /* largest primes just under 2**8 to 2**31 */
238
239 static ajuint primes[] =
240 {
241 3, 7, 13, 31, 61, 127,
242 251, 509,
243 1021, 2039, 4093, 8191,
244 16381, 32749, 65521,
245 131071, 262139, 524287,
246 1048573, 2097143, 4194301, 8388593,
247 16777213, 33554393, 67108859,
248 134217689, 268435399, 536870909,
249 1073741789, 2147483647,
250 UINT_MAX
251 };
252
253 hint = size/4;
254
255 for(i = 1U; primes[i] <= hint; i++); /* else use default primes[0] */
256
257 iprime = primes[i - 1];
258
259 /*ajDebug("ajTableNewFunctionLen hint %d size %d\n", hint, iprime);*/
260
261 AJNEW0(table);
262 table->Size = iprime;
263 table->Fcmp = cmp;
264 table->Fhash = hash;
265 table->Fkeydel = keydel;
266 table->Fvaldel = valdel;
267
268 AJCNEW(table->Buckets, iprime);
269
270 for(i = 0UL; i < table->Size; i++)
271 table->Buckets[i] = NULL;
272
273 table->Length = 0UL;
274 table->Timestamp = 0U;
275
276 #ifdef AJ_SAVESTATS
277 tableNewCnt++;
278
279 if(iprime > tableMaxNum)
280 tableMaxNum = iprime;
281
282 if(sizeof(*table) > tableMaxMem)
283 tableMaxMem = sizeof(*table);
284 #endif
285
286 table->Use = 1;
287 table->Type = ajETableTypeUser;
288
289 return table;
290 }
291
292
293
294
295 /* @section Destructors *******************************************************
296 **
297 ** @fdata [AjPTable]
298 **
299 ** Destructors know they are dealing with strings and can
300 ** clean up keys and values
301 **
302 ** @nam3rule Del Delete table
303 ** @nam4rule Keydel Delete keys using destructor
304 ** @nam4rule Valdel Delete values using destructor
305 ** @nam5rule KeydelValdel Delete keys and values using destructors
306 ** @nam3rule Free Delete table, ignore keys and values
307 **
308 ** @argrule * Ptable [AjPTable*] Hash table
309 ** @argrule Keydel keydel [void function] Key destructor function
310 ** @argrule Valdel valdel [void function] Value destructor function
311 **
312 ** @valrule * [void]
313 **
314 ** @fcategory delete
315 **
316 ******************************************************************************/
317
318
319
320
321 /* @func ajTableDel ***********************************************************
322 **
323 ** Deallocates and clears a hash table, and any keys or values.
324 **
325 ** @param [d] Ptable [AjPTable*] Table (by reference)
326 ** @return [void]
327 **
328 ** @release 6.4.0
329 ** @@
330 ******************************************************************************/
331
ajTableDel(AjPTable * Ptable)332 void ajTableDel(AjPTable* Ptable)
333 {
334 AjPTable thys;
335
336 if(!Ptable)
337 return;
338 if(!*Ptable)
339 return;
340
341 thys = *Ptable;
342
343 if(!thys->Use)
344 ajErr("trying to delete unused table");
345
346 --thys->Use;
347
348 if(!thys->Use)
349 { /* any other references? */
350 ajTableClearDelete(thys);
351
352 AJFREE(thys->Buckets);
353 AJFREE(*Ptable);
354 }
355
356 *Ptable = NULL;
357
358 return;
359 }
360
361
362
363
364 /* @func ajTableDelKeydelValdel ***********************************************
365 **
366 ** Deallocates and clears a hash table, and any keys or values.
367 **
368 ** @param [d] Ptable [AjPTable*] Table (by reference)
369 ** @param [f] keydel [void function] key destructor
370 ** @param [f] valdel [void function] value destructor
371 ** @return [void]
372 **
373 ** @release 6.4.0
374 ** @@
375 ******************************************************************************/
376
ajTableDelKeydelValdel(AjPTable * Ptable,void (* keydel)(void ** Pkey),void (* valdel)(void ** Pvalue))377 void ajTableDelKeydelValdel(AjPTable* Ptable,
378 void (*keydel)(void** Pkey),
379 void (*valdel)(void** Pvalue))
380 {
381 AjPTable thys;
382
383 if(!Ptable)
384 return;
385 if(!*Ptable)
386 return;
387
388 thys = *Ptable;
389
390 if(!thys->Use)
391 ajErr("trying to delete unused table");
392
393 --thys->Use;
394
395 if(!thys->Use)
396 { /* any other references? */
397 thys->Fkeydel = keydel;
398 thys->Fvaldel = valdel;
399
400 ajTableClearDelete(thys);
401
402 AJFREE(thys->Buckets);
403 AJFREE(*Ptable);
404 }
405
406 *Ptable = NULL;
407
408 return;
409 }
410
411
412
413
414 /* @func ajTableDelValdel *****************************************************
415 **
416 ** Deallocates and clears a hash table, and any keys or values.
417 **
418 ** @param [d] Ptable [AjPTable*] Table (by reference)
419 ** @param [f] valdel [void function] value destructor
420 ** @return [void]
421 **
422 ** @release 6.4.0
423 ** @@
424 ******************************************************************************/
425
ajTableDelValdel(AjPTable * Ptable,void (* valdel)(void ** Pvalue))426 void ajTableDelValdel(AjPTable* Ptable,
427 void (*valdel)(void** Pvalue))
428 {
429 AjPTable thys;
430
431 if(!Ptable)
432 return;
433 if(!*Ptable)
434 return;
435
436 thys = *Ptable;
437
438 if(!thys->Use)
439 ajErr("trying to delete unused table");
440
441 --thys->Use;
442
443 if(!thys->Use)
444 { /* any other references? */
445 thys->Fvaldel = valdel;
446
447 ajTableClearDelete(thys);
448
449 AJFREE(thys->Buckets);
450 AJFREE(*Ptable);
451 }
452
453 *Ptable = NULL;
454
455 return;
456 }
457
458
459
460
461 /* @func ajTableFree **********************************************************
462 **
463 ** Deallocates and clears a hash table. Does not clear keys or values.
464 **
465 ** @param [d] Ptable [AjPTable*] Table (by reference)
466 ** @return [void]
467 **
468 ** @release 1.0.0
469 ** @@
470 ******************************************************************************/
471
ajTableFree(AjPTable * Ptable)472 void ajTableFree(AjPTable* Ptable)
473 {
474 AjPTable thys;
475
476 if(!Ptable)
477 return;
478 if(!*Ptable)
479 return;
480
481 thys = *Ptable;
482
483 if(!thys->Use)
484 ajErr("trying to delete unused table");
485
486 --thys->Use;
487
488 if(!thys->Use)
489 { /* any other references? */
490 ajTableClear(thys);
491
492 AJFREE(thys->Buckets);
493 AJFREE(*Ptable);
494 }
495
496 *Ptable = NULL;
497
498 return;
499 }
500
501
502
503
504 /* @funcstatic tableFreeSetExpand *********************************************
505 **
506 ** Expand the list of free AJAX Table Node objects.
507 **
508 ** @return [void]
509 **
510 ** @release 6.0.0
511 ******************************************************************************/
512
tableFreeSetExpand(void)513 static void tableFreeSetExpand (void)
514 {
515 ajulong newsize;
516
517 if(!tableFreeSet)
518 {
519 tableFreeMax = 1024;
520 AJCNEW0(tableFreeSet,tableFreeMax);
521
522 return;
523 }
524
525 if(tableFreeMax >= 65536)
526 return;
527
528 newsize = tableFreeMax + tableFreeMax;
529 AJCRESIZE0(tableFreeSet, (size_t) tableFreeMax, (size_t) newsize);
530 tableFreeMax = newsize;
531
532 return;
533 }
534
535
536
537
538 /* @funcstatic tableDel *******************************************************
539 **
540 ** Delete an entry in a table by freeing the key and value pointers
541 **
542 ** @param [d] Pkey [void**] Standard argument. Table key.
543 ** @param [d] Pvalue [void**] Standard argument. Table item.
544 ** @param [u] cl [void*] Standard argument. Usually NULL.
545 ** @return [void]
546 **
547 ** @release 6.4.0
548 ** @@
549 ******************************************************************************/
550
tableDel(void ** Pkey,void ** Pvalue,void * cl)551 static void tableDel(void** Pkey, void** Pvalue, void* cl)
552 {
553 AJFREE(*Pkey);
554 AJFREE(*Pvalue);
555
556 (void) cl;
557
558 return;
559 }
560
561
562
563
564 /* @funcstatic tableDelKey ****************************************************
565 **
566 ** Delete an entry in a table by freeing the key pointers
567 **
568 ** @param [d] Pkey [void**] Standard argument. Table key.
569 ** @param [d] Pvalue [void**] Standard argument. Table item.
570 ** @param [u] cl [void*] Standard argument. Usually NULL.
571 ** @return [void]
572 **
573 ** @release 6.4.0
574 ** @@
575 ******************************************************************************/
576
tableDelKey(void ** Pkey,void ** Pvalue,void * cl)577 static void tableDelKey(void** Pkey, void** Pvalue, void* cl)
578 {
579 AJFREE(*Pkey);
580 *Pvalue = NULL;
581
582 (void) cl;
583
584 return;
585 }
586
587
588
589
590 /* @section Retrieval *********************************************************
591 **
592 ** @fdata [AjPTable]
593 **
594 ** Retrieves values from a hash table
595 **
596 ** @nam3rule Fetch Retrieval function for read-only value
597 ** @nam3rule Fetchmod Retrieval function for modifiable value
598 ** @nam3rule Fetchkey Key retrieval function
599 ** @nam3rule Get return attribute
600 ** @nam4rule GetLength Table number of entries
601 ** @nam4rule GetSize Table hash array size
602 ** @nam4rule Trace Debug report on table internals
603 ** @nam3rule Match Test key matches in table
604 ** @nam3rule Toarray Return keys and values as arrays
605 ** @suffix Keys Return keys as array
606 ** @suffix Values Return values as array
607 ** @suffix C Pass key as C string
608 ** @suffix S Pass key as string object
609 ** @suffix V Pass key as void
610 **
611 ** @argrule * table [const AjPTable] Hash table
612 ** @argrule C txtkey [const char*] Key
613 ** @argrule S key [const AjPStr] Key
614 ** @argrule V key [const void*] Key
615 ** @argrule Keys keyarray [void***] Array of keys, ending with NULL
616 ** @argrule Values valarray [void***] Array of values, ending with NULL
617 **
618 ** @valrule Fetch [const void*] Value
619 ** @valrule Fetchmod [void*] Value
620 ** @valrule *Fetchkey [const void*] Key
621 ** @valrule *Length [ajulong] Number of unique keys and values
622 ** @valrule *Match [AjBool] True if a match was found
623 ** @valrule *Size [ajulong] Hash array size
624 ** @valrule *Toarray [ajulong] Array size (not counting trailing NULL)
625 ** @fcategory cast
626 **
627 ******************************************************************************/
628
629
630
631
632 /* @func ajTableFetchC ********************************************************
633 **
634 ** returns the value associated with key in table, or null
635 ** if table does not hold key.
636 **
637 ** @param [r] table [const AjPTable] table to search
638 ** @param [r] txtkey [const char*] key to find.
639 ** @return [const void*] value associated with key
640 ** @error NULL if key not found in table.
641 **
642 ** @release 6.4.0
643 ** @@
644 ******************************************************************************/
645
ajTableFetchC(const AjPTable table,const char * txtkey)646 const void* ajTableFetchC(const AjPTable table, const char* txtkey)
647 {
648 ajulong i = 0UL;
649
650 AjPTableNode node = NULL;
651
652 if(!table)
653 return NULL;
654
655 if(!txtkey)
656 return NULL;
657
658 if(table->Type == ajETableTypeStr)
659 {
660 ajStrAssignC(&tableTmpkeyStr, txtkey);
661 return ajTableFetchS(table, tableTmpkeyStr);
662 }
663
664 if(table->Type != ajETableTypeChar)
665 ajFatal("ajTableFetchC called for %s table", tableType(table));
666
667 i = (*table->Fhash)(txtkey, table->Size);
668
669 for(node = table->Buckets[i]; node; node = node->Link)
670 if((*table->Fcmp)(txtkey, node->Key) == 0)
671 break;
672
673 return node ? node->Value : NULL;
674 }
675
676
677
678
679 /* @func ajTableFetchS ********************************************************
680 **
681 ** returns the value associated with key in table, or null
682 ** if table does not hold key.
683 **
684 ** @param [r] table [const AjPTable] table to search
685 ** @param [r] key [const AjPStr] key to find.
686 ** @return [const void*] value associated with key
687 ** @error NULL if key not found in table.
688 **
689 ** @release 6.4.0
690 ** @@
691 ******************************************************************************/
692
ajTableFetchS(const AjPTable table,const AjPStr key)693 const void* ajTableFetchS(const AjPTable table, const AjPStr key)
694 {
695 ajulong i = 0UL;
696
697 AjPTableNode node = NULL;
698
699 if(!table)
700 return NULL;
701
702 if(!key)
703 return NULL;
704
705 if(table->Type == ajETableTypeChar)
706 return ajTableFetchC(table, MAJSTRGETPTR(key));
707
708 if(table->Type != ajETableTypeStr)
709 ajFatal("ajTableFetchS called for %s table", tableType(table));
710
711 i = (*table->Fhash)(key, table->Size);
712
713 for(node = table->Buckets[i]; node; node = node->Link)
714 if((*table->Fcmp)(key, node->Key) == 0)
715 break;
716
717 return node ? node->Value : NULL;
718 }
719
720
721
722
723 /* @func ajTableFetchV ********************************************************
724 **
725 ** Returns the value associated with key in table, or null
726 ** if table does not hold key.
727 **
728 ** @param [r] table [const AjPTable] table to search
729 ** @param [r] key [const void*] key to find.
730 ** @return [const void*] value associated with key
731 ** @error NULL if key not found in table.
732 **
733 ** @release 6.4.0
734 ** @@
735 ******************************************************************************/
736
ajTableFetchV(const AjPTable table,const void * key)737 const void* ajTableFetchV(const AjPTable table, const void* key)
738 {
739 ajulong i = 0UL;
740
741 AjPTableNode node = NULL;
742
743 if(!table)
744 return NULL;
745
746 if(!key)
747 return NULL;
748
749 i = (*table->Fhash)(key, table->Size);
750
751 for(node = table->Buckets[i]; node; node = node->Link)
752 if((*table->Fcmp)(key, node->Key) == 0)
753 break;
754
755 return node ? node->Value : NULL;
756 }
757
758
759
760
761 /* @func ajTableFetchmodC *****************************************************
762 **
763 ** returns the value associated with key in table, or null
764 ** if table does not hold key.
765 **
766 ** @param [r] table [const AjPTable] table to search
767 ** @param [r] txtkey [const char*] key to find.
768 ** @return [void*] value associated with key
769 ** @error NULL if key not found in table.
770 **
771 ** @release 6.4.0
772 ** @@
773 ******************************************************************************/
774
ajTableFetchmodC(const AjPTable table,const char * txtkey)775 void* ajTableFetchmodC(const AjPTable table, const char* txtkey)
776 {
777 ajulong i = 0UL;
778
779 AjPTableNode node = NULL;
780
781 if(!table)
782 return NULL;
783
784 if(!txtkey)
785 return NULL;
786
787 if(table->Type == ajETableTypeStr)
788 {
789 ajStrAssignC(&tableTmpkeyStr, txtkey);
790 return ajTableFetchmodS(table, tableTmpkeyStr);
791 }
792
793 if(table->Type != ajETableTypeChar)
794 ajFatal("ajTableFetchmodC called for %s table", tableType(table));
795
796 i = (*table->Fhash)(txtkey, table->Size);
797
798 for(node = table->Buckets[i]; node; node = node->Link)
799 if((*table->Fcmp)(txtkey, node->Key) == 0)
800 break;
801
802 return node ? node->Value : NULL;
803 }
804
805
806
807
808 /* @func ajTableFetchmodS *****************************************************
809 **
810 ** returns the value associated with key in table, or null
811 ** if table does not hold key.
812 **
813 ** @param [r] table [const AjPTable] table to search
814 ** @param [r] key [const AjPStr] key to find.
815 ** @return [void*] value associated with key
816 ** @error NULL if key not found in table.
817 **
818 ** @release 6.4.0
819 ** @@
820 ******************************************************************************/
821
ajTableFetchmodS(const AjPTable table,const AjPStr key)822 void* ajTableFetchmodS(const AjPTable table, const AjPStr key)
823 {
824 ajulong i = 0UL;
825
826 AjPTableNode node = NULL;
827
828 if(!table)
829 return NULL;
830
831 if(!key)
832 return NULL;
833
834 if(table->Type == ajETableTypeChar)
835 return ajTableFetchmodC(table, MAJSTRGETPTR(key));
836
837 if(table->Type != ajETableTypeStr)
838 ajFatal("ajTableFetchmodS called for %s table", tableType(table));
839
840 i = (*table->Fhash)(key, table->Size);
841
842 for(node = table->Buckets[i]; node; node = node->Link)
843 if((*table->Fcmp)(key, node->Key) == 0)
844 break;
845
846 return node ? node->Value : NULL;
847 }
848
849
850
851
852 /* @func ajTableFetchmodV *****************************************************
853 **
854 ** Returns the value associated with key in table, or null
855 ** if table does not hold key.
856 **
857 ** @param [r] table [const AjPTable] table to search
858 ** @param [r] key [const void*] key to find.
859 ** @return [void*] value associated with key
860 ** @error NULL if key not found in table.
861 **
862 ** @release 6.4.0
863 ** @@
864 ******************************************************************************/
865
ajTableFetchmodV(const AjPTable table,const void * key)866 void* ajTableFetchmodV(const AjPTable table, const void* key)
867 {
868 ajulong i = 0UL;
869
870 AjPTableNode node = NULL;
871
872 if(!table)
873 return NULL;
874
875 if(!key)
876 return NULL;
877
878 i = (*table->Fhash)(key, table->Size);
879
880 for(node = table->Buckets[i]; node; node = node->Link)
881 if((*table->Fcmp)(key, node->Key) == 0)
882 break;
883
884 return node ? node->Value : NULL;
885 }
886
887
888
889
890 /* @func ajTableFetchmodTraceV ************************************************
891 **
892 ** Returns the value associated with key in table, or null
893 ** if table does not hold key.
894 **
895 ** Trace internals with debug calls.
896 **
897 ** @param [r] table [const AjPTable] table to search
898 ** @param [r] key [const void*] key to find.
899 ** @return [void*] value associated with key
900 ** @error NULL if key not found in table.
901 **
902 ** @release 6.4.0
903 ** @@
904 ******************************************************************************/
905
ajTableFetchmodTraceV(const AjPTable table,const void * key)906 void* ajTableFetchmodTraceV(const AjPTable table, const void* key)
907 {
908 ajulong i = 0UL;
909 ajulong j = 0UL;
910
911 AjPTableNode node = NULL;
912
913 if(!table)
914 return NULL;
915
916 if(!key)
917 return NULL;
918
919 ajDebug("ajTableFetchmodTraceV length %Lu key %x (%Lu)\n",
920 table->Length, key, key);
921
922 i = (*table->Fhash)(key, table->Size);
923
924 ajDebug("...hash to bucket %Lu\n", i);
925
926 for(node = table->Buckets[i]; node; node = node->Link)
927 {
928 if((*table->Fcmp)(key, node->Key) == 0)
929 break;
930 j++;
931 }
932
933 if(node)
934 {
935 ajDebug("...tested %Lu keys found %x (%Lu)\n",
936 j, node->Value, node->Value);
937 }
938 else
939 ajDebug("...tested %Lu keys no match\n", j);
940
941 return node ? node->Value : NULL;
942 }
943
944
945
946
947 /* @func ajTableGetLength *****************************************************
948 **
949 ** returns the number of key-value pairs in table.
950 **
951 ** @param [r] table [const AjPTable] Table to be applied.
952 ** @return [ajulong] number of key-value pairs.
953 **
954 ** @release 5.0.0
955 ** @@
956 ******************************************************************************/
957
ajTableGetLength(const AjPTable table)958 ajulong ajTableGetLength(const AjPTable table)
959 {
960 if(!table)
961 return 0UL;
962
963 return table->Length;
964 }
965
966
967
968
969 /* @func ajTableGetSize *******************************************************
970 **
971 ** returns the size of the hash array in a table.
972 **
973 ** @param [r] table [const AjPTable] Table to be applied.
974 ** @return [ajulong] number of hash array positions
975 **
976 ** @release 6.4.0
977 ** @@
978 ******************************************************************************/
979
ajTableGetSize(const AjPTable table)980 ajulong ajTableGetSize(const AjPTable table)
981 {
982 if(!table)
983 return 0UL;
984
985 return table->Size;
986 }
987
988
989
990
991 /* @func ajTableMatchC ********************************************************
992 **
993 ** Returns true if the key is found in the table
994 **
995 ** Used in place of ajTableFetchS where the value may be NULL
996 **
997 ** @param [r] table [const AjPTable] table to search
998 ** @param [r] txtkey [const char*] key to find.
999 ** @return [AjBool] True if key was found[
1000 **
1001 ** @release 6.4.0
1002 ** @@
1003 ******************************************************************************/
1004
ajTableMatchC(const AjPTable table,const char * txtkey)1005 AjBool ajTableMatchC(const AjPTable table, const char* txtkey)
1006 {
1007 ajulong i = 0UL;
1008
1009 AjPTableNode node = NULL;
1010
1011 if(!table)
1012 return ajFalse;
1013
1014 if(!txtkey)
1015 return ajFalse;
1016
1017 if(table->Type == ajETableTypeStr)
1018 {
1019 ajStrAssignC(&tableTmpkeyStr, txtkey);
1020 return ajTableMatchS(table, tableTmpkeyStr);
1021 }
1022
1023 if(table->Type != ajETableTypeChar)
1024 ajFatal("ajTableMatchC called for %s table", tableType(table));
1025
1026 i = (*table->Fhash)(txtkey, table->Size);
1027
1028 for(node = table->Buckets[i]; node; node = node->Link)
1029 if((*table->Fcmp)(txtkey, node->Key) == 0)
1030 break;
1031
1032 return node ? ajTrue : ajFalse;
1033 }
1034
1035
1036
1037
1038 /* @func ajTableMatchS ********************************************************
1039 **
1040 ** Returns true if the key is found in the table
1041 **
1042 ** Used in place of ajTableFetchS where the value may be NULL
1043 **
1044 ** @param [r] table [const AjPTable] table to search
1045 ** @param [r] key [const AjPStr] key to find.
1046 ** @return [AjBool] True if key was found
1047 **
1048 ** @release 6.4.0
1049 ** @@
1050 ******************************************************************************/
1051
ajTableMatchS(const AjPTable table,const AjPStr key)1052 AjBool ajTableMatchS(const AjPTable table, const AjPStr key)
1053 {
1054 ajulong i = 0UL;
1055
1056 AjPTableNode node = NULL;
1057
1058 if(!table)
1059 return ajFalse;
1060
1061 if(!key)
1062 return ajFalse;
1063
1064 if(table->Type == ajETableTypeChar)
1065 return ajTableMatchC(table, MAJSTRGETPTR(key));
1066
1067 if(table->Type != ajETableTypeStr)
1068 ajFatal("ajTableMatchS called for %s table", tableType(table));
1069
1070 i = (*table->Fhash)(key, table->Size);
1071
1072 for(node = table->Buckets[i]; node; node = node->Link)
1073 if((*table->Fcmp)(key, node->Key) == 0)
1074 break;
1075
1076 return node ? ajTrue : ajFalse;
1077 }
1078
1079
1080
1081
1082 /* @func ajTableMatchV ********************************************************
1083 **
1084 ** Returns true if the key is found in the table
1085 **
1086 ** Used in place of ajTableFetchS where the value may be NULL
1087 **
1088 ** @param [r] table [const AjPTable] table to search
1089 ** @param [r] key [const void*] key to find.
1090 ** @return [AjBool] True if key was found
1091 **
1092 ** @release 6.4.0
1093 ** @@
1094 ******************************************************************************/
1095
ajTableMatchV(const AjPTable table,const void * key)1096 AjBool ajTableMatchV(const AjPTable table, const void* key)
1097 {
1098 ajulong i = 0UL;
1099
1100 AjPTableNode node = NULL;
1101
1102 if(!table)
1103 return ajFalse;
1104
1105 if(!key)
1106 return ajFalse;
1107
1108 i = (*table->Fhash)(key, table->Size);
1109
1110 for(node = table->Buckets[i]; node; node = node->Link)
1111 if((*table->Fcmp)(key, node->Key) == 0)
1112 break;
1113
1114 return node ? ajTrue : ajFalse;
1115 }
1116
1117
1118
1119
1120 /* @func ajTableToarrayKeys ***************************************************
1121 **
1122 ** creates two N+1 element arrays that holds the N keys
1123 ** in table in an unspecified order and returns the number of elements.
1124 ** The final element of the array is NULL.
1125 **
1126 ** @param [r] table [const AjPTable] Table
1127 ** @param [w] keyarray [void***] NULL terminated array of keys.
1128 ** @return [ajulong] size of array returned
1129 **
1130 ** @release 6.2.0
1131 ** @@
1132 ******************************************************************************/
1133
ajTableToarrayKeys(const AjPTable table,void *** keyarray)1134 ajulong ajTableToarrayKeys(const AjPTable table,
1135 void*** keyarray)
1136 {
1137 ajulong i = 0UL;
1138 ajulong j = 0UL;
1139
1140 AjPTableNode node = NULL;
1141
1142 if(*keyarray)
1143 AJFREE(*keyarray);
1144
1145 if(!table)
1146 return 0UL;
1147
1148 *keyarray = AJALLOC((size_t)(table->Length + 1) * sizeof(keyarray));
1149
1150 for(i = 0UL; i < table->Size; i++)
1151 for(node = table->Buckets[i]; node; node = node->Link)
1152 (*keyarray)[j++] = node->Key;
1153
1154 (*keyarray)[j] = NULL;
1155
1156 return table->Length;
1157 }
1158
1159
1160
1161
1162 /* @func ajTableToarrayKeysValues *********************************************
1163 **
1164 ** creates two N+1 element arrays that holds the N key-value pairs
1165 ** in table in an unspecified order and returns the number of elements.
1166 ** The final element of the array is NULL.
1167 **
1168 ** @param [r] table [const AjPTable] Table
1169 ** @param [w] keyarray [void***] NULL terminated array of keys.
1170 ** @param [w] valarray [void***] NULL terminated array of values.
1171 ** @return [ajulong] size of arrays returned
1172 **
1173 ** @release 6.2.0
1174 ** @@
1175 ******************************************************************************/
1176
ajTableToarrayKeysValues(const AjPTable table,void *** keyarray,void *** valarray)1177 ajulong ajTableToarrayKeysValues(const AjPTable table,
1178 void*** keyarray, void*** valarray)
1179 {
1180 ajulong i = 0UL;
1181 ajulong j = 0UL;
1182
1183 AjPTableNode node = NULL;
1184
1185 if(*keyarray)
1186 AJFREE(*keyarray);
1187
1188 if(*valarray)
1189 AJFREE(*valarray);
1190
1191 if(!table)
1192 return 0UL;
1193
1194 *keyarray = AJALLOC((size_t)(table->Length + 1) * sizeof(keyarray));
1195 *valarray = AJALLOC((size_t)(table->Length + 1) * sizeof(valarray));
1196
1197 for(i = 0UL; i < table->Size; i++)
1198 for(node = table->Buckets[i]; node; node = node->Link)
1199 {
1200 (*keyarray)[j] = node->Key;
1201 (*valarray)[j++] = node->Value;
1202 }
1203
1204 (*keyarray)[j] = NULL;
1205 (*valarray)[j] = NULL;
1206
1207 return table->Length;
1208 }
1209
1210
1211
1212
1213 /* @func ajTableToarrayValues *************************************************
1214 **
1215 ** creates two N+1 element arrays that holds the N values
1216 ** in table in an unspecified order and returns the number of elements.
1217 ** The final element of the array is NULL.
1218 **
1219 ** @param [r] table [const AjPTable] Table
1220 ** @param [w] valarray [void***] NULL terminated array of values.
1221 ** @return [ajulong] size of array returned
1222 **
1223 ** @release 6.2.0
1224 ** @@
1225 ******************************************************************************/
1226
ajTableToarrayValues(const AjPTable table,void *** valarray)1227 ajulong ajTableToarrayValues(const AjPTable table,
1228 void*** valarray)
1229 {
1230 ajulong i = 0UL;
1231 ajulong j = 0UL;
1232
1233 AjPTableNode node = NULL;
1234
1235 if(*valarray)
1236 AJFREE(*valarray);
1237
1238 if(!table)
1239 return 0;
1240
1241 *valarray = AJALLOC((size_t)(table->Length + 1) * sizeof(valarray));
1242
1243 for(i = 0UL; i < table->Size; i++)
1244 for(node = table->Buckets[i]; node; node = node->Link)
1245 {
1246 (*valarray)[j++] = node->Value;
1247 }
1248
1249 (*valarray)[j] = NULL;
1250
1251 return table->Length;
1252 }
1253
1254
1255
1256
1257 /* @section Trace functions ***************************************************
1258 **
1259 ** @fdata [AjPTable]
1260 **
1261 ** @nam3rule Trace Trace contents
1262 ** @argrule Trace table [const AjPTable] Hash table
1263 ** @valrule * [void]
1264 **
1265 ** @fcategory misc
1266 **
1267 ******************************************************************************/
1268
1269
1270
1271
1272 /* @func ajTableTrace *********************************************************
1273 **
1274 ** Writes debug messages to trace the contents of a table.
1275 **
1276 ** @param [r] table [const AjPTable] Table
1277 ** @return [void]
1278 **
1279 ** @release 1.0.0
1280 ** @@
1281 ******************************************************************************/
1282
ajTableTrace(const AjPTable table)1283 void ajTableTrace(const AjPTable table)
1284 {
1285 ajulong i = 0UL;
1286 ajulong j = 0UL;
1287 ajulong k = 0UL;
1288
1289 AjPTableNode node = NULL;
1290
1291 if(!table)
1292 return;
1293
1294 ajDebug("table trace: ");
1295 ajDebug(" length: %Lu", table->Length);
1296 ajDebug(" size: %Lu", table->Size);
1297 ajDebug(" timestamp: %u", table->Timestamp);
1298
1299 for(i = 0UL; i < table->Size; i++)
1300 if(table->Buckets[i])
1301 {
1302 j = 0UL;
1303
1304 for(node = table->Buckets[i]; node; node = node->Link)
1305 j++;
1306
1307 k += j;
1308 }
1309
1310 ajDebug(" links: %Lu\n", k);
1311
1312 return;
1313 }
1314
1315
1316
1317
1318 /* @section Adding values *****************************************************
1319 **
1320 ** @fdata [AjPTable]
1321 **
1322 ** @nam3rule Put Add new key and value
1323 ** @nam4rule PutClean Add new key and value, removing any existing key and value
1324 ** @nam3rule Remove Remove one key and value
1325 ** @nam4rule RemoveKey Remove one key and value, return key for deletion
1326 ** @nam4rule Trace Debug report on table internals
1327 **
1328 ** @argrule * table [AjPTable] Hash table
1329 ** @argrule Put key [void*] Key
1330 ** @argrule Put value [void*] Value
1331 ** @argrule Remove key [const void*] Key
1332 ** @argrule RemoveKey truekey [void**] Removed key pointer - ready to be freed
1333 ** @argrule Clean keydel [void function] key destructor function
1334 ** @argrule Clean valdel [void function] value destructor function
1335 **
1336 ** @valrule * [void*] Previous value for key, or NULL
1337 ** @valrule *Clean [AjBool] Previous value found and destroyed
1338 **
1339 ** @fcategory modify
1340 ******************************************************************************/
1341
1342
1343
1344
1345 /* @func ajTablePut ***********************************************************
1346 **
1347 ** change the value associated with key in table to value and returns
1348 ** the previous value, or adds key and value if table does not hold key,
1349 ** and returns null.
1350 **
1351 ** @param [u] table [AjPTable] Table to add to
1352 ** @param [o] key [void*] key
1353 ** @param [u] value [void*] value of key
1354 ** @return [void*] previous value if key exists, NULL if not.
1355 **
1356 ** @release 1.0.0
1357 ** @@
1358 ******************************************************************************/
1359
ajTablePut(AjPTable table,void * key,void * value)1360 void* ajTablePut(AjPTable table, void* key, void* value)
1361 {
1362 ajulong i = 0UL;
1363 ajulong minsize = 0UL;
1364
1365 AjPTableNode node = NULL;
1366
1367 void* prev = NULL;
1368
1369 if(!table)
1370 return NULL;
1371
1372 if(!key)
1373 return NULL;
1374
1375 minsize = table->Length / 8UL;
1376 if(table->Size < minsize)
1377 ajTableResizeCount(table, 6*minsize);
1378
1379 i = (*table->Fhash)(key, table->Size);
1380
1381 for(node = table->Buckets[i]; node; node = node->Link)
1382 if((*table->Fcmp)(key, node->Key) == 0)
1383 break;
1384
1385 if(node == NULL)
1386 {
1387 if(tableFreeNext)
1388 node = tableFreeSet[--tableFreeNext];
1389 else
1390 AJNEW0(node);
1391
1392 node->Key = key;
1393 node->Link = table->Buckets[i];
1394 table->Buckets[i] = node;
1395 table->Length++;
1396 prev = NULL;
1397 }
1398 else
1399 {
1400 if(table->Fkeydel)
1401 {
1402 (*table->Fkeydel)(&node->Key);
1403 node->Key = key;
1404 }
1405 prev = node->Value;
1406 }
1407
1408 node->Value = value;
1409 table->Timestamp++;
1410
1411 return prev;
1412 }
1413
1414
1415
1416
1417 /* @func ajTablePutClean ******************************************************
1418 **
1419 ** change the value associated with key in table to value and returns
1420 ** the previous value, applying destructors to the given key and value,
1421 ** or adds key and value if table does not hold key,
1422 ** and returns null.
1423 **
1424 **
1425 ** @param [u] table [AjPTable] Table to add to
1426 ** @param [o] key [void*] key
1427 ** @param [u] value [void*] value of key
1428 ** @param [f] keydel [void function] key destructor
1429 ** @param [f] valdel [void function] value destructor
1430 ** @return [AjBool] previous value was found and deleted.
1431 **
1432 ** @release 6.4.0
1433 ** @@
1434 ******************************************************************************/
1435
ajTablePutClean(AjPTable table,void * key,void * value,void (* keydel)(void ** Pkey),void (* valdel)(void ** Pvalue))1436 AjBool ajTablePutClean(AjPTable table, void* key, void* value,
1437 void (*keydel)(void** Pkey),
1438 void (*valdel)(void** Pvalue))
1439 {
1440 ajulong i = 0UL;
1441 ajulong minsize = 0UL;
1442
1443 AjPTableNode node = NULL;
1444
1445 AjBool result = ajFalse;
1446
1447 if(!table)
1448 return ajFalse;
1449
1450 if(!key)
1451 return ajFalse;
1452
1453 minsize = table->Length / 8UL;
1454 if(table->Size < minsize)
1455 ajTableResizeCount(table, 6*minsize);
1456
1457 i = (*table->Fhash)(key, table->Size);
1458
1459 for(node = table->Buckets[i]; node; node = node->Link)
1460 if((*table->Fcmp)(key, node->Key) == 0)
1461 break;
1462
1463 if(node == NULL)
1464 {
1465 if(tableFreeNext)
1466 node = tableFreeSet[--tableFreeNext];
1467 else
1468 AJNEW0(node);
1469
1470 node->Key = key;
1471 node->Link = table->Buckets[i];
1472 table->Buckets[i] = node;
1473 table->Length++;
1474 }
1475 else
1476 {
1477 /*
1478 {
1479 AjPStr tmpkey = NULL;
1480 AjPStr newkey = NULL;
1481 tableStrFromKey(table, node->Key, &tmpkey);
1482 tableStrFromKey(table, key, &newkey);
1483 ajDebug("ajTablePutClean duplicate key %x (%S) == %x (%S)\n",
1484 node->Key, tmpkey, key, newkey);
1485 ajStrDel(&tmpkey);
1486 ajStrDel(&newkey);
1487 }
1488 */
1489 if (keydel)
1490 (*keydel) (&node->Key);
1491 else if (table->Fkeydel)
1492 (*table->Fkeydel) (&node->Key);
1493
1494 node->Key = key;
1495
1496 if (valdel)
1497 (*valdel) (&node->Value);
1498 else if (table->Fvaldel)
1499 (*table->Fvaldel) (&node->Value);
1500
1501 result = ajTrue;
1502 }
1503
1504 node->Value = value;
1505 table->Timestamp++;
1506
1507 return result;
1508 }
1509
1510
1511
1512
1513 /* @funcstatic tableStrFromKey ************************************************
1514 **
1515 ** Tries to print the value of a key by checking the internal hash functions
1516 ** against the hash function for the table to identify a known key type
1517 **
1518 ** Returns a string describing the key type and its value
1519 **
1520 ** @param [r] table [const AjPTable] Table object
1521 ** @param [r] key [const void*] Key
1522 ** @param [w] Pstr [AjPStr*] Output string
1523 **
1524 ** @return [void]
1525 **
1526 ** @release 6.4.0
1527 ******************************************************************************/
1528
tableStrFromKey(const AjPTable table,const void * key,AjPStr * Pstr)1529 static void tableStrFromKey(const AjPTable table, const void* key,
1530 AjPStr* Pstr)
1531 {
1532 if(table->Fhash == &ajTablecharHash)
1533 {
1534 ajFmtPrintS(Pstr, "key '%s' (char*)",
1535 (const char*) key);
1536 }
1537 else if(table->Fhash == &ajTableintHash)
1538 {
1539 ajFmtPrintS(Pstr, "key '%d' (int)",
1540 *((const ajint*) key));
1541 }
1542 else if(table->Fhash == &ajTablelongHash)
1543 {
1544 ajFmtPrintS(Pstr, "key '%Ld' (int)",
1545 *((const ajlong*) key));
1546 }
1547 else if(table->Fhash == &ajTablestrHash)
1548 {
1549 ajFmtPrintS(Pstr, "key '%S' (string)",
1550 (const AjPStr) key);
1551 }
1552 else if(table->Fhash == &ajTableuintHash)
1553 {
1554 ajFmtPrintS(Pstr, "key '%u' (unsigned int)",
1555 *((const ajuint*) key));
1556 }
1557 else if(table->Fhash == &ajTableulongHash)
1558 {
1559 ajFmtPrintS(Pstr, "key '%Lu' (unsigned long)",
1560 *((const ajulong*) key));
1561 }
1562 else
1563 {
1564 ajFmtPrintS(Pstr, "key '%x' (unknown)",
1565 (const void*) key);
1566 }
1567
1568 return;
1569 }
1570
1571
1572
1573
1574 /* @func ajTablePutTrace ******************************************************
1575 **
1576 ** change the value associated with key in table to value and returns
1577 ** the previous value, or adds key and value if table does not hold key,
1578 ** and returns null. Trace the internals as the value is inserted.
1579 **
1580 ** @param [u] table [AjPTable] Table to add to
1581 ** @param [o] key [void*] key
1582 ** @param [u] value [void*] value of key
1583 ** @return [void*] previous value if key exists, NULL if not.
1584 **
1585 ** @release 6.4.0
1586 ** @@
1587 ******************************************************************************/
1588
ajTablePutTrace(AjPTable table,void * key,void * value)1589 void* ajTablePutTrace(AjPTable table, void* key, void* value)
1590 {
1591 ajulong i = 0UL;
1592 ajulong j = 0UL;
1593 ajulong minsize = 0UL;
1594
1595 AjPTableNode node = NULL;
1596
1597 void* prev = NULL;
1598
1599 if(!table)
1600 return NULL;
1601
1602 if(!key)
1603 return NULL;
1604
1605 if(!value)
1606 return NULL;
1607
1608 minsize = table->Length / 6UL;
1609 if(table->Size < minsize)
1610 ajTableResizeCount(table, 4 * table->Length);
1611
1612 ajDebug("ajTablePut length %Lu key %x (%Lu) value %x (%Lu)\n",
1613 table->Length, key, key, value, value);
1614
1615 i = (*table->Fhash)(key, table->Size);
1616
1617 ajDebug("...hash to bucket %Lu\n", i);
1618
1619 for(node = table->Buckets[i]; node; node = node->Link)
1620 {
1621 if((*table->Fcmp)(key, node->Key) == 0)
1622 break;
1623 j++;
1624 }
1625
1626 ajDebug("...tested %Lu keys\n", j);
1627
1628 if(node == NULL)
1629 {
1630 if(tableFreeNext)
1631 node = tableFreeSet[--tableFreeNext];
1632 else
1633 AJNEW0(node);
1634
1635 node->Key = key;
1636 node->Link = table->Buckets[i];
1637 table->Buckets[i] = node;
1638 table->Length++;
1639 prev = NULL;
1640 }
1641 else
1642 {
1643 ajDebug("...existing value %x %Lu\n", node->Value, node->Value);
1644 prev = node->Value;
1645 }
1646
1647 node->Value = value;
1648 table->Timestamp++;
1649
1650 return prev;
1651 }
1652
1653
1654
1655
1656 /* @func ajTableRemove ********************************************************
1657 **
1658 ** Removes the key-value pair from table and returns the removed
1659 ** value. If table does not hold key, ajTableRemove has no effect
1660 ** and returns null.
1661 **
1662 ** @param [u] table [AjPTable] Table
1663 ** @param [r] key [const void*] key to be removed
1664 ** @return [void*] removed value.
1665 ** @error NULL if key not found.
1666 **
1667 ** @release 1.0.0
1668 ** @@
1669 ******************************************************************************/
1670
ajTableRemove(AjPTable table,const void * key)1671 void* ajTableRemove(AjPTable table, const void* key)
1672 {
1673 ajulong i = 0UL;
1674
1675 AjPTableNode* Pnode = NULL;
1676
1677 if(!table)
1678 return NULL;
1679
1680 if(!key)
1681 return NULL;
1682
1683 {
1684 AjPStr newkey = NULL;
1685 tableStrFromKey(table, key, &newkey);
1686 /*ajDebug("ajTableRemove key %x (%S)\n", key, newkey);*/
1687 ajStrDel(&newkey);
1688 }
1689
1690 table->Timestamp++;
1691 i = (*table->Fhash)(key, table->Size);
1692
1693 for(Pnode = &table->Buckets[i]; *Pnode; Pnode = &(*Pnode)->Link)
1694 if((*table->Fcmp)(key, (*Pnode)->Key) == 0)
1695 {
1696 AjPTableNode node = *Pnode;
1697 void* value = node->Value;
1698 *Pnode = node->Link;
1699
1700 if(table->Fkeydel)
1701 {
1702 AjPStr tmpkey = NULL;
1703 AjPStr newkey = NULL;
1704 tableStrFromKey(table, node->Key, &tmpkey);
1705 tableStrFromKey(table, key, &newkey);
1706 ajDebug("ajTableRemove key %x (%S) matched key %x (%S)\n",
1707 key, newkey, node->Key, tmpkey);
1708 (*table->Fkeydel)(&node->Key);
1709 ajStrDel(&tmpkey);
1710 ajStrDel(&newkey);
1711 }
1712
1713 if(tableFreeNext >= tableFreeMax)
1714 AJFREE(node);
1715 else
1716 tableFreeSet[tableFreeNext++] = node;
1717
1718 table->Length--;
1719
1720 return value;
1721 }
1722
1723 return NULL;
1724 }
1725
1726
1727
1728
1729 /* @func ajTableRemoveKey *****************************************************
1730 **
1731 ** Removes the key-value pair from table and returns the removed
1732 ** value. If table does not hold key, ajTableRemove has no effect
1733 ** and returns null.
1734 **
1735 ** @param [u] table [AjPTable] Table
1736 ** @param [r] key [const void*] key to be removed
1737 ** @param [w] truekey [void**] true internal key returned, now owned by caller
1738 ** @return [void*] removed value.
1739 ** @error NULL if key not found.
1740 **
1741 ** @release 5.0.0
1742 ** @@
1743 ******************************************************************************/
1744
ajTableRemoveKey(AjPTable table,const void * key,void ** truekey)1745 void* ajTableRemoveKey(AjPTable table, const void* key, void** truekey)
1746 {
1747 ajulong i = 0UL;
1748
1749 AjPTableNode* Pnode = NULL;
1750
1751 if(!table)
1752 return NULL;
1753
1754 if(!key)
1755 return NULL;
1756
1757 table->Timestamp++;
1758 i = (*table->Fhash)(key, table->Size);
1759
1760 for(Pnode = &table->Buckets[i]; *Pnode; Pnode = &(*Pnode)->Link)
1761 if((*table->Fcmp)(key, (*Pnode)->Key) == 0)
1762 {
1763 AjPTableNode node = *Pnode;
1764 void* value = node->Value;
1765 *truekey = node->Key;
1766 *Pnode = node->Link;
1767
1768 if(tableFreeNext >= tableFreeMax)
1769 AJFREE(node);
1770 else
1771 tableFreeSet[tableFreeNext++] = node;
1772
1773 table->Length--;
1774
1775 return value;
1776 }
1777
1778 return NULL;
1779 }
1780
1781
1782
1783
1784 /* @section Map function to each value ****************************************
1785 **
1786 ** @fdata [AjPTable]
1787 **
1788 ** @nam3rule Map Map function to each key value pair
1789 ** @nam4rule MapDel Map function to delete each key value pair
1790 **
1791 ** @argrule Map table [AjPTable] Hash table
1792 ** @argrule Map apply [void function] function to be applied
1793 ** @argrule Map cl [void*] Standard. Usually NULL. To be passed to apply
1794 **
1795 ** @valrule * [void]
1796 **
1797 ** @fcategory modify
1798 ******************************************************************************/
1799
1800
1801
1802
1803 /* @func ajTableMap ***********************************************************
1804 **
1805 ** calls function 'apply' for each key-value in table
1806 ** in an unspecified order. The table keys should not be modified by
1807 ** function 'apply' although values can be updated.
1808 **
1809 ** See ajTableMapDel for a function that can delete.
1810 **
1811 ** Note: because of the properties of C it is difficult to check these
1812 ** are being called correctly. This is because the apply function
1813 ** uses void* arguments.
1814 **
1815 ** @param [u] table [AjPTable] Table.
1816 ** @param [f] apply [void function] function to be applied
1817 ** @param [u] cl [void*] Standard. Usually NULL. To be passed to apply
1818 ** @return [void]
1819 **
1820 ** @release 1.0.0
1821 ** @@
1822 ******************************************************************************/
1823
ajTableMap(AjPTable table,void (* apply)(const void * key,void ** Pvalue,void * cl),void * cl)1824 void ajTableMap(AjPTable table,
1825 void (*apply)(const void* key, void** Pvalue, void* cl),
1826 void* cl)
1827 {
1828 ajulong i = 0UL;
1829 ajuint stamp = 0U;
1830
1831 AjPTableNode node = NULL;
1832
1833 if(!table)
1834 return;
1835
1836 stamp = table->Timestamp;
1837
1838 for(i = 0UL; i < table->Size; i++)
1839 for(node = table->Buckets[i]; node; node = node->Link)
1840 {
1841 (*apply)(node->Key, &node->Value, cl);
1842 assert(table->Timestamp == stamp);
1843 }
1844
1845 return;
1846 }
1847
1848
1849
1850
1851 /* @func ajTableMapDel ********************************************************
1852 **
1853 ** calls function 'apply' for each key-value in table
1854 ** in an unspecified order.
1855 **
1856 ** Keys in the table can be deleted - for example a function to delete
1857 ** a table entry. See ajTableMap for a function that is read-only
1858 **
1859 ** @param [u] table [AjPTable] Table.
1860 ** @param [f] apply [void function] function to be applied
1861 ** @param [u] cl [void*] Standard. Usually NULL. To be passed to apply
1862 ** @return [void]
1863 **
1864 ** @release 2.9.0
1865 ** @@
1866 ******************************************************************************/
1867
ajTableMapDel(AjPTable table,void (* apply)(void ** Pkey,void ** Pvalue,void * cl),void * cl)1868 void ajTableMapDel(AjPTable table,
1869 void (*apply)(void** Pkey, void** Pvalue, void* cl),
1870 void* cl)
1871 {
1872 ajulong i = 0UL;
1873 ajuint stamp = 0U;
1874
1875 AjPTableNode node1 = NULL;
1876 AjPTableNode node2 = NULL;
1877
1878 if(!table)
1879 return;
1880
1881 stamp = table->Timestamp;
1882
1883 for(i = 0UL; i < table->Size; i++)
1884 {
1885 for(node1 = table->Buckets[i]; node1; node1 = node2)
1886 {
1887 node2 = node1->Link;
1888
1889 (*apply)(&node1->Key, &node1->Value, cl);
1890 assert(table->Timestamp == stamp);
1891 table->Length--;
1892 if(tableFreeNext >= tableFreeMax)
1893 tableFreeSetExpand();
1894 if(tableFreeNext >= tableFreeMax)
1895 AJFREE(node1);
1896 else
1897 tableFreeSet[tableFreeNext++] = node1;
1898 }
1899 table->Buckets[i] = NULL;
1900 }
1901
1902 return;
1903 }
1904
1905
1906
1907
1908 /* @section Modify ************************************************************
1909 **
1910 ** @fdata [AjPTable]
1911 **
1912 ** Updates values from a hash table
1913 **
1914 ** @nam3rule Clear Reset table
1915 ** @nam4rule ClearDelete Reset table and delete keys and values
1916 ** @nam3rule Resize Resize table
1917 ** @nam4rule ResizeCount Resize table to fit a given number of entries
1918 ** @nam4rule ResizeHashsize Resize table to a minimum hash size
1919 ** @nam3rule Set Set a table property
1920 ** @nam4rule SetDestroy Set key and value destructors
1921 ** @nam4rule SetDestroyboth Set value destructor same as key
1922 ** @nam4rule SetDestroykey Set key destructor
1923 ** @nam4rule SetDestroyvalue Set value destructor
1924 ** @nam3rule Settype Reset table using a new key type
1925 ** @nam4rule SettypeChar C character string type
1926 ** @nam4rule SettypeDefault Default key type
1927 ** @nam4rule SettypeInt Integer key type
1928 ** @nam4rule SettypeLong Long integer key type
1929 ** @nam4rule SettypeString String key type
1930 ** @nam4rule SettypeUint Unsigned integer key type
1931 ** @nam4rule SettypeUlong Unsigned long integer key type
1932 ** @nam4rule SettypeUser User-defined key type
1933 ** @nam5rule Case Case-insensitive string comparison
1934 **
1935 ** @argrule * table [AjPTable] Hash table
1936 ** @argrule ResizeCount size [ajulong] Expected number of key-value pairs
1937 ** @argrule ResizeHashsize hashsize [ajulong] Required minimum hash array size
1938 ** @argrule SettypeUser cmp [ajint function] Comparison function returning
1939 ** +1, zero or -1
1940 ** @argrule SettypeUser hash [ajulong function] Hash function for keys
1941 ** @argrule Destroy keydel [void function] key destructor function
1942 ** @argrule Destroykey keydel [void function] key destructor function
1943 ** @argrule Destroy valdel [void function] value destructor function
1944 ** @argrule Destroyvalue valdel [void function] value destructor function
1945 **
1946 ** @valrule * [void]
1947 ** @fcategory modify
1948 **
1949 ******************************************************************************/
1950
1951
1952
1953
1954 /* @func ajTableClear *********************************************************
1955 **
1956 ** Clears a hash table. Does not clear keys or values.
1957 **
1958 ** @param [u] table [AjPTable] Table
1959 ** @return [void]
1960 **
1961 ** @release 6.4.0
1962 ** @@
1963 ******************************************************************************/
1964
ajTableClear(AjPTable table)1965 void ajTableClear(AjPTable table)
1966 {
1967 ajulong i = 0UL;
1968 ajulong ikeys = 0UL;
1969
1970 if(!table)
1971 return;
1972
1973 /*ajDebug("ajTableClear length: %Lu size: %Lu type: %u\n",
1974 table->Length, table->Size, table->Type);*/
1975
1976 if(table->Length > 0)
1977 {
1978 AjPTableNode node1 = NULL;
1979 AjPTableNode node2 = NULL;
1980
1981 for(i = 0UL; i < table->Size; i++)
1982 {
1983 ikeys = 0UL;
1984 for(node1 = table->Buckets[i]; node1; node1 = node2)
1985 {
1986 ikeys++;
1987
1988 node2 = node1->Link;
1989
1990 if(tableFreeNext >= tableFreeMax)
1991 tableFreeSetExpand();
1992 if(tableFreeNext >= tableFreeMax)
1993 AJFREE(node1);
1994 else
1995 tableFreeSet[tableFreeNext++] = node1;
1996 }
1997 table->Buckets[i] = NULL;
1998 }
1999 }
2000
2001 table->Length = 0UL;
2002
2003 return;
2004 }
2005
2006
2007
2008
2009 /* @func ajTableClearDelete ***************************************************
2010 **
2011 ** Clears a hash table. Deletes all keys or values.
2012 **
2013 ** @param [u] table [AjPTable] Table
2014 ** @return [void]
2015 **
2016 ** @release 6.4.0
2017 ** @@
2018 ******************************************************************************/
2019
ajTableClearDelete(AjPTable table)2020 void ajTableClearDelete(AjPTable table)
2021 {
2022 ajulong i = 0UL;
2023
2024 AjPTableNode node1 = NULL;
2025 AjPTableNode node2 = NULL;
2026
2027 if(!table)
2028 return;
2029
2030 if(table->Length > 0)
2031 {
2032
2033 for(i = 0UL; i < table->Size; i++)
2034 {
2035 for(node1 = table->Buckets[i]; node1; node1 = node2)
2036 {
2037 node2 = node1->Link;
2038
2039 if(table->Fkeydel)
2040 (*table->Fkeydel)(&node1->Key);
2041
2042 if(table->Fvaldel)
2043 (*table->Fvaldel)(&node1->Value);
2044
2045 if(tableFreeNext >= tableFreeMax)
2046 tableFreeSetExpand();
2047 if(tableFreeNext >= tableFreeMax)
2048 AJFREE(node1);
2049 else
2050 tableFreeSet[tableFreeNext++] = node1;
2051 }
2052 table->Buckets[i] = NULL;
2053 }
2054 }
2055
2056 table->Length = 0UL;
2057
2058 return;
2059 }
2060
2061
2062
2063
2064 /* @func ajTableResizeCount ***************************************************
2065 **
2066 ** Resizes a hash table to a new number of expected values.
2067 **
2068 ** @param [u] table [AjPTable] Table
2069 ** @param [r] size [ajulong] Expected number of key-value pairs
2070 ** @return [void]
2071 **
2072 ** @release 6.4.0
2073 ** @@
2074 ******************************************************************************/
2075
ajTableResizeCount(AjPTable table,ajulong size)2076 void ajTableResizeCount(AjPTable table, ajulong size)
2077 {
2078 ajTableResizeHashsize(table, size/4);
2079
2080 return;
2081 }
2082
2083
2084
2085
2086 /* @func ajTableResizeHashsize ************************************************
2087 **
2088 ** Resizes a hash table to a new size.
2089 **
2090 ** @param [u] table [AjPTable] Table
2091 ** @param [r] hashsize [ajulong] Expected number of key-value pairs
2092 ** @return [void]
2093 **
2094 ** @release 6.4.0
2095 ** @@
2096 ******************************************************************************/
2097
ajTableResizeHashsize(AjPTable table,ajulong hashsize)2098 void ajTableResizeHashsize(AjPTable table, ajulong hashsize)
2099 {
2100 ajulong n = 0UL;
2101 void** keyarray = NULL;
2102 void** valarray = NULL;
2103 ajulong hint = 0UL;
2104 ajulong iprime = 0UL;
2105 ajulong ibucket = 0UL;
2106 ajulong i = 0UL;
2107 AjPTableNode node = NULL;
2108 ajulong savelength = 0UL;
2109
2110 /* largest primes just under 2**8 to 2**31 */
2111
2112 static ajulong primes[] =
2113 {
2114 3UL,
2115 7UL,
2116 13UL,
2117 31UL,
2118 61UL,
2119 127UL,
2120 251UL,
2121 509UL,
2122 1021UL,
2123 2039UL,
2124 4093UL,
2125 8191UL,
2126 16381UL,
2127 32749UL,
2128 65521UL,
2129 131071UL,
2130 262139UL,
2131 524287UL,
2132 1048573UL,
2133 2097143UL,
2134 4194301UL,
2135 8388593UL,
2136 16777213UL,
2137 33554393UL,
2138 67108859UL,
2139 134217689UL,
2140 268435399UL,
2141 536870909UL,
2142 1073741789UL,
2143 2147483647UL,
2144 UINT_MAX
2145 };
2146
2147 if(!table)
2148 return;
2149
2150 /* check the size required */
2151
2152 hint = hashsize;
2153
2154 for(i = 1; primes[i] <= hint; i++); /* else use default i=0 */
2155
2156 iprime = primes[i - 1];
2157
2158 /*ajDebug("ajTableResizeHashsize test %x entries %Lu newhashsize %Lu "
2159 "hashsize %Lu newsize %Lu\n",
2160 table, table->Length, hashsize, table->Size, iprime);*/
2161
2162 if(iprime == table->Size)
2163 return;
2164
2165 /* save the current keys and values */
2166
2167 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2168
2169 AJCRESIZE0(table->Buckets, (size_t) table->Size, (size_t) iprime);
2170 table->Size = iprime;
2171
2172 /* empty the old buckets */
2173
2174 savelength = table->Length;
2175 ajTableClear(table);
2176 table->Length = savelength;
2177
2178 /*ajDebug("ajTableResizeHashsize yes %x length %Lu nkeys %Lu hashsize %Lu\n",
2179 table, table->Length, n, table->Size);*/
2180
2181 /* repopulate the new bucket array */
2182
2183 for(i=0; i < n; i++)
2184 {
2185 ibucket = (*table->Fhash)(keyarray[i], table->Size);
2186 for(node = table->Buckets[ibucket]; node; node = node->Link)
2187 if((*table->Fcmp)(keyarray[i], node->Key) == 0)
2188 break;
2189
2190 if(node == NULL)
2191 {
2192 if(tableFreeNext)
2193 node = tableFreeSet[--tableFreeNext];
2194 else
2195 AJNEW0(node);
2196
2197 node->Key = keyarray[i];
2198 node->Link = table->Buckets[ibucket];
2199 table->Buckets[ibucket] = node;
2200 }
2201
2202 node->Value = valarray[i];
2203 }
2204
2205 AJFREE(keyarray);
2206 AJFREE(valarray);
2207 table->Timestamp++;
2208
2209 return;
2210 }
2211
2212
2213
2214
2215 /* @func ajTableSetDestroy ****************************************************
2216 **
2217 ** Sets the destructor functions for keys and values
2218 **
2219 ** @param [u] table [AjPTable] Table
2220 ** @param [fN] keydel [void function] key destructor function
2221 ** @param [fN] valdel [void function] value destructor function
2222 ** @return [void]
2223 **
2224 ** @release 6.4.0
2225 ** @@
2226 ******************************************************************************/
2227
ajTableSetDestroy(AjPTable table,void (* keydel)(void ** Pkey),void (* valdel)(void ** Pvalue))2228 void ajTableSetDestroy(AjPTable table,
2229 void (*keydel)(void** Pkey),
2230 void (*valdel)(void** Pvalue))
2231 {
2232 if(!table)
2233 return;
2234
2235 table->Fkeydel = keydel;
2236 table->Fvaldel = valdel;
2237
2238 return;
2239 }
2240
2241
2242
2243
2244 /* @func ajTableSetDestroyboth ************************************************
2245 **
2246 ** Sets the destructor functions values to be the same as for keys
2247 **
2248 ** @param [u] table [AjPTable] Table
2249 ** @return [void]
2250 **
2251 ** @release 6.4.0
2252 ** @@
2253 ******************************************************************************/
2254
ajTableSetDestroyboth(AjPTable table)2255 void ajTableSetDestroyboth(AjPTable table)
2256 {
2257 if(!table)
2258 return;
2259
2260 table->Fvaldel = table->Fkeydel;
2261
2262 return;
2263 }
2264
2265
2266
2267
2268 /* @func ajTableSetDestroykey *************************************************
2269 **
2270 ** Sets the destructor functions for keys
2271 **
2272 ** @param [u] table [AjPTable] Table
2273 ** @param [fN] keydel [void function] key destructor function
2274 ** @return [void]
2275 **
2276 ** @release 6.4.0
2277 ** @@
2278 ******************************************************************************/
2279
ajTableSetDestroykey(AjPTable table,void (* keydel)(void ** Pkey))2280 void ajTableSetDestroykey(AjPTable table,
2281 void (*keydel)(void** Pkey))
2282 {
2283 if(!table)
2284 return;
2285
2286 table->Fkeydel = keydel;
2287
2288 return;
2289 }
2290
2291
2292
2293
2294 /* @func ajTableSetDestroyvalue ***********************************************
2295 **
2296 ** Sets the destructor functions for values
2297 **
2298 ** @param [u] table [AjPTable] Table
2299 ** @param [fN] valdel [void function] value destructor function
2300 ** @return [void]
2301 **
2302 ** @release 6.4.0
2303 ** @@
2304 ******************************************************************************/
2305
ajTableSetDestroyvalue(AjPTable table,void (* valdel)(void ** Pvalue))2306 void ajTableSetDestroyvalue(AjPTable table,
2307 void (*valdel)(void** Pvalue))
2308 {
2309 if(!table)
2310 return;
2311
2312 table->Fvaldel = valdel;
2313
2314 return;
2315 }
2316
2317
2318
2319
2320 /* @func ajTableSettypeChar ***************************************************
2321 **
2322 ** Resets a hash table to use C character string keys
2323 **
2324 ** @param [u] table [AjPTable] Hash table
2325 ** @return [void]
2326 **
2327 ** @release 6.4.0
2328 ** @@
2329 ******************************************************************************/
2330
ajTableSettypeChar(AjPTable table)2331 void ajTableSettypeChar(AjPTable table)
2332 {
2333 void** keyarray = NULL;
2334 void** valarray = NULL;
2335
2336 ajulong n = 0UL;
2337 ajulong i = 0UL;
2338
2339 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2340
2341 ajTableClear(table);
2342
2343 table->Fcmp = &ajTablecharCmp;
2344 table->Fhash = &ajTablecharHash;
2345 table->Fkeydel = &ajMemFree;
2346 table->Type = ajETableTypeChar;
2347
2348 if(n)
2349 {
2350 for(i = 0UL; i < n; i++)
2351 ajTablePut(table, keyarray[i], valarray[i]);
2352 }
2353
2354 AJFREE(keyarray);
2355 AJFREE(valarray);
2356
2357 return;
2358 }
2359
2360
2361
2362
2363 /* @func ajTableSettypeCharCase ***********************************************
2364 **
2365 ** Resets a hash table to use case-insensitive C character string keys
2366 **
2367 ** @param [u] table [AjPTable] Hash table
2368 ** @return [void]
2369 **
2370 ** @release 6.4.0
2371 ** @@
2372 ******************************************************************************/
2373
ajTableSettypeCharCase(AjPTable table)2374 void ajTableSettypeCharCase(AjPTable table)
2375 {
2376 void** keyarray = NULL;
2377 void** valarray = NULL;
2378
2379 ajulong n = 0UL;
2380 ajulong i = 0UL;
2381
2382 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2383
2384 ajTableClear(table);
2385
2386 table->Fcmp = &ajTablecharCmpCase;
2387 table->Fhash = &ajTablecharHashCase;
2388 table->Fkeydel = &ajMemFree;
2389 table->Type = ajETableTypeChar;
2390
2391 if(n)
2392 {
2393 for(i = 0UL; i < n; i++)
2394 ajTablePut(table, keyarray[i], valarray[i]);
2395 }
2396
2397 AJFREE(keyarray);
2398 AJFREE(valarray);
2399
2400 return;
2401 }
2402
2403
2404
2405
2406 /* @func ajTableSettypeDefault ************************************************
2407 **
2408 ** Resets a hash table to use default keys
2409 **
2410 ** @param [u] table [AjPTable] Hash table
2411 ** @return [void]
2412 **
2413 ** @release 6.4.0
2414 ** @@
2415 ******************************************************************************/
2416
ajTableSettypeDefault(AjPTable table)2417 void ajTableSettypeDefault(AjPTable table)
2418 {
2419 void** keyarray = NULL;
2420 void** valarray = NULL;
2421
2422 ajulong n = 0UL;
2423 ajulong i = 0UL;
2424
2425 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2426
2427 ajTableClear(table);
2428
2429 table->Fcmp = &tableCmpAtom;
2430 table->Fhash = &tableHashAtom;
2431 table->Fkeydel = NULL;
2432 table->Type = ajETableTypeUnknown;
2433
2434 if(n)
2435 {
2436 for(i = 0UL; i < n; i++)
2437 ajTablePut(table, keyarray[i], valarray[i]);
2438 }
2439
2440 AJFREE(keyarray);
2441 AJFREE(valarray);
2442
2443 return;
2444 }
2445
2446
2447
2448
2449 /* @func ajTableSettypeInt ****************************************************
2450 **
2451 ** Resets a hash table to use integer keys
2452 **
2453 ** @param [u] table [AjPTable] Hash table
2454 ** @return [void]
2455 **
2456 ** @release 6.4.0
2457 ** @@
2458 ******************************************************************************/
2459
ajTableSettypeInt(AjPTable table)2460 void ajTableSettypeInt(AjPTable table)
2461 {
2462 void** keyarray = NULL;
2463 void** valarray = NULL;
2464
2465 ajulong n = 0UL;
2466 ajulong i = 0UL;
2467
2468 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2469
2470 ajTableClear(table);
2471
2472 table->Fcmp = &ajTableintCmp;
2473 table->Fhash = &ajTableintHash;
2474 table->Fkeydel = &ajMemFree;
2475 table->Type = ajETableTypeInt;
2476
2477 if(n)
2478 {
2479 for(i = 0Ul; i < n; i++)
2480 ajTablePut(table, keyarray[i], valarray[i]);
2481 }
2482
2483 AJFREE(keyarray);
2484 AJFREE(valarray);
2485
2486 return;
2487 }
2488
2489
2490
2491
2492 /* @func ajTableSettypeLong ***************************************************
2493 **
2494 ** Resets a hash table to use long integer keys
2495 **
2496 ** @param [u] table [AjPTable] Hash table
2497 ** @return [void]
2498 **
2499 ** @release 6.4.0
2500 ** @@
2501 ******************************************************************************/
2502
ajTableSettypeLong(AjPTable table)2503 void ajTableSettypeLong(AjPTable table)
2504 {
2505 void** keyarray = NULL;
2506 void** valarray = NULL;
2507
2508 ajulong n = 0UL;
2509 ajulong i = 0UL;
2510
2511 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2512
2513 ajTableClear(table);
2514
2515 table->Fcmp = &ajTablelongCmp;
2516 table->Fhash = &ajTablelongHash;
2517 table->Fkeydel = &ajMemFree;
2518 table->Type = ajETableTypeLong;
2519
2520 if(n)
2521 {
2522 for(i = 0UL; i < n; i++)
2523 ajTablePut(table, keyarray[i], valarray[i]);
2524 }
2525
2526 AJFREE(keyarray);
2527 AJFREE(valarray);
2528
2529 return;
2530 }
2531
2532
2533
2534
2535 /* @func ajTableSettypeString *************************************************
2536 **
2537 ** Resets a hash table to use string keys
2538 **
2539 ** @param [u] table [AjPTable] Hash table
2540 ** @return [void]
2541 **
2542 ** @release 6.4.0
2543 ** @@
2544 ******************************************************************************/
2545
ajTableSettypeString(AjPTable table)2546 void ajTableSettypeString(AjPTable table)
2547 {
2548 void** keyarray = NULL;
2549 void** valarray = NULL;
2550
2551 ajulong n = 0UL;
2552 ajulong i = 0UL;
2553
2554 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2555
2556 ajTableClear(table);
2557
2558 table->Fcmp = &ajTablestrCmp;
2559 table->Fhash = &ajTablestrHash;
2560 table->Fkeydel = &tableDelStr;
2561 table->Type = ajETableTypeStr;
2562
2563 if(n)
2564 {
2565 for(i = 0UL; i < n; i++)
2566 ajTablePut(table, keyarray[i], valarray[i]);
2567 }
2568
2569 AJFREE(keyarray);
2570 AJFREE(valarray);
2571
2572 return;
2573 }
2574
2575
2576
2577
2578 /* @func ajTableSettypeStringCase *********************************************
2579 **
2580 ** Resets a hash table to use case-insensitive string keys
2581 **
2582 ** @param [u] table [AjPTable] Hash table
2583 ** @return [void]
2584 **
2585 ** @release 6.4.0
2586 ** @@
2587 ******************************************************************************/
2588
ajTableSettypeStringCase(AjPTable table)2589 void ajTableSettypeStringCase(AjPTable table)
2590 {
2591 void** keyarray = NULL;
2592 void** valarray = NULL;
2593
2594 ajulong n = 0UL;
2595 ajulong i = 0UL;
2596
2597 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2598
2599 ajTableClear(table);
2600
2601 table->Fcmp = &ajTablestrCmpCase;
2602 table->Fhash = &ajTablestrHashCase;
2603 table->Fkeydel = &tableDelStr;
2604 table->Type = ajETableTypeStr;
2605
2606 if(n)
2607 {
2608 for(i = 0UL; i < n; i++)
2609 ajTablePut(table, keyarray[i], valarray[i]);
2610 }
2611
2612 AJFREE(keyarray);
2613 AJFREE(valarray);
2614
2615 return;
2616 }
2617
2618
2619
2620
2621 /* @func ajTableSettypeUint ***************************************************
2622 **
2623 ** Resets a hash table to use unsigned integer keys
2624 **
2625 ** @param [u] table [AjPTable] Hash table
2626 ** @return [void]
2627 **
2628 ** @release 6.4.0
2629 ** @@
2630 ******************************************************************************/
2631
ajTableSettypeUint(AjPTable table)2632 void ajTableSettypeUint(AjPTable table)
2633 {
2634 void** keyarray = NULL;
2635 void** valarray = NULL;
2636
2637 ajulong n = 0UL;
2638 ajulong i = 0UL;
2639
2640 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2641
2642 ajTableClear(table);
2643
2644 table->Fcmp = &ajTableuintCmp;
2645 table->Fhash = &ajTableuintHash;
2646 table->Fkeydel = &ajMemFree;
2647 table->Type = ajETableTypeUint;
2648
2649 if(n)
2650 {
2651 for(i = 0UL; i < n; i++)
2652 ajTablePut(table, keyarray[i], valarray[i]);
2653 }
2654
2655 AJFREE(keyarray);
2656 AJFREE(valarray);
2657
2658 return;
2659 }
2660
2661
2662
2663
2664 /* @func ajTableSettypeUlong **************************************************
2665 **
2666 ** Resets a hash table to use unsigned long integer keys
2667 **
2668 ** @param [u] table [AjPTable] Hash table
2669 ** @return [void]
2670 **
2671 ** @release 6.4.0
2672 ** @@
2673 ******************************************************************************/
2674
ajTableSettypeUlong(AjPTable table)2675 void ajTableSettypeUlong(AjPTable table)
2676 {
2677 void** keyarray = NULL;
2678 void** valarray = NULL;
2679
2680 ajulong n = 0UL;
2681 ajulong i = 0UL;
2682
2683 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2684
2685 ajTableClear(table);
2686
2687 table->Fcmp = &ajTableulongCmp;
2688 table->Fhash = &ajTableulongHash;
2689 table->Fkeydel = &ajMemFree;
2690 table->Type = ajETableTypeUlong;
2691
2692 if(n)
2693 {
2694 for(i = 0UL; i < n; i++)
2695 ajTablePut(table, keyarray[i], valarray[i]);
2696 }
2697
2698 AJFREE(keyarray);
2699 AJFREE(valarray);
2700
2701 return;
2702 }
2703
2704
2705
2706
2707 /* @func ajTableSettypeUser ***************************************************
2708 **
2709 ** Resets a hash table to use user-defined keys
2710 **
2711 **
2712 ** @param [u] table [AjPTable] Hash table
2713 ** @param [fN] cmp [ajint function] function for comparing
2714 ** @param [fN] hash [ajulong function] function for hashing keys
2715 ** @return [void]
2716 **
2717 ** @release 6.4.0
2718 ** @@
2719 ******************************************************************************/
2720
ajTableSettypeUser(AjPTable table,ajint (* cmp)(const void * P1,const void * P2),ajulong (* hash)(const void * key,ajulong hashsize))2721 void ajTableSettypeUser(AjPTable table,
2722 ajint (*cmp)(const void* P1, const void* P2),
2723 ajulong (*hash)(const void* key, ajulong hashsize))
2724 {
2725 void** keyarray = NULL;
2726 void** valarray = NULL;
2727
2728 ajulong n = 0UL;
2729 ajulong i = 0UL;
2730
2731 n = ajTableToarrayKeysValues(table, &keyarray, &valarray);
2732
2733 ajTableClear(table);
2734
2735 table->Fcmp = cmp;
2736 table->Fhash = hash;
2737 table->Fkeydel = NULL;
2738 table->Type = ajETableTypeUser;
2739
2740 if(n)
2741 {
2742 for(i = 0UL; i < n; i++)
2743 ajTablePut(table, keyarray[i], valarray[i]);
2744 }
2745
2746 AJFREE(keyarray);
2747 AJFREE(valarray);
2748
2749 return;
2750 }
2751
2752
2753
2754
2755 /* @section Merging ***********************************************************
2756 **
2757 ** Merging two tables with matchng key and value types
2758 **
2759 ** @fdata [AjPTable]
2760 **
2761 ** @fcategory modify
2762 **
2763 ** @nam3rule Merge Merge two tables
2764 ** @nam4rule And Keep keys in both tables
2765 ** @nam4rule Eor Keep keys in one but not both tables
2766 ** @nam4rule Not Keep keys in first table but not in second table
2767 ** @nam4rule Or Keep all keys, removing duplicates
2768 **
2769 ** @argrule * thys [AjPTable] Current table
2770 ** @argrule * table [AjPTable] Table to be merged
2771 **
2772 ** @valrule * [AjBool] true on success
2773 ******************************************************************************/
2774
2775
2776
2777
2778 /* @func ajTableMergeAnd ******************************************************
2779 **
2780 ** Merge two tables, keeping all keys that are in both tables
2781 **
2782 ** @param [u] thys [AjPTable] Current table
2783 ** @param [u] table [AjPTable] Table to be merged
2784 **
2785 ** @return [AjBool] True on success
2786 **
2787 **
2788 ** @release 6.4.0
2789 ******************************************************************************/
2790
ajTableMergeAnd(AjPTable thys,AjPTable table)2791 AjBool ajTableMergeAnd(AjPTable thys, AjPTable table)
2792 {
2793 ajulong i = 0UL;
2794
2795 AjBool ismatch = ajFalse;
2796
2797 AjPTableNode p = NULL;
2798 AjPTableNode q = NULL;
2799 AjPTableNode tmpnode = NULL;
2800 AjPTableNode pprev = NULL;
2801 AjPTableNode pfirst = NULL;
2802 AjPTableNode qfirst = NULL;
2803
2804 /* first we make both tables have the same hashsize */
2805
2806 if(table->Size > thys->Size)
2807 ajTableResizeHashsize(thys, table->Size);
2808 else if(thys->Size > table->Size)
2809 ajTableResizeHashsize(table, thys->Size);
2810
2811 /* compare keys and find matches */
2812
2813 for(i = 0UL; i < thys->Size; i++)
2814 {
2815 pfirst = thys->Buckets[i];
2816 qfirst = table->Buckets[i];
2817
2818 pprev = NULL;
2819 p = pfirst;
2820
2821 while(p)
2822 {
2823 ismatch = ajFalse;
2824
2825 for(q = qfirst; q; q = q->Link)
2826 {
2827 if((*thys->Fcmp)(p->Key, q->Key) == 0)
2828 {
2829 ismatch = ajTrue;
2830 break;
2831 }
2832 }
2833
2834 if(ismatch)
2835 {
2836 pprev = p;
2837 p = p->Link;
2838 }
2839 else
2840 {
2841 tmpnode = p->Link;
2842
2843 if(thys->Fkeydel)
2844 (*thys->Fkeydel)(&p->Key);
2845 if(thys->Fvaldel)
2846 (*thys->Fvaldel)(&p->Value);
2847
2848 if(tableFreeNext >= tableFreeMax)
2849 tableFreeSetExpand();
2850 if(tableFreeNext >= tableFreeMax)
2851 AJFREE(p);
2852 else
2853 tableFreeSet[tableFreeNext++] = p;
2854
2855 p = tmpnode;
2856
2857 if(pprev)
2858 pprev->Link = tmpnode;
2859 else
2860 thys->Buckets[i] = tmpnode;
2861
2862 --thys->Length;
2863 }
2864 }
2865
2866 for(q = qfirst; q; q = tmpnode)
2867 {
2868 tmpnode = q->Link;
2869
2870 if(table->Fkeydel)
2871 (*table->Fkeydel)(&q->Key);
2872
2873 if(table->Fvaldel)
2874 (*table->Fvaldel)(&q->Value);
2875
2876 if(tableFreeNext >= tableFreeMax)
2877 tableFreeSetExpand();
2878 if(tableFreeNext >= tableFreeMax)
2879 AJFREE(q);
2880 else
2881 tableFreeSet[tableFreeNext++] = q;
2882
2883 --table->Length;
2884 }
2885 table->Buckets[i] = NULL;
2886 }
2887
2888 return ajTrue;
2889 }
2890
2891
2892
2893
2894 /* @func ajTableMergeEor ******************************************************
2895 **
2896 ** Merge two tables, keeping all keys that are in only one table
2897 **
2898 ** @param [u] thys [AjPTable] Current table
2899 ** @param [u] table [AjPTable] Table to be merged
2900 **
2901 ** @return [AjBool] True on success
2902 **
2903 **
2904 ** @release 6.4.0
2905 ******************************************************************************/
2906
ajTableMergeEor(AjPTable thys,AjPTable table)2907 AjBool ajTableMergeEor(AjPTable thys, AjPTable table)
2908 {
2909 ajulong i = 0UL;
2910
2911 AjBool ismatch = ajFalse;
2912
2913 AjPTableNode p = NULL;
2914 AjPTableNode q = NULL;
2915 AjPTableNode tmpnode = NULL;
2916 AjPTableNode pprev = NULL;
2917 AjPTableNode qprev = NULL;
2918 AjPTableNode pfirst = NULL;
2919 AjPTableNode qfirst = NULL;
2920 AjPTableNode qtmp = NULL;
2921
2922 /* first we make both tables have the same hashsize */
2923
2924 if(table->Size > thys->Size)
2925 ajTableResizeHashsize(thys, table->Size);
2926 else if(thys->Size > table->Size)
2927 ajTableResizeHashsize(table, thys->Size);
2928
2929 /* compare keys and find matches */
2930
2931 for(i=0; i < thys->Size; i++)
2932 {
2933 pfirst = thys->Buckets[i];
2934 qfirst = table->Buckets[i];
2935
2936 pprev = NULL;
2937 p = pfirst;
2938 while(p)
2939 {
2940 ismatch = ajFalse;
2941
2942 qprev = NULL;
2943 for(q = qfirst; q; q = q->Link)
2944 {
2945 if((*thys->Fcmp)(p->Key, q->Key) == 0)
2946 {
2947 ismatch = ajTrue;
2948 break;
2949 }
2950 qprev = q;
2951 }
2952
2953 if(!ismatch)
2954 {
2955 pprev = p;
2956 p = p->Link;
2957 }
2958 else
2959 {
2960 tmpnode = p->Link;
2961
2962 if(thys->Fkeydel)
2963 (*thys->Fkeydel)(&p->Key);
2964 if(thys->Fvaldel)
2965 (*thys->Fvaldel)(&p->Value);
2966
2967 if(tableFreeNext >= tableFreeMax)
2968 tableFreeSetExpand();
2969 if(tableFreeNext >= tableFreeMax)
2970 AJFREE(p);
2971 else
2972 tableFreeSet[tableFreeNext++] = p;
2973
2974 p = tmpnode;
2975
2976 if(pprev)
2977 pprev->Link = tmpnode;
2978 else
2979 thys->Buckets[i] = tmpnode;
2980
2981 --thys->Length;
2982
2983 tmpnode = q->Link;
2984
2985 if(table->Fkeydel)
2986 (*table->Fkeydel)(&q->Key);
2987
2988 if(table->Fvaldel)
2989 (*table->Fvaldel)(&q->Value);
2990
2991 if(tableFreeNext >= tableFreeMax)
2992 tableFreeSetExpand();
2993 if(tableFreeNext >= tableFreeMax)
2994 AJFREE(q);
2995 else
2996 tableFreeSet[tableFreeNext++] = q;
2997
2998
2999 if(qprev)
3000 qprev->Link = tmpnode;
3001 else
3002 qfirst = table->Buckets[i] = tmpnode;
3003
3004 --table->Length;
3005 }
3006 }
3007
3008 for(q = table->Buckets[i]; q; q = qtmp)
3009 {
3010 qtmp = q->Link;
3011 tmpnode = thys->Buckets[i];
3012 thys->Buckets[i] = q;
3013 q->Link = tmpnode;
3014
3015 --table->Length;
3016 ++thys->Length;
3017 }
3018 table->Buckets[i] = NULL;
3019 }
3020
3021 return ajTrue;
3022 }
3023
3024
3025
3026
3027 /* @func ajTableMergeNot ******************************************************
3028 **
3029 ** Merge two tables, removing all keys that are not in the new table
3030 **
3031 ** @param [u] thys [AjPTable] Current table
3032 ** @param [u] table [AjPTable] Table to be merged
3033 **
3034 ** @return [AjBool] True on success
3035 **
3036 **
3037 ** @release 6.4.0
3038 ******************************************************************************/
3039
ajTableMergeNot(AjPTable thys,AjPTable table)3040 AjBool ajTableMergeNot(AjPTable thys, AjPTable table)
3041 {
3042 ajulong i = 0UL;
3043
3044 AjBool ismatch = ajFalse;
3045
3046 AjPTableNode p = NULL;
3047 AjPTableNode q = NULL;
3048 AjPTableNode tmpnode = NULL;
3049 AjPTableNode pprev = NULL;
3050 AjPTableNode pfirst = NULL;
3051 AjPTableNode qfirst = NULL;
3052
3053 /* first we make both tables have the same hashsize */
3054
3055 if(table->Size > thys->Size)
3056 ajTableResizeHashsize(thys, table->Size);
3057 else if(thys->Size > table->Size)
3058 ajTableResizeHashsize(table, thys->Size);
3059
3060 /* compare keys and find matches */
3061
3062 for(i=0UL; i < thys->Size; i++)
3063 {
3064 pfirst = thys->Buckets[i];
3065 qfirst = table->Buckets[i];
3066
3067 pprev = NULL;
3068 p = pfirst;
3069
3070 while(p)
3071 {
3072 ismatch = ajFalse;
3073
3074 for(q = qfirst; q; q = q->Link)
3075 {
3076 if((*thys->Fcmp)(p->Key, q->Key) == 0)
3077 {
3078 ismatch = ajTrue;
3079 break;
3080 }
3081 }
3082
3083 if(!ismatch)
3084 {
3085 pprev = p;
3086 p = p->Link;
3087 }
3088 else
3089 {
3090 tmpnode = p->Link;
3091
3092 if(thys->Fkeydel)
3093 (*thys->Fkeydel)(&p->Key);
3094 if(thys->Fvaldel)
3095 (*thys->Fvaldel)(&p->Value);
3096
3097 if(tableFreeNext >= tableFreeMax)
3098 tableFreeSetExpand();
3099 if(tableFreeNext >= tableFreeMax)
3100 AJFREE(p);
3101 else
3102 tableFreeSet[tableFreeNext++] = p;
3103
3104 p = tmpnode;
3105
3106 if(pprev)
3107 pprev->Link = tmpnode;
3108 else
3109 thys->Buckets[i] = tmpnode;
3110
3111 --thys->Length;
3112 }
3113 }
3114 for(q = qfirst; q; q = tmpnode)
3115 {
3116 tmpnode = q->Link;
3117
3118 if(table->Fkeydel)
3119 (*table->Fkeydel)(&q->Key);
3120
3121 if(table->Fvaldel)
3122 (*table->Fvaldel)(&q->Value);
3123
3124 if(tableFreeNext >= tableFreeMax)
3125 tableFreeSetExpand();
3126 if(tableFreeNext >= tableFreeMax)
3127 AJFREE(q);
3128 else
3129 tableFreeSet[tableFreeNext++] = q;
3130
3131 --table->Length;
3132 }
3133 table->Buckets[i] = NULL;
3134 }
3135
3136 return ajTrue;
3137 }
3138
3139
3140
3141
3142 /* @func ajTableMergeOr *******************************************************
3143 **
3144 ** Merge two tables, adding all unique keys from the new table
3145 **
3146 ** @param [u] thys [AjPTable] Current table
3147 ** @param [u] table [AjPTable] Table to be merged
3148 **
3149 ** @return [AjBool] True on success
3150 **
3151 **
3152 ** @release 6.4.0
3153 ******************************************************************************/
3154
ajTableMergeOr(AjPTable thys,AjPTable table)3155 AjBool ajTableMergeOr(AjPTable thys, AjPTable table)
3156 {
3157 ajulong i = 0UL;
3158
3159 AjBool ismatch = ajFalse;
3160
3161 AjPTableNode p = NULL;
3162 AjPTableNode q = NULL;
3163 AjPTableNode tmpnode = NULL;
3164 AjPTableNode qprev = NULL;
3165 AjPTableNode pfirst = NULL;
3166 AjPTableNode qfirst = NULL;
3167 AjPTableNode qtmp = NULL;
3168
3169 /* first we make both tables have the same hashsize */
3170
3171 if(table->Size > thys->Size)
3172 ajTableResizeHashsize(thys, table->Size);
3173 else if(thys->Size > table->Size)
3174 ajTableResizeHashsize(table, thys->Size);
3175
3176 /* compare keys and find matches */
3177
3178 for(i=0UL; i < thys->Size; i++)
3179 {
3180 pfirst = thys->Buckets[i];
3181 qfirst = table->Buckets[i];
3182
3183 p = pfirst;
3184
3185 while(p)
3186 {
3187 ismatch = ajFalse;
3188
3189 qprev = NULL;
3190 for(q = qfirst; q; q = q->Link)
3191 {
3192 if((*thys->Fcmp)(p->Key, q->Key) == 0)
3193 {
3194 ismatch = ajTrue;
3195 break;
3196 }
3197 qprev = q;
3198 }
3199
3200 p = p->Link;
3201
3202 if(ismatch)
3203 {
3204 tmpnode = q->Link;
3205
3206 if(table->Fkeydel)
3207 (*table->Fkeydel)(&q->Key);
3208 if(table->Fvaldel)
3209 (*table->Fvaldel)(&q->Value);
3210
3211 if(tableFreeNext >= tableFreeMax)
3212 tableFreeSetExpand();
3213 if(tableFreeNext >= tableFreeMax)
3214 AJFREE(q);
3215 else
3216 tableFreeSet[tableFreeNext++] = q;
3217
3218 q = tmpnode;
3219
3220 if(qprev)
3221 qprev->Link = tmpnode;
3222 else
3223 qfirst = table->Buckets[i] = tmpnode;
3224
3225 --table->Length;
3226 }
3227 }
3228
3229 for(q = table->Buckets[i]; q; q = qtmp)
3230 {
3231 qtmp = q->Link;
3232 tmpnode = thys->Buckets[i];
3233 thys->Buckets[i] = q;
3234 q->Link = tmpnode;
3235
3236 --table->Length;
3237 ++thys->Length;
3238 }
3239 table->Buckets[i] = NULL;
3240 }
3241
3242 return ajTrue;
3243 }
3244
3245
3246
3247
3248 /* @section Comparison functions **********************************************
3249 **
3250 ** @fdata [AjPTable]
3251 **
3252 ** Comparison functions for table keys
3253 **
3254 ** @nam3rule Cmp Comparison
3255 ** @nam3rule Hash Hashing keys
3256 **
3257 ** @argrule Cmp key1 [const void*] First key
3258 ** @argrule Cmp key2 [const void*] Second key
3259 ** @argrule Hash key [const void*] Key
3260 ** @argrule Hash hashsize [ajulong] Hash table size
3261 ** @suffix Case Case insensitive keys
3262 **
3263 ** @valrule Cmp [ajint] Comparison result 0 for a match,
3264 ** -1 or +1 for a mismatch
3265 ** @valrule Hash [ajulong] hash value
3266 **
3267 ** @fcategory misc
3268 **
3269 ******************************************************************************/
3270
3271
3272
3273
3274 /* @funcstatic tableCmpAtom ***************************************************
3275 **
3276 ** Default comparison function for key comparison
3277 **
3278 ** @param [r] key1 [const void*] First key
3279 ** @param [r] key2 [const void*] Second key
3280 ** @return [ajint] 0 for success, 1 for different keys
3281 **
3282 ** @release 2.0.0
3283 ** @@
3284 ******************************************************************************/
3285
3286
tableCmpAtom(const void * key1,const void * key2)3287 static ajint tableCmpAtom(const void* key1, const void* key2)
3288 {
3289 return (ajint) (key1 != key2);
3290 }
3291
3292
3293
3294
3295 /* @funcstatic tableHashAtom **************************************************
3296 **
3297 ** Default hash function for key indexing
3298 **
3299 ** @param [r] key [const void*] Key
3300 ** @param [r] hashsize [ajulong] Hash size (maximum hash value)
3301 ** @return [ajulong] Hash value in range 0 to hashsize-1
3302 **
3303 ** @release 2.0.0
3304 ** @@
3305 ******************************************************************************/
3306
tableHashAtom(const void * key,ajulong hashsize)3307 static ajulong tableHashAtom(const void* key, ajulong hashsize)
3308 {
3309 return((unsigned long)key>>2) % hashsize;
3310 }
3311
3312
3313
3314
3315 /* @section exit **************************************************************
3316 **
3317 ** Functions called on exit from the program by ajExit to do
3318 ** any necessary cleanup and to report internal statistics to the debug file
3319 **
3320 ** @fdata [AjPTable]
3321 ** @fnote general exit functions, no arguments
3322 **
3323 ** @nam3rule Exit Cleanup and report on exit
3324 **
3325 ** @valrule * [void]
3326 **
3327 ** @fcategory misc
3328 ******************************************************************************/
3329
3330
3331
3332
3333 /* @func ajTableExit **********************************************************
3334 **
3335 ** Prints a summary of table usage with debug calls
3336 **
3337 ** @return [void]
3338 **
3339 ** @release 2.8.0
3340 ** @@
3341 ******************************************************************************/
3342
ajTableExit(void)3343 void ajTableExit(void)
3344 {
3345 ajulong i = 0UL;
3346
3347 #ifdef AJ_SAVESTATS
3348 ajDebug("Table usage : %d opened, %d closed, %d maxsize, %d maxmem\n",
3349 tableNewCnt, tableDelCnt, tableMaxNum, tableMaxMem);
3350 #endif
3351
3352 if(tableFreeNext)
3353 for(i = 0UL; i < tableFreeNext; i++)
3354 AJFREE(tableFreeSet[i]);
3355
3356 if(tableFreeSet)
3357 AJFREE(tableFreeSet);
3358
3359 ajStrDel(&tableTmpkeyStr);
3360
3361 tableFreeNext = 0UL;
3362 tableFreeMax = 0UL;
3363
3364 return;
3365 }
3366
3367
3368
3369
3370 /* @datasection [AjPTable] Character hash tables ******************************
3371 **
3372 ** @nam2rule Tablechar
3373 **
3374 ******************************************************************************/
3375
3376
3377
3378
3379 /* @section Constructors ******************************************************
3380 **
3381 ** Constructors for hash tables
3382 **
3383 ** @fdata [AjPTable]
3384 **
3385 ** @fcategory new
3386 **
3387 ** @nam3rule New Constructor
3388 ** @nam4rule Case Case-sensitive keys
3389 ** @suffix Const Constant keys with no destructor
3390 **
3391 ** @argrule New size [ajulong] Number of key values
3392 **
3393 ** @valrule * [AjPTable] New hash table
3394 **
3395 ******************************************************************************/
3396
3397
3398
3399
3400 /* @func ajTablecharNew *******************************************************
3401 **
3402 ** Creates a table with a character string key.
3403 **
3404 ** @param [r] size [ajulong] number of key-value pairs
3405 ** @return [AjPTable] New table object with a character string key.
3406 **
3407 ** @release 5.0.0
3408 ** @@
3409 ******************************************************************************/
3410
ajTablecharNew(ajulong size)3411 AjPTable ajTablecharNew(ajulong size)
3412 {
3413 AjPTable table = NULL;
3414
3415 table = ajTableNewFunctionLen(size, &ajTablecharCmp, &ajTablecharHash,
3416 &ajMemFree, NULL);
3417 table->Type = ajETableTypeChar;
3418
3419 return table;
3420 }
3421
3422
3423
3424
3425 /* @func ajTablecharNewCase ***************************************************
3426 **
3427 ** Creates a table with a character string key and case insensitive searching.
3428 **
3429 ** @param [r] size [ajulong] Hash size estimate.
3430 ** @return [AjPTable] New table object with a character string key.
3431 **
3432 ** @release 5.0.0
3433 ** @@
3434 ******************************************************************************/
3435
ajTablecharNewCase(ajulong size)3436 AjPTable ajTablecharNewCase(ajulong size)
3437 {
3438 AjPTable table = NULL;
3439
3440 table = ajTableNewFunctionLen(size, &ajTablecharCmpCase,
3441 &ajTablecharHashCase, &ajMemFree, NULL);
3442 table->Type = ajETableTypeChar;
3443
3444 return table;
3445 }
3446
3447
3448
3449
3450 /* @func ajTablecharNewCaseConst **********************************************
3451 **
3452 ** Creates a table with a character string key and case insensitive searching.
3453 **
3454 ** @param [r] size [ajulong] Hash size estimate.
3455 ** @return [AjPTable] New table object with a character string key.
3456 **
3457 ** @release 6.4.0
3458 ** @@
3459 ******************************************************************************/
3460
ajTablecharNewCaseConst(ajulong size)3461 AjPTable ajTablecharNewCaseConst(ajulong size)
3462 {
3463 AjPTable table = NULL;
3464
3465 table = ajTableNewFunctionLen(size, &ajTablecharCmpCase,
3466 &ajTablecharHashCase,
3467 NULL, NULL);
3468 table->Type = ajETableTypeChar;
3469
3470 return table;
3471 }
3472
3473
3474
3475
3476 /* @func ajTablecharNewConst **************************************************
3477 **
3478 ** Creates a table with a character string key.
3479 **
3480 ** @param [r] size [ajulong] number of key-value pairs
3481 ** @return [AjPTable] New table object with a character string key.
3482 **
3483 ** @release 6.4.0
3484 ** @@
3485 ******************************************************************************/
3486
ajTablecharNewConst(ajulong size)3487 AjPTable ajTablecharNewConst(ajulong size)
3488 {
3489 AjPTable table = NULL;
3490
3491 table = ajTableNewFunctionLen(size, &ajTablecharCmp, &ajTablecharHash,
3492 NULL, NULL);
3493 table->Type = ajETableTypeChar;
3494
3495 return table;
3496 }
3497
3498
3499
3500
3501 /* @section Trace functions ***************************************************
3502 **
3503 ** @fdata [AjPTable]
3504 **
3505 ** @nam3rule Print Trace contents to standard error
3506 ** @nam3rule Trace Trace contents to debug file
3507 **
3508 ** @argrule * table [const AjPTable] Hash table
3509 **
3510 ** @valrule * [void]
3511 **
3512 ** @fcategory misc
3513 **
3514 ******************************************************************************/
3515
3516
3517
3518
3519 /* @func ajTablecharPrint *****************************************************
3520 **
3521 ** Print function for a table with a character string key.
3522 **
3523 ** @param [r] table [const AjPTable] Table.
3524 ** @return [void]
3525 **
3526 ** @release 5.0.0
3527 ** @@
3528 ******************************************************************************/
3529
ajTablecharPrint(const AjPTable table)3530 void ajTablecharPrint(const AjPTable table)
3531 {
3532 ajulong i = 0UL;
3533
3534 AjPTableNode node = NULL;
3535
3536 if(!table)
3537 return;
3538
3539 for(i = 0UL; i < table->Size; i++)
3540 for(node = table->Buckets[i]; node; node = node->Link)
3541 {
3542 ajUser("key '%s' value '%s'",
3543 (const char*) node->Key, (char*) node->Value);
3544 }
3545
3546 return;
3547 }
3548
3549
3550
3551
3552 /* @section Comparison functions **********************************************
3553 **
3554 ** @fdata [AjPTable]
3555 **
3556 ** Comparison functions for table keys
3557 **
3558 ** @nam3rule Cmp Comparison
3559 ** @nam3rule Hash Hashing keys
3560 **
3561 ** @argrule Cmp key1 [const void*] First key
3562 ** @argrule Cmp key2 [const void*] Second key
3563 ** @argrule Hash key [const void*] Key
3564 ** @argrule Hash hashsize [ajulong] Hash table size
3565 ** @suffix Case Case insensitive keys
3566 **
3567 ** @valrule Cmp [ajint] Comparison result 0 for a match,
3568 ** -1 or +1 for a mismatch
3569 ** @valrule Hash [ajulong] hash value
3570 **
3571 ** @fcategory misc
3572 **
3573 ******************************************************************************/
3574
3575
3576
3577
3578 /* @func ajTablecharCmp *******************************************************
3579 **
3580 ** Comparison function for a table with a character string key
3581 **
3582 ** @param [r] key1 [const void*] First key.
3583 ** @param [r] key2 [const void*] Second key.
3584 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
3585 **
3586 ** @release 5.0.0
3587 ** @@
3588 ******************************************************************************/
3589
ajTablecharCmp(const void * key1,const void * key2)3590 ajint ajTablecharCmp(const void* key1, const void* key2)
3591 {
3592 return (ajint) strcmp((const char*) key1, (const char*) key2);
3593 }
3594
3595
3596
3597
3598 /* @func ajTablecharCmpCase ***************************************************
3599 **
3600 ** Comparison function for a table with a character string key
3601 ** and case insensitivity.
3602 **
3603 ** @param [r] key1 [const void*] First key.
3604 ** @param [r] key2 [const void*] Second key.
3605 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
3606 **
3607 ** @release 5.0.0
3608 ** @@
3609 ******************************************************************************/
3610
ajTablecharCmpCase(const void * key1,const void * key2)3611 ajint ajTablecharCmpCase(const void* key1, const void* key2)
3612 {
3613 return (ajint) ajCharCmpCase((const char*) key1, (const char*) key2);
3614 }
3615
3616
3617
3618
3619 /* @func ajTablecharHash ******************************************************
3620 **
3621 ** Hash function for a table with a character string key
3622 **
3623 ** @param [r] key [const void*] Standard argument. Table key.
3624 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
3625 ** @return [ajulong] Hash value.
3626 **
3627 ** @release 5.0.0
3628 ** @@
3629 ******************************************************************************/
3630
ajTablecharHash(const void * key,ajulong hashsize)3631 ajulong ajTablecharHash(const void* key, ajulong hashsize)
3632 {
3633 ajulong hash = 0UL;
3634
3635 const char* s = NULL;
3636
3637 s = (const char*) key;
3638
3639 for(hash = 0UL; *s; s++)
3640 hash = (hash * 127 + *s) % hashsize;
3641
3642 return hash;
3643 }
3644
3645
3646
3647
3648 /* @func ajTablecharHashCase **************************************************
3649 **
3650 ** Hash function for a table with a character string key and
3651 ** case insensitivity.
3652 **
3653 ** @param [r] key [const void*] Standard argument. Table key.
3654 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
3655 ** @return [ajulong] Hash value.
3656 **
3657 ** @release 5.0.0
3658 ** @@
3659 ******************************************************************************/
3660
ajTablecharHashCase(const void * key,ajulong hashsize)3661 ajulong ajTablecharHashCase(const void* key, ajulong hashsize)
3662 {
3663 ajulong hash = 0UL;
3664
3665 const char* s = NULL;
3666
3667 s = (const char*) key;
3668
3669 for(hash = 0UL; *s; s++)
3670 hash = (hash * 127 + toupper((ajint)*s)) % hashsize;
3671
3672 return hash;
3673 }
3674
3675
3676
3677
3678 /* @datasection [AjPTable] Integer hash tables ********************************
3679 **
3680 ** @nam2rule Tableint Integer hash tables
3681 **
3682 ******************************************************************************/
3683
3684
3685
3686
3687 /* @section Constructors ******************************************************
3688 **
3689 ** Constructors for hash tables
3690 **
3691 ** @fdata [AjPTable]
3692 **
3693 ** @fcategory new
3694 **
3695 ** @nam3rule New Constructor
3696 ** @nam4rule Case Case-sensitive keys
3697 ** @suffix Const Constant keys with no destructor
3698 **
3699 ** @argrule New size [ajulong] Number of key values
3700 **
3701 ** @valrule * [AjPTable] New hash table
3702 **
3703 ******************************************************************************/
3704
3705
3706
3707
3708 /* @func ajTableintNew ********************************************************
3709 **
3710 ** Creates, initialises, and returns a new, empty table that can hold a
3711 ** specified number of integer key-value pairs.
3712 **
3713 ** @param [r] size [ajulong] estimate of number of unique keys
3714 **
3715 ** @return [AjPTable] new table.
3716 **
3717 ** @release 6.4.0
3718 ** @@
3719 **
3720 ******************************************************************************/
3721
ajTableintNew(ajulong size)3722 AjPTable ajTableintNew(ajulong size)
3723 {
3724 AjPTable table = NULL;
3725
3726 table = ajTableNewFunctionLen(size, &ajTableintCmp, &ajTableintHash,
3727 &ajMemFree, NULL);
3728 table->Type = ajETableTypeInt;
3729
3730 return table;
3731 }
3732
3733
3734
3735
3736 /* @func ajTableintNewConst ***************************************************
3737 **
3738 ** Creates, initialises, and returns a new, empty table that can hold a
3739 ** specified number of integer key-value pairs.
3740 **
3741 ** @param [r] size [ajulong] estimate of number of unique keys
3742 **
3743 ** @return [AjPTable] new table.
3744 **
3745 ** @release 6.4.0
3746 ** @@
3747 **
3748 ******************************************************************************/
3749
ajTableintNewConst(ajulong size)3750 AjPTable ajTableintNewConst(ajulong size)
3751 {
3752 AjPTable table = NULL;
3753
3754 table = ajTableNewFunctionLen(size, &ajTableintCmp, &ajTableintHash,
3755 NULL, NULL);
3756 table->Type = ajETableTypeInt;
3757
3758 return table;
3759 }
3760
3761
3762
3763
3764 /* @section Destructors *******************************************************
3765 **
3766 ** @fdata [AjPTable]
3767 **
3768 ** Destructors know they are dealing with strings and can
3769 ** clean up keys and values
3770 **
3771 ** @nam3rule Free Delete table, keys and values
3772 ** @nam4rule FreeKey Delete table, keys and values
3773 **
3774 ** @argrule * Ptable [AjPTable*] Hash table
3775 **
3776 ** @valrule * [void]
3777 **
3778 ** @fcategory delete
3779 **
3780 ******************************************************************************/
3781
3782
3783
3784
3785 /* @func ajTableintFree *******************************************************
3786 **
3787 ** Free keys and value strings in a table and free the table. Use
3788 ** only where the keys and data in the table are real, and not just
3789 ** copies of pointers. Otherwise a call to ajTableFree is enough.
3790 **
3791 ** @param [d] Ptable [AjPTable*] Table
3792 ** @return [void]
3793 **
3794 ** @release 6.4.0
3795 ** @@
3796 ******************************************************************************/
3797
ajTableintFree(AjPTable * Ptable)3798 void ajTableintFree(AjPTable* Ptable)
3799 {
3800 if(!Ptable)
3801 return;
3802
3803 if(!*Ptable)
3804 return;
3805
3806 ajTableMapDel(*Ptable, &tableDel, NULL);
3807
3808 ajTableFree(Ptable);
3809
3810 return;
3811 }
3812
3813
3814
3815
3816 /* @func ajTableintFreeKey ****************************************************
3817 **
3818 ** Free keys and value strings in a table and free the table.
3819 ** Use only where the keys
3820 ** in the table are real, and not just copies of pointers. Otherwise
3821 ** a call to ajTableFree is enough.
3822 **
3823 ** @param [d] Ptable [AjPTable*] Table
3824 ** @return [void]
3825 **
3826 ** @release 6.4.0
3827 ** @@
3828 ******************************************************************************/
3829
ajTableintFreeKey(AjPTable * Ptable)3830 void ajTableintFreeKey(AjPTable* Ptable)
3831 {
3832 if(!Ptable)
3833 return;
3834
3835 if(!*Ptable)
3836 return;
3837
3838 ajTableMapDel(*Ptable, &tableDelKey, NULL);
3839
3840 ajTableFree(Ptable);
3841
3842 return;
3843 }
3844
3845
3846
3847
3848 /* @section Retrieval *********************************************************
3849 **
3850 ** @fdata [AjPTable]
3851 **
3852 ** Retrieves values from a hash table
3853 **
3854 ** @nam3rule Fetch Retrieval function
3855 **
3856 ** @argrule Fetch table [const AjPTable] Hash table
3857 ** @argrule Fetch intkey [const ajint*] Key
3858 **
3859 ** @valrule Fetch [const ajint*] Value
3860 **
3861 ** @fcategory cast
3862 **
3863 ******************************************************************************/
3864
3865
3866
3867
3868 /* @func ajTableintFetch ******************************************************
3869 **
3870 ** returns the value associated with key in table, or null
3871 ** if table does not hold key.
3872 **
3873 ** @param [r] table [const AjPTable] table to search
3874 ** @param [r] intkey [const ajint*] key to find.
3875 ** @return [const ajint*] value associated with key
3876 ** @error NULL if key not found in table.
3877 **
3878 ** @release 6.4.0
3879 ** @@
3880 ******************************************************************************/
3881
ajTableintFetch(const AjPTable table,const ajint * intkey)3882 const ajint* ajTableintFetch(const AjPTable table, const ajint* intkey)
3883 {
3884 ajulong i = 0UL;
3885
3886 AjPTableNode node = NULL;
3887
3888 if(!table)
3889 return NULL;
3890
3891 if(!intkey)
3892 return NULL;
3893
3894 i = (*table->Fhash)(intkey, table->Size);
3895
3896 for(node = table->Buckets[i]; node; node = node->Link)
3897 if((*table->Fcmp)(intkey, node->Key) == 0)
3898 break;
3899
3900 return node ? (const ajint*) node->Value : NULL;
3901 }
3902
3903
3904
3905
3906 /* @section Modify ************************************************************
3907 **
3908 ** @fdata [AjPTable]
3909 **
3910 ** Updates values from a hash table
3911 **
3912 ** @nam3rule Fetchmod Retrieval function
3913 **
3914 ** @argrule * table [AjPTable] Hash table
3915 ** @argrule Fetchmod intkey [const ajint*] Key
3916 **
3917 ** @valrule Fetchmod [ajint*] Value
3918 **
3919 ** @fcategory modify
3920 **
3921 ******************************************************************************/
3922
3923
3924
3925
3926 /* @func ajTableintFetchmod ***************************************************
3927 **
3928 ** returns the value associated with key in table, or null
3929 ** if table does not hold key.
3930 **
3931 ** @param [u] table [AjPTable] table to search
3932 ** @param [r] intkey [const ajint*] key to find.
3933 ** @return [ajint*] value associated with key
3934 ** @error NULL if key not found in table.
3935 **
3936 ** @release 6.4.0
3937 ** @@
3938 ******************************************************************************/
3939
ajTableintFetchmod(AjPTable table,const ajint * intkey)3940 ajint* ajTableintFetchmod(AjPTable table, const ajint* intkey)
3941 {
3942 ajulong i = 0UL;
3943
3944 AjPTableNode node = NULL;
3945
3946 if(!table)
3947 return NULL;
3948
3949 if(!intkey)
3950 return NULL;
3951
3952 i = (*table->Fhash)(intkey, table->Size);
3953
3954 for(node = table->Buckets[i]; node; node = node->Link)
3955 if((*table->Fcmp)(intkey, node->Key) == 0)
3956 break;
3957
3958 return node ? (ajint*) (&node->Value) : NULL;
3959 }
3960
3961
3962
3963
3964 /* @section Comparison functions **********************************************
3965 **
3966 ** @fdata [AjPTable]
3967 **
3968 ** Comparison functions for table keys
3969 **
3970 ** @nam3rule Cmp Comparison
3971 ** @nam3rule Hash Hashing keys
3972 **
3973 ** @argrule Cmp key1 [const void*] First key
3974 ** @argrule Cmp key2 [const void*] Second key
3975 ** @argrule Hash key [const void*] Key
3976 ** @argrule Hash hashsize [ajulong] Hash table size
3977 ** @suffix Case Case insensitive keys
3978 **
3979 ** @valrule Cmp [ajint] Comparison result 0 for a match,
3980 ** -1 or +1 for a mismatch
3981 ** @valrule Hash [ajulong] hash value
3982 **
3983 ** @fcategory misc
3984 **
3985 ******************************************************************************/
3986
3987
3988
3989
3990 /* @func ajTableintCmp ********************************************************
3991 **
3992 ** Comparison function for a table with an integer key
3993 **
3994 ** @param [r] key1 [const void*] First key.
3995 ** @param [r] key2 [const void*] Second key.
3996 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
3997 **
3998 ** @release 6.4.0
3999 ** @@
4000 ******************************************************************************/
4001
ajTableintCmp(const void * key1,const void * key2)4002 ajint ajTableintCmp(const void* key1, const void* key2)
4003 {
4004 return (ajint) (*((const ajint*) key1) != *((const ajint*) key2));
4005 }
4006
4007
4008
4009
4010 /* @func ajTableintHash *******************************************************
4011 **
4012 ** Hash function for a table with an integer key
4013 **
4014 ** @param [r] key [const void*] Standard argument. Table key.
4015 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
4016 ** @return [ajulong] Hash value in range 0 to hashsize-1
4017 **
4018 ** @release 6.4.0
4019 ** @@
4020 ******************************************************************************/
4021
ajTableintHash(const void * key,ajulong hashsize)4022 ajulong ajTableintHash(const void* key, ajulong hashsize)
4023 {
4024 ajulong hash = 0UL;
4025
4026 const ajint* ia = NULL;
4027
4028 if(!key)
4029 return 0;
4030
4031 if(!hashsize)
4032 return 0;
4033
4034 ia = (const ajint*) key;
4035
4036 hash = (*ia >> 2) % hashsize;
4037
4038 return hash;
4039 }
4040
4041
4042
4043
4044 /* @datasection [AjPTable] Long integer hash tables ***************************
4045 **
4046 ** @nam2rule Tablelong Long integer hash tables
4047 **
4048 ******************************************************************************/
4049
4050
4051
4052
4053 /* @section Constructors ******************************************************
4054 **
4055 ** Constructors for hash tables
4056 **
4057 ** @fdata [AjPTable]
4058 **
4059 ** @fcategory new
4060 **
4061 ** @nam3rule New Constructor
4062 ** @suffix Const Constant keys with no destructor
4063 **
4064 ** @argrule New size [ajulong] Number of key values
4065 **
4066 ** @valrule * [AjPTable] New hash table
4067 **
4068 ******************************************************************************/
4069
4070
4071
4072
4073 /* @func ajTablelongNew *******************************************************
4074 **
4075 ** Creates, initialises, and returns a new, empty table that can hold a
4076 ** specified number of long integer key-value pairs.
4077 **
4078 ** @param [r] size [ajulong] estimate of number of unique keys
4079 **
4080 ** @return [AjPTable] new table.
4081 **
4082 ** @release 6.4.0
4083 ** @@
4084 **
4085 ******************************************************************************/
4086
ajTablelongNew(ajulong size)4087 AjPTable ajTablelongNew(ajulong size)
4088 {
4089 AjPTable table = NULL;
4090
4091 table = ajTableNewFunctionLen(size, &ajTablelongCmp, &ajTablelongHash,
4092 &ajMemFree, NULL);
4093 table->Type = ajETableTypeLong;
4094
4095 return table;
4096 }
4097
4098
4099
4100
4101 /* @func ajTablelongNewConst **************************************************
4102 **
4103 ** Creates, initialises, and returns a new, empty table that can hold a
4104 ** specified number of long integer key-value pairs.
4105 **
4106 ** @param [r] size [ajulong] estimate of number of unique keys
4107 **
4108 ** @return [AjPTable] new table.
4109 **
4110 ** @release 6.4.0
4111 ** @@
4112 **
4113 ******************************************************************************/
4114
ajTablelongNewConst(ajulong size)4115 AjPTable ajTablelongNewConst(ajulong size)
4116 {
4117 AjPTable table = NULL;
4118
4119 table = ajTableNewFunctionLen(size, &ajTablelongCmp, &ajTablelongHash,
4120 NULL, NULL);
4121 table->Type = ajETableTypeLong;
4122
4123 return table;
4124 }
4125
4126
4127
4128
4129 /* @section Destructors *******************************************************
4130 **
4131 ** @fdata [AjPTable]
4132 **
4133 ** Destructors know they are dealing with strings and can
4134 ** clean up keys and values
4135 **
4136 ** @nam3rule Free Delete table, keys and values
4137 ** @nam4rule FreeKey Delete table, keys and values
4138 **
4139 ** @argrule * Ptable [AjPTable*] Hash table
4140 **
4141 ** @valrule * [void]
4142 **
4143 ** @fcategory delete
4144 **
4145 ******************************************************************************/
4146
4147
4148
4149
4150 /* @func ajTablelongFree ******************************************************
4151 **
4152 ** Free keys and value strings in a table and free the table. Use
4153 ** only where the keys and data in the table are real, and not just
4154 ** copies of pointers. Otherwise a call to ajTableFree is enough.
4155 **
4156 ** @param [d] Ptable [AjPTable*] Table
4157 ** @return [void]
4158 **
4159 ** @release 6.4.0
4160 ** @@
4161 ******************************************************************************/
4162
ajTablelongFree(AjPTable * Ptable)4163 void ajTablelongFree(AjPTable* Ptable)
4164 {
4165 if(!Ptable)
4166 return;
4167
4168 if(!*Ptable)
4169 return;
4170
4171 ajTableMapDel(*Ptable, &tableDel, NULL);
4172
4173 ajTableFree(Ptable);
4174
4175 return;
4176 }
4177
4178
4179
4180
4181 /* @func ajTablelongFreeKey ***************************************************
4182 **
4183 ** Free keys and value strings in a table and free the table. Use
4184 ** only where the keys in the table are real, and not just copies of
4185 ** pointers. Otherwise a call to ajTableFree is enough.
4186 **
4187 ** @param [d] Ptable [AjPTable*] Table
4188 ** @return [void]
4189 **
4190 ** @release 6.4.0
4191 ** @@
4192 ******************************************************************************/
4193
ajTablelongFreeKey(AjPTable * Ptable)4194 void ajTablelongFreeKey(AjPTable* Ptable)
4195 {
4196 if(!Ptable)
4197 return;
4198
4199 if(!*Ptable)
4200 return;
4201
4202 ajTableMapDel(*Ptable, &tableDelKey, NULL);
4203
4204 ajTableFree(Ptable);
4205
4206 return;
4207 }
4208
4209
4210
4211
4212 /* @section Retrieval *********************************************************
4213 **
4214 ** @fdata [AjPTable]
4215 **
4216 ** Retrieves values from a hash table
4217 **
4218 ** @nam3rule Fetch Retrieval function
4219 **
4220 ** @argrule * table [const AjPTable] Hash table
4221 ** @argrule Fetch longkey [const ajlong*] Key
4222 **
4223 ** @valrule Fetch [const ajlong*] Value
4224 ** @fcategory cast
4225 **
4226 ******************************************************************************/
4227
4228
4229
4230
4231 /* @func ajTablelongFetch *****************************************************
4232 **
4233 ** returns the value associated with key in table, or null
4234 ** if table does not hold key.
4235 **
4236 ** @param [r] table [const AjPTable] table to search
4237 ** @param [r] longkey [const ajlong*] key to find.
4238 ** @return [const ajlong*] value associated with key
4239 ** @error NULL if key not found in table.
4240 **
4241 ** @release 6.4.0
4242 ** @@
4243 ******************************************************************************/
4244
ajTablelongFetch(const AjPTable table,const ajlong * longkey)4245 const ajlong* ajTablelongFetch(const AjPTable table, const ajlong* longkey)
4246 {
4247 ajulong i = 0UL;
4248
4249 AjPTableNode node = NULL;
4250
4251 if(!table)
4252 return NULL;
4253
4254 if(!longkey)
4255 return NULL;
4256
4257 i = (*table->Fhash)(longkey, table->Size);
4258
4259 for(node = table->Buckets[i]; node; node = node->Link)
4260 if((*table->Fcmp)(longkey, node->Key) == 0)
4261 break;
4262
4263 return node ? (const ajlong*) node->Value : NULL;
4264 }
4265
4266
4267
4268
4269 /* @section Modify ************************************************************
4270 **
4271 ** @fdata [AjPTable]
4272 **
4273 ** Updates values from a hash table
4274 **
4275 ** @nam3rule Fetchmod Retrieval function
4276 **
4277 ** @argrule * table [AjPTable] Hash table
4278 ** @argrule Fetchmod longkey [const ajlong*] Key
4279 **
4280 ** @valrule Fetchmod [ajlong*] Value
4281 **
4282 ** @fcategory modify
4283 **
4284 ******************************************************************************/
4285
4286
4287
4288
4289 /* @func ajTablelongFetchmod **************************************************
4290 **
4291 ** returns the value associated with key in table, or null
4292 ** if table does not hold key.
4293 **
4294 ** @param [u] table [AjPTable] table to search
4295 ** @param [r] longkey [const ajlong*] key to find.
4296 ** @return [ajlong*] value associated with key
4297 ** @error NULL if key not found in table.
4298 **
4299 ** @release 6.4.0
4300 ** @@
4301 ******************************************************************************/
4302
ajTablelongFetchmod(AjPTable table,const ajlong * longkey)4303 ajlong* ajTablelongFetchmod(AjPTable table, const ajlong* longkey)
4304 {
4305 ajulong i = 0UL;
4306
4307 AjPTableNode node = NULL;
4308
4309 if(!table)
4310 return NULL;
4311
4312 if(!longkey)
4313 return NULL;
4314
4315 i = (*table->Fhash)(longkey, table->Size);
4316
4317 for(node = table->Buckets[i]; node; node = node->Link)
4318 if((*table->Fcmp)(longkey, node->Key) == 0)
4319 break;
4320
4321 return node ? (ajlong*) (&node->Value) : NULL;
4322 }
4323
4324
4325
4326
4327 /* @section Comparison functions **********************************************
4328 **
4329 ** @fdata [AjPTable]
4330 **
4331 ** Comparison functions for table keys
4332 **
4333 ** @nam3rule Cmp Comparison
4334 ** @nam3rule Hash Hashing keys
4335 **
4336 ** @argrule Cmp key1 [const void*] First key
4337 ** @argrule Cmp key2 [const void*] Second key
4338 ** @argrule Hash key [const void*] Key
4339 ** @argrule Hash hashsize [ajulong] Hash table size
4340 ** @suffix Case Case insensitive keys
4341 **
4342 ** @valrule Cmp [ajint] Comparison result 0 for a match,
4343 ** -1 or +1 for a mismatch
4344 ** @valrule Hash [ajulong] hash value
4345 **
4346 ** @fcategory misc
4347 **
4348 ******************************************************************************/
4349
4350
4351
4352
4353 /* @func ajTablelongCmp *******************************************************
4354 **
4355 ** Comparison function for a table with a long integer key
4356 **
4357 ** @param [r] key1 [const void*] First key.
4358 ** @param [r] key2 [const void*] Second key.
4359 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
4360 **
4361 ** @release 6.4.0
4362 ** @@
4363 ******************************************************************************/
4364
ajTablelongCmp(const void * key1,const void * key2)4365 ajint ajTablelongCmp(const void* key1, const void* key2)
4366 {
4367 return (ajint) (*((const ajlong*) key1) != *((const ajlong*) key2));
4368 }
4369
4370
4371
4372
4373 /* @func ajTablelongHash ******************************************************
4374 **
4375 ** Hash function for a table with a long integer key
4376 **
4377 ** @param [r] key [const void*] Standard argument. Table key.
4378 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
4379 ** @return [ajulong] Hash value in range 0 to hashsize-1
4380 **
4381 ** @release 6.4.0
4382 ** @@
4383 ******************************************************************************/
4384
ajTablelongHash(const void * key,ajulong hashsize)4385 ajulong ajTablelongHash(const void* key, ajulong hashsize)
4386 {
4387 ajulong hash = 0UL;
4388
4389 const ajlong* ia = NULL;
4390
4391 if(!key)
4392 return 0;
4393
4394 if(!hashsize)
4395 return 0;
4396
4397 ia = (const ajlong*) key;
4398
4399 hash = (*ia >> 2) % hashsize;
4400
4401 return hash;
4402 }
4403
4404
4405
4406
4407 /* @datasection [AjPTable] String hash tables *********************************
4408 **
4409 ** @nam2rule Tablestr String hash tables
4410 **
4411 ******************************************************************************/
4412
4413
4414
4415
4416 /* @section Constructors ******************************************************
4417 **
4418 ** Constructors for hash tables
4419 **
4420 ** @fdata [AjPTable]
4421 **
4422 ** @fcategory new
4423 **
4424 ** @nam3rule New Constructor
4425 ** @nam4rule Case Case-sensitive keys
4426 ** @suffix Const Constant keys with no destructor
4427 **
4428 ** @argrule New size [ajulong] Number of key values
4429 **
4430 ** @valrule * [AjPTable] New hash table
4431 **
4432 ******************************************************************************/
4433
4434
4435
4436
4437 /* @func ajTablestrNew ********************************************************
4438 **
4439 ** Creates, initialises, and returns a new, empty table that can hold a
4440 ** specified number of key-value pairs.
4441 **
4442 ** @param [r] size [ajulong] estimate of number of unique keys
4443 **
4444 ** @return [AjPTable] new table.
4445 **
4446 ** @release 5.0.0
4447 ** @@
4448 **
4449 ******************************************************************************/
4450
ajTablestrNew(ajulong size)4451 AjPTable ajTablestrNew(ajulong size)
4452 {
4453 AjPTable table = NULL;
4454
4455 table = ajTableNewFunctionLen(size, &ajTablestrCmp, &ajTablestrHash,
4456 &tableDelStr, NULL);
4457 table->Type = ajETableTypeStr;
4458
4459 return table;
4460 }
4461
4462
4463
4464
4465 /* @func ajTablestrNewCase ****************************************************
4466 **
4467 ** Creates, initialises, and returns a new, empty table that can hold a
4468 ** specified number of key-value pairs.
4469 **
4470 ** @param [r] size [ajulong] estimate of number of unique keys
4471 **
4472 ** @return [AjPTable] new table.
4473 **
4474 ** @release 5.0.0
4475 ** @@
4476 **
4477 ******************************************************************************/
4478
ajTablestrNewCase(ajulong size)4479 AjPTable ajTablestrNewCase(ajulong size)
4480 {
4481 AjPTable table = NULL;
4482
4483 table = ajTableNewFunctionLen(size, &ajTablestrCmpCase, &ajTablestrHashCase,
4484 &tableDelStr, NULL);
4485 table->Type = ajETableTypeStr;
4486
4487 return table;
4488 }
4489
4490
4491
4492
4493 /* @func ajTablestrNewCaseConst ***********************************************
4494 **
4495 ** Creates, initialises, and returns a new, empty table that can hold a
4496 ** specified number of key-value pairs.
4497 **
4498 ** @param [r] size [ajulong] estimate of number of unique keys
4499 **
4500 ** @return [AjPTable] new table.
4501 **
4502 ** @release 6.4.0
4503 ** @@
4504 **
4505 ******************************************************************************/
4506
ajTablestrNewCaseConst(ajulong size)4507 AjPTable ajTablestrNewCaseConst(ajulong size)
4508 {
4509 AjPTable table = NULL;
4510
4511 table = ajTableNewFunctionLen(size, &ajTablestrCmpCase, &ajTablestrHashCase,
4512 NULL, NULL);
4513 table->Type = ajETableTypeStr;
4514
4515 return table;
4516 }
4517
4518
4519
4520
4521 /* @func ajTablestrNewConst ***************************************************
4522 **
4523 ** Creates, initialises, and returns a new, empty table that can hold a
4524 ** specified number of key-value pairs.
4525 **
4526 ** @param [r] size [ajulong] estimate of number of unique keys
4527 **
4528 ** @return [AjPTable] new table.
4529 **
4530 ** @release 6.4.0
4531 ** @@
4532 **
4533 ******************************************************************************/
4534
ajTablestrNewConst(ajulong size)4535 AjPTable ajTablestrNewConst(ajulong size)
4536 {
4537 AjPTable table = NULL;
4538
4539 table = ajTableNewFunctionLen(size, &ajTablestrCmp, &ajTablestrHash,
4540 NULL, NULL);
4541 table->Type = ajETableTypeStr;
4542
4543 return table;
4544 }
4545
4546
4547
4548
4549 /* @section Destructors *******************************************************
4550 **
4551 ** @fdata [AjPTable]
4552 **
4553 ** Destructors know they are dealing with strings and can
4554 ** clean up keys and values
4555 **
4556 ** @nam3rule Free Delete table, keys and values
4557 ** @nam4rule FreeKey Delete table, keys and values
4558 **
4559 ** @argrule * Ptable [AjPTable*] Hash table
4560 **
4561 ** @valrule * [void]
4562 **
4563 ** @fcategory delete
4564 **
4565 ******************************************************************************/
4566
4567
4568
4569
4570 /* @func ajTablestrFree *******************************************************
4571 **
4572 ** Free keys and value strings in a table and free the table.
4573 ** Use only where the keys and strings
4574 ** in the table are real, and not just copies of pointers. Otherwise
4575 ** a call to ajTableFree is enough.
4576 **
4577 ** @param [d] Ptable [AjPTable*] Table
4578 ** @return [void]
4579 **
4580 ** @release 5.0.0
4581 ** @@
4582 ******************************************************************************/
4583
ajTablestrFree(AjPTable * Ptable)4584 void ajTablestrFree(AjPTable* Ptable)
4585 {
4586 if(!Ptable)
4587 return;
4588
4589 if(!*Ptable)
4590 return;
4591
4592 ajTableMapDel(*Ptable, &tableStrDel, NULL);
4593
4594 ajTableFree(Ptable);
4595
4596 return;
4597 }
4598
4599
4600
4601
4602 /* @func ajTablestrFreeKey ****************************************************
4603 **
4604 ** Free string keys in a table and free the table. Do not free the values.
4605 ** Use only where the keys
4606 ** in the table are real strings, and not just copies of pointers. Otherwise
4607 ** a call to ajTableFree is enough. The data is simply freed.
4608 **
4609 ** @param [d] Ptable [AjPTable*] Table
4610 ** @return [void]
4611 **
4612 ** @release 5.0.0
4613 ** @@
4614 ******************************************************************************/
4615
ajTablestrFreeKey(AjPTable * Ptable)4616 void ajTablestrFreeKey(AjPTable* Ptable)
4617 {
4618 if(!*Ptable)
4619 return;
4620
4621 ajTableMapDel(*Ptable, &tableStrDelKey, NULL);
4622
4623 ajTableFree(Ptable);
4624
4625 return;
4626 }
4627
4628
4629
4630
4631 /* @funcstatic tableStrDel ****************************************************
4632 **
4633 ** Delete an entry in a string table.
4634 **
4635 ** @param [d] Pkey [void**] AJAX String key address.
4636 ** @param [d] Pvalue [void**] AJAX String value address.
4637 ** @param [u] cl [void*] Standard argument. Usually NULL.
4638 ** @return [void]
4639 **
4640 ** @release 1.0.0
4641 ** @@
4642 ******************************************************************************/
4643
tableStrDel(void ** Pkey,void ** Pvalue,void * cl)4644 static void tableStrDel(void** Pkey, void** Pvalue, void* cl)
4645 {
4646 (void) cl;
4647
4648 ajStrDel((AjPStr*) Pvalue);
4649 ajStrDel((AjPStr*) Pkey);
4650
4651 *Pkey = NULL;
4652 *Pvalue = NULL;
4653
4654 return;
4655 }
4656
4657
4658
4659
4660 /* @funcstatic tableStrDelKey *************************************************
4661 **
4662 ** Delete an entry in a table with a string key and ignore the value.
4663 **
4664 ** @param [d] Pkey [void**] AJAX String key address.
4665 ** @param [d] Pvalue [void**] Value address.
4666 ** @param [u] cl [void*] Standard argument. Usually NULL.
4667 ** @return [void]
4668 **
4669 ** @release 5.0.0
4670 ** @@
4671 ******************************************************************************/
4672
tableStrDelKey(void ** Pkey,void ** Pvalue,void * cl)4673 static void tableStrDelKey(void** Pkey, void** Pvalue, void* cl)
4674 {
4675 (void) cl;
4676
4677 ajStrDel((AjPStr*) Pkey);
4678
4679 *Pkey = NULL;
4680 *Pvalue = NULL;
4681
4682 return;
4683 }
4684
4685
4686
4687
4688 /* @section Retrieval *********************************************************
4689 **
4690 ** @fdata [AjPTable]
4691 **
4692 ** Retrieves values from a hash table
4693 **
4694 ** @nam3rule Fetch Retrieval function for string values
4695 ** @nam3rule Fetchkey Retrieval function for string keys
4696 ** @suffix C [char*] C character string
4697 ** @suffix S [AjPStr] string object
4698 **
4699 ** @argrule * table [const AjPTable] Hash table
4700 ** @argrule *C txtkey [const char*] Key
4701 ** @argrule *S key [const AjPStr] Key
4702 **
4703 ** @valrule Fetch [void*] Value
4704 ** @valrule Fetchkey [const AjPStr] Value
4705 **
4706 ** @fcategory cast
4707 **
4708 ******************************************************************************/
4709
4710
4711
4712
4713 /* @func ajTablestrFetchC *****************************************************
4714 **
4715 ** returns the value associated with key in table, or null
4716 ** if table does not hold key.
4717 **
4718 ** @param [r] table [const AjPTable] table to search
4719 ** @param [r] txtkey [const char*] key to find.
4720 ** @return [void*] value associated with key
4721 ** @error NULL if key not found in table.
4722 **
4723 ** @release 6.4.0
4724 ** @@
4725 ******************************************************************************/
4726
ajTablestrFetchC(const AjPTable table,const char * txtkey)4727 void* ajTablestrFetchC(const AjPTable table, const char* txtkey)
4728 {
4729 ajulong i = 0UL;
4730
4731 AjPTableNode node = NULL;
4732
4733 ajStrAssignC(&tableTmpkeyStr, txtkey);
4734
4735 if(!table)
4736 return NULL;
4737
4738 if(!txtkey)
4739 return NULL;
4740
4741 i = (*table->Fhash)(tableTmpkeyStr, table->Size);
4742
4743 for(node = table->Buckets[i]; node; node = node->Link)
4744 if((*table->Fcmp)(tableTmpkeyStr, node->Key) == 0)
4745 break;
4746
4747 return node ? node->Value : NULL;
4748 }
4749
4750
4751
4752
4753 /* @func ajTablestrFetchS *****************************************************
4754 **
4755 ** returns the value associated with key in table, or null
4756 ** if table does not hold key.
4757 **
4758 ** @param [r] table [const AjPTable] table to search
4759 ** @param [r] key [const AjPStr] key to find.
4760 ** @return [void*] value associated with key
4761 ** @error NULL if key not found in table.
4762 **
4763 ** @release 6.4.0
4764 ** @@
4765 ******************************************************************************/
4766
ajTablestrFetchS(const AjPTable table,const AjPStr key)4767 void* ajTablestrFetchS(const AjPTable table, const AjPStr key)
4768 {
4769 ajulong i = 0UL;
4770
4771 AjPTableNode node = NULL;
4772
4773 if(!table)
4774 return NULL;
4775
4776 if(!key)
4777 return NULL;
4778
4779 i = (*table->Fhash)(key, table->Size);
4780
4781 for(node = table->Buckets[i]; node; node = node->Link)
4782 if((*table->Fcmp)(key, node->Key) == 0)
4783 break;
4784
4785 return node ? node->Value : NULL;
4786 }
4787
4788
4789
4790
4791 /* @func ajTablestrFetchkeyC **************************************************
4792 **
4793 ** returns the key value associated with key in table, or null
4794 ** if table does not hold key.
4795 **
4796 ** Intended for case-insensitive keys, to return the true key
4797 **
4798 ** @param [r] table [const AjPTable] table to search
4799 ** @param [r] txtkey [const char*] key to find.
4800 ** @return [const AjPStr] key value as stored in the table
4801 ** @error NULL if key not found in table.
4802 **
4803 ** @release 6.4.0
4804 ** @@
4805 ******************************************************************************/
4806
ajTablestrFetchkeyC(const AjPTable table,const char * txtkey)4807 const AjPStr ajTablestrFetchkeyC(const AjPTable table, const char* txtkey)
4808 {
4809 ajulong i = 0UL;
4810
4811 const AjPTableNode node = NULL;
4812
4813 if(!table)
4814 return NULL;
4815
4816 if(!txtkey)
4817 return NULL;
4818
4819 if(table->Type == ajETableTypeStr)
4820 {
4821 ajStrAssignC(&tableTmpkeyStr, txtkey);
4822 return ajTablestrFetchkeyS(table, tableTmpkeyStr);
4823 }
4824
4825 if(table->Type != ajETableTypeChar)
4826 ajFatal("ajTablestrFetchkeyC called for %s table", tableType(table));
4827
4828 i = (*table->Fhash)(txtkey, table->Size);
4829
4830 for(node = table->Buckets[i]; node; node = node->Link)
4831 if((*table->Fcmp)(txtkey, node->Key) == 0)
4832 break;
4833
4834 return node ? (const void*) node->Key : NULL;
4835 }
4836
4837
4838
4839
4840 /* @func ajTablestrFetchkeyS **************************************************
4841 **
4842 ** returns the key value associated with key in table, or null
4843 ** if table does not hold key.
4844 **
4845 ** Intended for case-insensitive keys, to return the true key
4846 **
4847 ** @param [r] table [const AjPTable] table to search
4848 ** @param [r] key [const AjPStr] key to find.
4849 ** @return [const AjPStr] key value as stored in the table
4850 ** @error NULL if key not found in table.
4851 **
4852 ** @release 6.4.0
4853 ** @@
4854 ******************************************************************************/
4855
ajTablestrFetchkeyS(const AjPTable table,const AjPStr key)4856 const AjPStr ajTablestrFetchkeyS(const AjPTable table, const AjPStr key)
4857 {
4858 ajulong i = 0UL;
4859
4860 const AjPTableNode node = NULL;
4861
4862 if(!table)
4863 return NULL;
4864
4865 if(!key)
4866 return NULL;
4867
4868 if(table->Type == ajETableTypeChar)
4869 {
4870 return ajTablestrFetchkeyC(table, MAJSTRGETPTR(key));
4871 }
4872
4873 if(table->Type != ajETableTypeStr)
4874 ajFatal("ajTablestrFetchkeyS called for %s table", tableType(table));
4875
4876 i = (*table->Fhash)(key, table->Size);
4877
4878 for(node = table->Buckets[i]; node; node = node->Link)
4879 if((*table->Fcmp)(key, node->Key) == 0)
4880 break;
4881
4882 return node ? (const void*) node->Key : NULL;
4883 }
4884
4885
4886
4887
4888 /* @funcstatic tableType ******************************************************
4889 **
4890 ** returns the name of a table type.
4891 **
4892 ** @param [r] table [const AjPTable] table type
4893 ** @return [const char*] Name of table type
4894 **
4895 ** @release 6.4.0
4896 ** @@
4897 ******************************************************************************/
4898
tableType(const AjPTable table)4899 static const char* tableType(const AjPTable table)
4900 {
4901 const char* typenames[] = {"unknown", "char", "string",
4902 "int", "uint", "long", "ulong", "user", NULL};
4903 ajint i = table->Type;
4904
4905 if(i < ajETableTypeUnknown || i >= ajETableTypeMax)
4906 return "unknown";
4907
4908 return typenames[i];
4909 }
4910
4911
4912
4913
4914 /* @section Modify ************************************************************
4915 **
4916 ** @fdata [AjPTable]
4917 **
4918 ** Updates values from a hash table
4919 **
4920 ** @nam3rule Fetchmod Retrieval function
4921 **
4922 ** @argrule * table [AjPTable] Hash table
4923 ** @argrule Fetchmod key [const AjPStr] Key
4924 **
4925 ** @valrule Fetchmod [AjPStr*] Value
4926 **
4927 ** @fcategory modify
4928 **
4929 ******************************************************************************/
4930
4931
4932
4933
4934 /* @func ajTablestrFetchmod ***************************************************
4935 **
4936 ** returns the value associated with key in table, or null
4937 ** if table does not hold key.
4938 **
4939 ** @param [u] table [AjPTable] table to search
4940 ** @param [r] key [const AjPStr] key to find.
4941 ** @return [AjPStr*] value associated with key
4942 ** @error NULL if key not found in table.
4943 **
4944 ** @release 6.0.0
4945 ** @@
4946 ******************************************************************************/
4947
ajTablestrFetchmod(AjPTable table,const AjPStr key)4948 AjPStr* ajTablestrFetchmod(AjPTable table, const AjPStr key)
4949 {
4950 ajulong i = 0UL;
4951
4952 AjPTableNode node = NULL;
4953
4954 if(!table)
4955 return NULL;
4956
4957 if(!key)
4958 return NULL;
4959
4960 i = (*table->Fhash)(key, table->Size);
4961
4962 for(node = table->Buckets[i]; node; node = node->Link)
4963 if((*table->Fcmp)(key, node->Key) == 0)
4964 break;
4965
4966 return node ? (AjPStr*) (&node->Value) : NULL;
4967 }
4968
4969
4970
4971
4972 /* @section Comparison functions **********************************************
4973 **
4974 ** @fdata [AjPTable]
4975 **
4976 ** Comparison functions for table keys
4977 **
4978 ** @nam3rule Cmp Comparison
4979 ** @nam3rule Hash Hashing keys
4980 **
4981 ** @argrule Cmp key1 [const void*] First key
4982 ** @argrule Cmp key2 [const void*] Second key
4983 ** @argrule Hash key [const void*] Key
4984 ** @argrule Hash hashsize [ajulong] Hash table size
4985 ** @suffix Case Case insensitive keys
4986 **
4987 ** @valrule Cmp [ajint] Comparison result 0 for a match,
4988 ** -1 or +1 for a mismatch
4989 ** @valrule Hash [ajulong] hash value
4990 **
4991 ** @fcategory misc
4992 **
4993 ******************************************************************************/
4994
4995
4996
4997
4998 /* @func ajTablestrCmp ********************************************************
4999 **
5000 ** Comparison function for a table with a string key
5001 **
5002 ** @param [r] key1 [const void*] First key.
5003 ** @param [r] key2 [const void*] Second key.
5004 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
5005 **
5006 ** @release 5.0.0
5007 ** @@
5008 ******************************************************************************/
5009
ajTablestrCmp(const void * key1,const void * key2)5010 ajint ajTablestrCmp(const void* key1, const void* key2)
5011 {
5012 return (ajint) ajStrCmpS((const AjPStr) key1, (const AjPStr) key2);
5013 }
5014
5015
5016
5017
5018 /* @func ajTablestrCmpCase ****************************************************
5019 **
5020 ** Comparison function for a table with a string key
5021 ** and case insensitivity.
5022 **
5023 ** @param [r] key1 [const void*] First key.
5024 ** @param [r] key2 [const void*] Second key.
5025 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
5026 **
5027 ** @release 5.0.0
5028 ** @@
5029 ******************************************************************************/
5030
ajTablestrCmpCase(const void * key1,const void * key2)5031 ajint ajTablestrCmpCase(const void* key1, const void* key2)
5032 {
5033 return (ajint) ajStrCmpCaseS((const AjPStr) key1, (const AjPStr) key2);
5034 }
5035
5036
5037
5038
5039 /* @func ajTablestrHash *******************************************************
5040 **
5041 ** Hash function for a table with a string key
5042 **
5043 ** @param [r] key [const void*] Standard argument. Table key.
5044 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
5045 ** @return [ajulong] Hash value in range 0 to hashsize-1
5046 **
5047 ** @release 5.0.0
5048 ** @@
5049 ******************************************************************************/
5050
ajTablestrHash(const void * key,ajulong hashsize)5051 ajulong ajTablestrHash(const void* key, ajulong hashsize)
5052 {
5053 ajulong hash = 0UL;
5054
5055 const char* s = NULL;
5056
5057 const AjPStr str = NULL;
5058
5059 str = (const AjPStr) key;
5060 s = ajStrGetPtr(str);
5061
5062 for(hash = 0; *s; s++)
5063 hash = (hash * 127 + *s) % hashsize;
5064
5065 return hash;
5066 }
5067
5068
5069
5070
5071 /* @func ajTablestrHashCase ***************************************************
5072 **
5073 ** Hash function for a table with a string key and
5074 ** case insensitivity.
5075 **
5076 ** @param [r] key [const void*] Standard argument. Table key.
5077 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
5078 ** @return [ajulong] Hash value in range 0 to hashsize-1
5079 **
5080 ** @release 5.0.0
5081 ** @@
5082 ******************************************************************************/
5083
ajTablestrHashCase(const void * key,ajulong hashsize)5084 ajulong ajTablestrHashCase(const void* key, ajulong hashsize)
5085 {
5086 ajulong hash = 0UL;
5087
5088 const char* s = NULL;
5089
5090 const AjPStr str = NULL;
5091
5092 str = (const AjPStr) key;
5093 s = ajStrGetPtr(str);
5094
5095 for(hash = 0; *s; s++)
5096 hash = (hash * 127 + toupper((ajint)*s)) % hashsize;
5097
5098 return hash;
5099 }
5100
5101
5102
5103
5104 /* @section Trace functions ***************************************************
5105 **
5106 ** @fdata [AjPTable]
5107 **
5108 ** @nam3rule Print Trace contents to standard error
5109 ** @nam3rule Trace Trace contents to debug file
5110 ** @nam3rule Tracekeys Trace keys only to debug file
5111 **
5112 ** @argrule * table [const AjPTable] Hash table
5113 **
5114 ** @valrule * [void]
5115 **
5116 ** @fcategory misc
5117 **
5118 ******************************************************************************/
5119
5120
5121
5122
5123 /* @section Trace functions ***************************************************
5124 **
5125 ** @fdata [AjPTable]
5126 **
5127 ** @nam3rule Print Trace contents to standard error
5128 ** @nam3rule Trace Trace contents to debug file
5129 ** @nam3rule Tracekeys Trace keys only to debug file
5130 **
5131 ** @argrule * table [const AjPTable] Hash table
5132 **
5133 ** @valrule * [void]
5134 **
5135 ** @fcategory misc
5136 **
5137 ******************************************************************************/
5138
5139
5140
5141
5142 /* @func ajTablestrPrint ******************************************************
5143 **
5144 ** Print function for a table with a string key.
5145 **
5146 ** @param [r] table [const AjPTable] Table.
5147 ** @return [void]
5148 **
5149 ** @release 5.0.0
5150 ** @@
5151 ******************************************************************************/
5152
ajTablestrPrint(const AjPTable table)5153 void ajTablestrPrint(const AjPTable table)
5154 {
5155 ajulong i = 0UL;
5156
5157 AjPTableNode node = NULL;
5158
5159 if(!table)
5160 return;
5161
5162 for(i = 0; i < table->Size; i++)
5163 for(node = table->Buckets[i]; node; node = node->Link)
5164 ajUser("key '%S' value '%S'",
5165 (const AjPStr) node->Key, (AjPStr) node->Value);
5166
5167 return;
5168 }
5169
5170
5171
5172
5173 /* @func ajTablestrTrace ******************************************************
5174 **
5175 ** Writes debug messages to trace the contents of a table,
5176 ** assuming all keys and values are strings.
5177 **
5178 ** @param [r] table [const AjPTable] Table
5179 ** @return [void]
5180 **
5181 ** @release 5.0.0
5182 ** @@
5183 ******************************************************************************/
5184
ajTablestrTrace(const AjPTable table)5185 void ajTablestrTrace(const AjPTable table)
5186 {
5187 ajulong i = 0UL;
5188 ajulong j = 0UL;
5189 ajulong k = 0UL;
5190
5191 AjPTableNode node = NULL;
5192
5193 if(!table)
5194 return;
5195
5196 ajDebug("(string) table trace: ");
5197 ajDebug(" length: %Lu", table->Length);
5198 ajDebug(" size: %Lu", table->Size);
5199 ajDebug(" timestamp: %u\n", table->Timestamp);
5200
5201 for(i = 0UL; i < table->Size; i++)
5202 if(table->Buckets[i])
5203 {
5204 j = 0UL;
5205 ajDebug("buckets[%Lu]\n", i);
5206
5207 for(node = table->Buckets[i]; node; node = node->Link)
5208 {
5209 ajDebug(" '%S' => '%S'\n",
5210 (const AjPStr) node->Key, (AjPStr) node->Value);
5211 j++;
5212 }
5213
5214 k += j;
5215 }
5216
5217 ajDebug(" links: %Lu\n", k);
5218
5219 return;
5220 }
5221
5222
5223
5224
5225 /* @func ajTablestrTracekeys **************************************************
5226 **
5227 ** Writes debug messages to trace the keys of a string table,
5228 ** assuming all keys and values are strings.
5229 **
5230 ** @param [r] table [const AjPTable] Table
5231 ** @return [void]
5232 **
5233 ** @release 6.4.0
5234 ** @@
5235 ******************************************************************************/
5236
ajTablestrTracekeys(const AjPTable table)5237 void ajTablestrTracekeys(const AjPTable table)
5238 {
5239 ajulong i = 0UL;
5240 ajulong j = 0UL;
5241 ajulong k = 0UL;
5242
5243 AjPTableNode node = NULL;
5244
5245 if(!table)
5246 return;
5247
5248 ajDebug("(string) table trace: ");
5249 ajDebug(" length: %Lu", table->Length);
5250 ajDebug(" size: %Lu", table->Size);
5251 ajDebug(" timestamp: %u\n", table->Timestamp);
5252
5253 for(i = 0UL; i < table->Size; i++)
5254 if(table->Buckets[i])
5255 {
5256 j = 0UL;
5257 ajDebug("buckets[%Lu]\n", i);
5258
5259 for(node = table->Buckets[i]; node; node = node->Link)
5260 {
5261 ajDebug(" '%S' => '%xS\n",
5262 (const AjPStr) node->Key, node->Value);
5263 j++;
5264 }
5265
5266 k += j;
5267 }
5268
5269 ajDebug(" links: %Lu\n", k);
5270
5271 return;
5272 }
5273
5274
5275
5276
5277 /* @datasection [AjPTable] Unsigned integer hash tables ***********************
5278 **
5279 ** @nam2rule Tableuint Unsigned integer hash tables
5280 **
5281 ******************************************************************************/
5282
5283
5284
5285
5286 /* @section Constructors ******************************************************
5287 **
5288 ** Constructors for hash tables
5289 **
5290 ** @fdata [AjPTable]
5291 **
5292 ** @fcategory new
5293 **
5294 ** @nam3rule New Constructor
5295 ** @suffix Const Constant keys with no destructor
5296 **
5297 ** @argrule New size [ajulong] Number of key values
5298 **
5299 ** @valrule * [AjPTable] New hash table
5300 **
5301 ******************************************************************************/
5302
5303
5304
5305
5306 /* @func ajTableuintNew *******************************************************
5307 **
5308 ** Creates, initialises, and returns a new, empty table that can hold a
5309 ** specified number of unsigned integer key-value pairs.
5310 **
5311 ** @param [r] size [ajulong] estimate of number of unique keys
5312 **
5313 ** @return [AjPTable] new table.
5314 **
5315 ** @release 6.4.0
5316 ** @@
5317 **
5318 ******************************************************************************/
5319
ajTableuintNew(ajulong size)5320 AjPTable ajTableuintNew(ajulong size)
5321 {
5322 AjPTable table = NULL;
5323
5324 table = ajTableNewFunctionLen(size, &ajTableuintCmp, &ajTableuintHash,
5325 &ajMemFree, NULL);
5326 table->Type = ajETableTypeUint;
5327
5328 return table;
5329 }
5330
5331
5332
5333
5334 /* @func ajTableuintNewConst **************************************************
5335 **
5336 ** Creates, initialises, and returns a new, empty table that can hold a
5337 ** specified number of unsigned integer key-value pairs.
5338 **
5339 ** @param [r] size [ajulong] estimate of number of unique keys
5340 **
5341 ** @return [AjPTable] new table.
5342 **
5343 ** @release 6.4.0
5344 ** @@
5345 **
5346 ******************************************************************************/
5347
ajTableuintNewConst(ajulong size)5348 AjPTable ajTableuintNewConst(ajulong size)
5349 {
5350 AjPTable table = NULL;
5351
5352 table = ajTableNewFunctionLen(size, &ajTableuintCmp, &ajTableuintHash,
5353 NULL, NULL);
5354 table->Type = ajETableTypeUint;
5355
5356 return table;
5357 }
5358
5359
5360
5361
5362 /* @section Destructors *******************************************************
5363 **
5364 ** @fdata [AjPTable]
5365 **
5366 ** Destructors know they are dealing with strings and can clean up
5367 ** keys and values
5368 **
5369 ** @nam3rule Free Delete table, keys and values
5370 ** @nam4rule FreeKey Delete table, keys and values
5371 **
5372 ** @argrule * Ptable [AjPTable*] Hash table
5373 **
5374 ** @valrule * [void]
5375 **
5376 ** @fcategory delete
5377 **
5378 ******************************************************************************/
5379
5380
5381
5382
5383 /* @func ajTableuintFree ******************************************************
5384 **
5385 ** Free keys and value strings in a table and free the table.
5386 ** Use only where the keys and data
5387 ** in the table are real, and not just copies of pointers. Otherwise
5388 ** a call to ajTableFree is enough.
5389 **
5390 ** @param [d] Ptable [AjPTable*] Table
5391 ** @return [void]
5392 **
5393 ** @release 6.4.0
5394 ** @@
5395 ******************************************************************************/
5396
ajTableuintFree(AjPTable * Ptable)5397 void ajTableuintFree(AjPTable* Ptable)
5398 {
5399 if(!Ptable)
5400 return;
5401
5402 if(!*Ptable)
5403 return;
5404
5405 ajTableMapDel(*Ptable, &tableDel, NULL);
5406
5407 ajTableFree(Ptable);
5408
5409 return;
5410 }
5411
5412
5413
5414
5415 /* @func ajTableuintFreeKey ***************************************************
5416 **
5417 ** Free keys and value strings in a table and free the table.
5418 ** Use only where the keys
5419 ** in the table are real, and not just copies of pointers. Otherwise
5420 ** a call to ajTableFree is enough.
5421 **
5422 ** @param [d] Ptable [AjPTable*] Table
5423 ** @return [void]
5424 **
5425 ** @release 6.4.0
5426 ** @@
5427 ******************************************************************************/
5428
ajTableuintFreeKey(AjPTable * Ptable)5429 void ajTableuintFreeKey(AjPTable* Ptable)
5430 {
5431 if(!Ptable)
5432 return;
5433
5434 if(!*Ptable)
5435 return;
5436
5437 ajTableMapDel(*Ptable, &tableDelKey, NULL);
5438
5439 ajTableFree(Ptable);
5440
5441 return;
5442 }
5443
5444
5445
5446
5447 /* @section Retrieval *********************************************************
5448 **
5449 ** @fdata [AjPTable]
5450 **
5451 ** Retrieves values from a hash table
5452 **
5453 ** @nam3rule Fetch Retrieval function
5454 **
5455 ** @argrule * table [const AjPTable] Hash table
5456 ** @argrule Fetch uintkey [const ajuint*] Key
5457 **
5458 ** @valrule Fetch [const ajuint*] Value
5459 ** @fcategory cast
5460 **
5461 ******************************************************************************/
5462
5463
5464
5465
5466 /* @func ajTableuintFetch *****************************************************
5467 **
5468 ** returns the value associated with key in table, or null
5469 ** if table does not hold key.
5470 **
5471 ** @param [r] table [const AjPTable] table to search
5472 ** @param [r] uintkey [const ajuint*] key to find.
5473 ** @return [const ajuint*] value associated with key
5474 ** @error NULL if key not found in table.
5475 **
5476 ** @release 6.4.0
5477 ** @@
5478 ******************************************************************************/
5479
ajTableuintFetch(const AjPTable table,const ajuint * uintkey)5480 const ajuint* ajTableuintFetch(const AjPTable table, const ajuint* uintkey)
5481 {
5482 ajulong i = 0UL;
5483
5484 AjPTableNode node = NULL;
5485
5486 if(!table)
5487 return NULL;
5488
5489 if(!uintkey)
5490 return NULL;
5491
5492 i = (*table->Fhash)(uintkey, table->Size);
5493
5494 for(node = table->Buckets[i]; node; node = node->Link)
5495 if((*table->Fcmp)(uintkey, node->Key) == 0)
5496 break;
5497
5498 return node ? (const ajuint*) node->Value : NULL;
5499 }
5500
5501
5502
5503
5504 /* @section Modify ************************************************************
5505 **
5506 ** @fdata [AjPTable]
5507 **
5508 ** Updates values from a hash table
5509 **
5510 ** @nam3rule Fetchmod Retrieval function
5511 **
5512 ** @argrule * table [AjPTable] Hash table
5513 ** @argrule Fetchmod uintkey [const ajuint*] Key
5514 **
5515 ** @valrule Fetchmod [ajuint*] Value
5516 **
5517 ** @fcategory modify
5518 **
5519 ******************************************************************************/
5520
5521
5522
5523
5524 /* @func ajTableuintFetchmod **************************************************
5525 **
5526 ** returns the value associated with key in table, or null
5527 ** if table does not hold key.
5528 **
5529 ** @param [u] table [AjPTable] table to search
5530 ** @param [r] uintkey [const ajuint*] key to find.
5531 ** @return [ajuint*] value associated with key
5532 ** @error NULL if key not found in table.
5533 **
5534 ** @release 6.4.0
5535 ** @@
5536 ******************************************************************************/
5537
ajTableuintFetchmod(AjPTable table,const ajuint * uintkey)5538 ajuint* ajTableuintFetchmod(AjPTable table, const ajuint* uintkey)
5539 {
5540 ajulong i = 0UL;
5541
5542 AjPTableNode node = NULL;
5543
5544 if(!table)
5545 return NULL;
5546
5547 if(!uintkey)
5548 return NULL;
5549
5550 i = (*table->Fhash)(uintkey, table->Size);
5551
5552 for(node = table->Buckets[i]; node; node = node->Link)
5553 if((*table->Fcmp)(uintkey, node->Key) == 0)
5554 break;
5555
5556 return node ? (ajuint*) (&node->Value) : NULL;
5557 }
5558
5559
5560
5561
5562 /* @section Comparison functions **********************************************
5563 **
5564 ** @fdata [AjPTable]
5565 **
5566 ** Comparison functions for table keys
5567 **
5568 ** @nam3rule Cmp Comparison
5569 ** @nam3rule Hash Hashing keys
5570 **
5571 ** @argrule Cmp key1 [const void*] First key
5572 ** @argrule Cmp key2 [const void*] Second key
5573 ** @argrule Hash key [const void*] Key
5574 ** @argrule Hash hashsize [ajulong] Hash table size
5575 ** @suffix Case Case insensitive keys
5576 **
5577 ** @valrule Cmp [ajint] Comparison result 0 for a match,
5578 ** -1 or +1 for a mismatch
5579 ** @valrule Hash [ajulong] hash value
5580 **
5581 ** @fcategory misc
5582 **
5583 ******************************************************************************/
5584
5585
5586
5587
5588 /* @func ajTableuintCmp *******************************************************
5589 **
5590 ** Comparison function for a table with an unsigned integer key
5591 **
5592 ** @param [r] key1 [const void*] First key.
5593 ** @param [r] key2 [const void*] Second key.
5594 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
5595 **
5596 ** @release 6.4.0
5597 ** @@
5598 ******************************************************************************/
5599
ajTableuintCmp(const void * key1,const void * key2)5600 ajint ajTableuintCmp(const void* key1, const void* key2)
5601 {
5602 return (ajint) (*((const ajuint*) key1) != *((const ajuint*) key2));
5603 }
5604
5605
5606
5607
5608 /* @func ajTableuintHash ******************************************************
5609 **
5610 ** Hash function for a table with an unsigned integer key
5611 **
5612 ** @param [r] key [const void*] Standard argument. Table key.
5613 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
5614 ** @return [ajulong] Hash value in range 0 to hashsize-1
5615 **
5616 ** @release 6.4.0
5617 ** @@
5618 ******************************************************************************/
5619
ajTableuintHash(const void * key,ajulong hashsize)5620 ajulong ajTableuintHash(const void* key, ajulong hashsize)
5621 {
5622 ajulong hash = 0UL;
5623
5624 const ajuint* ia = NULL;
5625
5626 if(!key)
5627 return 0;
5628
5629 if(!hashsize)
5630 return 0;
5631
5632 ia = (const ajuint *) key;
5633
5634 hash = (*ia >> 2) % hashsize;
5635
5636 return hash;
5637 }
5638
5639
5640
5641
5642 /* @datasection [AjPTable] Unsigned long hash tables **************************
5643 **
5644 ** @nam2rule Tableulong Unsigned long integer hash tables
5645 **
5646 ******************************************************************************/
5647
5648
5649
5650
5651 /* @section Constructors ******************************************************
5652 **
5653 ** Constructors for hash tables
5654 **
5655 ** @fdata [AjPTable]
5656 **
5657 ** @fcategory new
5658 **
5659 ** @nam3rule New Constructor
5660 ** @suffix Const Constant keys with no destructor
5661 **
5662 ** @argrule New size [ajulong] Number of key values
5663 **
5664 ** @valrule * [AjPTable] New hash table
5665 **
5666 ******************************************************************************/
5667
5668
5669
5670
5671 /* @func ajTableulongNew ******************************************************
5672 **
5673 ** Creates, initialises, and returns a new, empty table that can hold an
5674 ** arbitrary number of unsigned long integer key-value pairs
5675 **
5676 ** @param [r] size [ajulong] estimate of number of unique keys
5677 ** @return [AjPTable] new table.
5678 **
5679 ** @release 6.4.0
5680 ** @@
5681 **
5682 ******************************************************************************/
5683
ajTableulongNew(ajulong size)5684 AjPTable ajTableulongNew(ajulong size)
5685 {
5686 AjPTable table = NULL;
5687
5688 table = ajTableNewFunctionLen(size, &ajTableulongCmp, &ajTableulongHash,
5689 &ajMemFree, NULL);
5690 table->Type = ajETableTypeUlong;
5691
5692 return table;
5693 }
5694
5695
5696
5697
5698
5699 /* @func ajTableulongNewConst *************************************************
5700 **
5701 ** Creates, initialises, and returns a new, empty table that can hold an
5702 ** arbitrary number of unsigned long integer key-value pairs
5703 **
5704 ** @param [r] size [ajulong] estimate of number of unique keys
5705 ** @return [AjPTable] new table.
5706 **
5707 ** @release 6.4.0
5708 ** @@
5709 **
5710 ******************************************************************************/
5711
ajTableulongNewConst(ajulong size)5712 AjPTable ajTableulongNewConst(ajulong size)
5713 {
5714 AjPTable table = NULL;
5715
5716 table = ajTableNewFunctionLen(size, &ajTableulongCmp, &ajTableulongHash,
5717 NULL, NULL);
5718 table->Type = ajETableTypeUlong;
5719
5720 return table;
5721 }
5722
5723
5724
5725
5726
5727 /* @section Destructors *******************************************************
5728 **
5729 ** @fdata [AjPTable]
5730 **
5731 ** Destructors know they are dealing with strings and can
5732 ** clean up keys and values
5733 **
5734 ** @nam3rule Free Delete table, keys and values
5735 ** @nam4rule FreeKey Delete table, keys and values
5736 **
5737 ** @argrule * Ptable [AjPTable*] Hash table
5738 **
5739 ** @valrule * [void]
5740 **
5741 ** @fcategory delete
5742 **
5743 ******************************************************************************/
5744
5745
5746
5747
5748 /* @func ajTableulongFree *****************************************************
5749 **
5750 ** Free keys and value strings in a table and free the table.
5751 ** Use only where the keys and data
5752 ** in the table are real, and not just copies of pointers. Otherwise
5753 ** a call to ajTableFree is enough.
5754 **
5755 ** @param [d] Ptable [AjPTable*] Table
5756 ** @return [void]
5757 **
5758 ** @release 6.4.0
5759 ** @@
5760 ******************************************************************************/
5761
ajTableulongFree(AjPTable * Ptable)5762 void ajTableulongFree(AjPTable* Ptable)
5763 {
5764 if(!Ptable)
5765 return;
5766
5767 if(!*Ptable)
5768 return;
5769
5770 ajTableMapDel(*Ptable, &tableDel, NULL);
5771
5772 ajTableFree(Ptable);
5773
5774 return;
5775 }
5776
5777
5778
5779
5780 /* @func ajTableulongFreeKey **************************************************
5781 **
5782 ** Free keys and value strings in a table and free the table.
5783 ** Use only where the keys
5784 ** in the table are real, and not just copies of pointers. Otherwise
5785 ** a call to ajTableFree is enough.
5786 **
5787 ** @param [d] Ptable [AjPTable*] Table
5788 ** @return [void]
5789 **
5790 ** @release 6.4.0
5791 ** @@
5792 ******************************************************************************/
5793
ajTableulongFreeKey(AjPTable * Ptable)5794 void ajTableulongFreeKey(AjPTable* Ptable)
5795 {
5796 if(!Ptable)
5797 return;
5798
5799 if(!*Ptable)
5800 return;
5801
5802 ajTableMapDel(*Ptable, &tableDelKey, NULL);
5803
5804 ajTableFree(Ptable);
5805
5806 return;
5807 }
5808
5809
5810
5811
5812 /* @section Retrieval *********************************************************
5813 **
5814 ** @fdata [AjPTable]
5815 **
5816 ** Retrieves values from a hash table
5817 **
5818 ** @nam3rule Fetch Retrieval function
5819 **
5820 ** @argrule * table [const AjPTable] Hash table
5821 ** @argrule Fetch ulongkey [const ajulong*] Key
5822 **
5823 ** @valrule Fetch [const ajulong*] Value
5824 **
5825 ** @fcategory cast
5826 **
5827 ******************************************************************************/
5828
5829
5830
5831
5832 /* @func ajTableulongFetch ****************************************************
5833 **
5834 ** returns the value associated with key in table, or null
5835 ** if table does not hold key.
5836 **
5837 ** @param [r] table [const AjPTable] table to search
5838 ** @param [r] ulongkey [const ajulong*] key to find.
5839 ** @return [const ajulong*] value associated with key
5840 ** @error NULL if key not found in table.
5841 **
5842 ** @release 6.4.0
5843 ** @@
5844 ******************************************************************************/
5845
ajTableulongFetch(const AjPTable table,const ajulong * ulongkey)5846 const ajulong* ajTableulongFetch(const AjPTable table, const ajulong* ulongkey)
5847 {
5848 ajulong i = 0UL;
5849
5850 AjPTableNode node = NULL;
5851
5852 if(!table)
5853 return NULL;
5854
5855 if(!ulongkey)
5856 return NULL;
5857
5858 i = (*table->Fhash)(ulongkey, table->Size);
5859
5860 for(node = table->Buckets[i]; node; node = node->Link)
5861 if((*table->Fcmp)(ulongkey, node->Key) == 0)
5862 break;
5863
5864 return node ? (const ajulong*) node->Value : NULL;
5865 }
5866
5867
5868
5869
5870 /* @section Modify ************************************************************
5871 **
5872 ** @fdata [AjPTable]
5873 **
5874 ** Updates values from a hash table
5875 **
5876 ** @nam3rule Fetchmod Retrieval function
5877 **
5878 ** @argrule * table [AjPTable] Hash table
5879 ** @argrule Fetchmod ulongkey [const ajulong*] Key
5880 **
5881 ** @valrule Fetchmod [ajulong*] Value
5882 **
5883 ** @fcategory modify
5884 **
5885 ******************************************************************************/
5886
5887
5888
5889
5890 /* @func ajTableulongFetchmod *************************************************
5891 **
5892 ** Returns the value associated with key in table, or null if table
5893 ** does not hold key.
5894 **
5895 ** @param [u] table [AjPTable] table to search
5896 ** @param [r] ulongkey [const ajulong*] key to find.
5897 ** @return [ajulong*] value associated with key
5898 ** @error NULL if key not found in table.
5899 **
5900 ** @release 6.4.0
5901 ** @@
5902 ******************************************************************************/
5903
ajTableulongFetchmod(AjPTable table,const ajulong * ulongkey)5904 ajulong* ajTableulongFetchmod(AjPTable table, const ajulong* ulongkey)
5905 {
5906 ajulong i = 0UL;
5907
5908 AjPTableNode node = NULL;
5909
5910 if(!table)
5911 return NULL;
5912
5913 if(!ulongkey)
5914 return NULL;
5915
5916 i = (*table->Fhash)(ulongkey, table->Size);
5917
5918 for(node = table->Buckets[i]; node; node = node->Link)
5919 if((*table->Fcmp)(ulongkey, node->Key) == 0)
5920 break;
5921
5922 return node ? (ajulong*) (&node->Value) : NULL;
5923 }
5924
5925
5926
5927
5928 /* @section Comparison functions **********************************************
5929 **
5930 ** @fdata [AjPTable]
5931 **
5932 ** Comparison functions for table keys
5933 **
5934 ** @nam3rule Cmp Comparison
5935 ** @nam3rule Hash Hashing keys
5936 **
5937 ** @argrule Cmp key1 [const void*] First key
5938 ** @argrule Cmp key2 [const void*] Second key
5939 ** @argrule Hash key [const void*] Key
5940 ** @argrule Hash hashsize [ajulong] Hash table size
5941 ** @suffix Case Case insensitive keys
5942 **
5943 ** @valrule Cmp [ajint] Comparison result 0 for a match,
5944 ** -1 or +1 for a mismatch
5945 ** @valrule Hash [ajulong] hash value
5946 **
5947 ** @fcategory misc
5948 **
5949 ******************************************************************************/
5950
5951
5952
5953
5954 /* @func ajTableulongCmp ******************************************************
5955 **
5956 ** Comparison function for a table with an unsigned long integer key
5957 **
5958 ** @param [r] key1 [const void*] First key.
5959 ** @param [r] key2 [const void*] Second key.
5960 ** @return [ajint] Comparison result. Zero if equal, non-zero if different.
5961 **
5962 ** @release 6.4.0
5963 ** @@
5964 ******************************************************************************/
5965
ajTableulongCmp(const void * key1,const void * key2)5966 ajint ajTableulongCmp(const void* key1, const void* key2)
5967 {
5968 return (ajint) (*((const ajulong*) key1) != *((const ajulong*) key2));
5969 }
5970
5971
5972
5973
5974 /* @func ajTableulongHash *****************************************************
5975 **
5976 ** Hash function for a table with an unsigned long integer key
5977 **
5978 ** @param [r] key [const void*] Standard argument. Table key.
5979 ** @param [r] hashsize [ajulong] Standard argument. Estimated Hash size.
5980 ** @return [ajulong] Hash value in range 0 to hashsize-1
5981 **
5982 ** @release 6.4.0
5983 ** @@
5984 ******************************************************************************/
5985
ajTableulongHash(const void * key,ajulong hashsize)5986 ajulong ajTableulongHash(const void* key, ajulong hashsize)
5987 {
5988 ajulong hash = 0UL;
5989
5990 const ajulong* ia = NULL;
5991
5992 if(!key)
5993 return 0;
5994
5995 if(!hashsize)
5996 return 0;
5997
5998 ia = (const ajulong*) key;
5999
6000 hash = (*ia >> 2) % hashsize;
6001
6002 return hash;
6003 }
6004
6005
6006
6007
6008 /* @funcstatic tableDelStr ****************************************************
6009 **
6010 ** Delete a string object value
6011 **
6012 ** @param [d] Pstr [void**] AJAX String object
6013 ** @return [void]
6014 **
6015 ** @release 6.4.0
6016 ******************************************************************************/
6017
tableDelStr(void ** Pstr)6018 static void tableDelStr(void** Pstr)
6019 {
6020 if(!Pstr)
6021 return;
6022 if(!*Pstr)
6023 return;
6024
6025 ajStrDel((AjPStr*) Pstr);
6026
6027 return;
6028 }
6029
6030
6031
6032
6033 #ifdef AJ_COMPILE_DEPRECATED_BOOK
6034 #endif
6035
6036
6037
6038
6039 #ifdef AJ_COMPILE_DEPRECATED
6040 /* @obsolete ajTableNewLen
6041 ** @rename ajTableNew
6042 */
ajTableNewLen(ajuint size)6043 __deprecated AjPTable ajTableNewLen(ajuint size)
6044 {
6045 AjPTable table = NULL;
6046
6047 table = ajTableNewFunctionLen(size, &tableCmpAtom, &tableHashAtom,
6048 NULL, NULL);
6049 table->Type = ajETableTypeUser;
6050
6051 return table;
6052 }
6053
6054
6055
6056
6057 /* @obsolete ajTableNewL
6058 ** @rename ajTableNewFunctionLen
6059 */
6060
ajTableNewL(ajuint size,ajint (* cmp)(const void * key1,const void * key2),ajuint (* hash)(const void * key,ajuint hashsize))6061 __deprecated AjPTable ajTableNewL(
6062 ajuint size,
6063 ajint (*cmp)(const void* key1, const void* key2),
6064 ajuint (*hash)(const void* key,
6065 ajuint hashsize))
6066 {
6067 /*
6068 ** Since the interface of ajTableNewFunctionLen has changed after
6069 ** deprecation of ajTableNewL, the hash function pointer needs
6070 ** additional casting.
6071 */
6072 return ajTableNewFunctionLen(size, cmp,
6073 (ajulong (*)(const void*, ajulong)) hash,
6074 NULL, NULL);
6075 }
6076
6077
6078
6079
6080 /* @obsolete ajTableFetch
6081 ** @rename ajTableFetchmodV
6082 */
6083
ajTableFetch(const AjPTable table,const void * key)6084 __deprecated void* ajTableFetch(const AjPTable table, const void* key)
6085 {
6086 ajuint i = 0U;
6087
6088 AjPTableNode node = NULL;
6089
6090 if(!table)
6091 return NULL;
6092
6093 if (!key)
6094 return NULL;
6095
6096 i = (*table->Fhash)(key, table->Size);
6097
6098 for(node = table->Buckets[i]; node; node = node->Link)
6099 if((*table->Fcmp)(key, node->Key) == 0)
6100 break;
6101
6102 return node ? node->Value : NULL;
6103 }
6104
6105
6106
6107
6108 /* @obsolete ajTablestrFetch
6109 ** @rename ajTablestrFetchS
6110 */
ajTablestrFetch(const AjPTable table,const AjPStr key)6111 __deprecated const AjPStr ajTablestrFetch(const AjPTable table,
6112 const AjPStr key)
6113 {
6114 return ajTablestrFetchS(table, key);
6115 }
6116
6117
6118
6119
6120 /* @obsolete ajTableGet
6121 ** @rename ajTableFetchmodV
6122 */
6123
ajTableGet(const AjPTable table,const void * key)6124 __deprecated void* ajTableGet(const AjPTable table, const void* key)
6125 {
6126 return ajTableFetchmodV(table, key);
6127 }
6128
6129
6130
6131
6132 /* @obsolete ajTableFetchKey
6133 ** @rename ajTablestrFetchKeyS
6134 */
6135
ajTableFetchKey(const AjPTable table,const void * key)6136 __deprecated const void* ajTableFetchKey(const AjPTable table,
6137 const void* key)
6138 {
6139 ajuint i = 0U;
6140
6141 const AjPTableNode node = NULL;
6142
6143 if (!table)
6144 return NULL;
6145
6146 if (!key)
6147 return NULL;
6148
6149 i = (*table->Fhash)(key, table->Size);
6150
6151 for(node = table->Buckets[i]; node; node = node->Link)
6152 if((*table->Fcmp)(key, node->Key) == 0)
6153 break;
6154
6155 return node ? (const void*) node->Key : NULL;
6156 }
6157
6158
6159
6160
6161 /* @obsolete ajTableLength
6162 ** @rename ajTableGetLength
6163 */
6164
ajTableLength(const AjPTable table)6165 __deprecated ajint ajTableLength(const AjPTable table)
6166 {
6167 return (ajuint) ajTableGetLength(table);
6168 }
6169
6170
6171
6172
6173 /* @obsolete ajTableToarray
6174 ** @rename ajTableToarrayKeysValues
6175 */
6176
ajTableToarray(const AjPTable table,void *** keyarray,void *** valarray)6177 __deprecated ajuint ajTableToarray(const AjPTable table,
6178 void*** keyarray, void*** valarray)
6179 {
6180
6181 return ajTableToarrayKeysValues(table, keyarray, valarray);
6182 }
6183
6184
6185
6186
6187 /* @obsolete ajTablecharNewCaseLen
6188 ** @rename ajTablecharNewCase
6189 */
6190
ajTablecharNewCaseLen(ajuint hint)6191 __deprecated AjPTable ajTablecharNewCaseLen(ajuint hint)
6192 {
6193 return ajTablecharNewCase(hint);
6194 }
6195
6196
6197
6198
6199 /* @obsolete ajStrTableNewCase
6200 ** @rename ajTablecharNewCase
6201 */
6202
ajStrTableNewCase(ajuint hint)6203 __deprecated AjPTable ajStrTableNewCase(ajuint hint)
6204 {
6205 return ajTablecharNewCase(hint);
6206 }
6207
6208
6209
6210
6211 /* @obsolete ajStrTableNewCaseC
6212 ** @rename ajTablecharNewCase
6213 */
6214
ajStrTableNewCaseC(ajuint hint)6215 __deprecated AjPTable ajStrTableNewCaseC(ajuint hint)
6216 {
6217 return ajTablecharNewCase(hint);
6218 }
6219
6220
6221
6222
6223 /* @obsolete ajStrTableNewC
6224 ** @rename ajTablecharNew
6225 */
6226
ajStrTableNewC(ajuint hint)6227 __deprecated AjPTable ajStrTableNewC(ajuint hint)
6228 {
6229 return ajTablecharNew(hint);
6230 }
6231
6232
6233
6234
6235 /* @obsolete ajStrTableNew
6236 ** @rename ajTablestrNew
6237 */
6238
ajStrTableNew(ajuint hint)6239 __deprecated AjPTable ajStrTableNew(ajuint hint)
6240 {
6241 return ajTablestrNew(hint);
6242 }
6243
6244
6245
6246
6247 /* @obsolete ajStrTablePrintC
6248 ** @rename ajTablecharPrint
6249 */
6250
ajStrTablePrintC(const AjPTable table)6251 __deprecated void ajStrTablePrintC(const AjPTable table)
6252 {
6253 ajTablecharPrint(table);
6254
6255 return;
6256 }
6257
6258
6259
6260
6261 /* @obsolete ajStrTableCmpC
6262 ** @rename ajTablecharCmp
6263 */
6264
ajStrTableCmpC(const void * key1,const void * key2)6265 __deprecated ajint ajStrTableCmpC(const void* key1, const void* key2)
6266 {
6267 return ajTablecharCmp(key1, key2);
6268 }
6269
6270
6271
6272
6273 /* @obsolete ajStrTableCmpCaseC
6274 ** @rename ajTablecharCmpCase
6275 */
6276
ajStrTableCmpCaseC(const void * key1,const void * key2)6277 __deprecated ajint ajStrTableCmpCaseC(const void* key1, const void* key2)
6278 {
6279 return ajTablecharCmpCase(key1, key2);
6280 }
6281
6282
6283
6284
6285 /* @obsolete ajStrTableHashC
6286 ** @rename ajTablecharHash
6287 */
6288
ajStrTableHashC(const void * key,ajuint hashsize)6289 __deprecated ajuint ajStrTableHashC(const void* key, ajuint hashsize)
6290 {
6291 return ajTablecharHash(key, hashsize);
6292 }
6293
6294
6295
6296
6297 /* @obsolete ajStrTableHashCaseC
6298 ** @rename ajTablecharHashCase
6299 */
6300
ajStrTableHashCaseC(const void * key,ajuint hashsize)6301 __deprecated ajuint ajStrTableHashCaseC(const void* key, ajuint hashsize)
6302 {
6303 return ajTablecharHashCase(key, hashsize);
6304 }
6305
6306
6307
6308
6309 /* @obsolete ajTablestrNewLen
6310 ** @rename ajTablestrNew
6311 */
6312
ajTablestrNewLen(ajuint size)6313 __deprecated AjPTable ajTablestrNewLen(ajuint size)
6314 {
6315 AjPTable table = NULL;
6316
6317 table = ajTableNewFunctionLen(size, &ajTablestrCmp, &ajTablestrHash,
6318 NULL, NULL);
6319 table->Type = ajETableTypeStr;
6320
6321 return table;
6322 }
6323
6324
6325
6326
6327 /* @obsolete ajTablestrNewCaseLen
6328 ** @rename ajTablestrNewCase
6329 */
ajTablestrNewCaseLen(ajuint size)6330 __deprecated AjPTable ajTablestrNewCaseLen(ajuint size)
6331 {
6332 AjPTable table = NULL;
6333
6334 table = ajTableNewFunctionLen(size, &ajTablestrCmpCase, &ajTablestrHashCase,
6335 NULL, NULL);
6336 table->Type = ajETableTypeStr;
6337
6338 return table;
6339 }
6340
6341
6342
6343
6344 /* @obsolete ajStrTableFree
6345 ** @rename ajTablestrFree
6346 */
6347
ajStrTableFree(AjPTable * ptable)6348 __deprecated void ajStrTableFree(AjPTable* ptable)
6349 {
6350 ajTablestrFree(ptable);
6351
6352 return;
6353 }
6354
6355
6356
6357
6358 /* @obsolete ajStrTableFreeKey
6359 ** @rename ajTablestrFreeKey
6360 */
6361
ajStrTableFreeKey(AjPTable * ptable)6362 __deprecated void ajStrTableFreeKey(AjPTable* ptable)
6363 {
6364 ajTablestrFreeKey(ptable);
6365
6366 return;
6367 }
6368
6369
6370
6371
6372 /* @obsolete ajTableKey
6373 ** @rename ajTablestrFetchKeyS
6374 */
6375
ajTableKey(const AjPTable table,const void * key)6376 __deprecated const void* ajTableKey(const AjPTable table, const void* key)
6377 {
6378 return ajTablestrFetchkeyS(table, key);
6379 }
6380
6381
6382
6383
6384 /* @obsolete ajStrTableCmp
6385 ** @rename ajTablestrCmp
6386 */
6387
ajStrTableCmp(const void * key1,const void * key2)6388 __deprecated ajint ajStrTableCmp(const void* key1, const void* key2)
6389 {
6390 return ajTablestrCmp(key1, key2);
6391 }
6392
6393
6394
6395
6396 /* @obsolete ajStrTableCmpCase
6397 ** @rename ajTablestrCmpCase
6398 */
6399
ajStrTableCmpCase(const void * key1,const void * key2)6400 __deprecated ajint ajStrTableCmpCase(const void* key1, const void* key2)
6401 {
6402 return ajTablestrCmpCase(key1, key2);
6403 }
6404
6405
6406
6407
6408 /* @obsolete ajStrTableHash
6409 ** @rename ajTablestrHash
6410 */
6411
ajStrTableHash(const void * key,ajuint hashsize)6412 __deprecated ajuint ajStrTableHash(const void* key, ajuint hashsize)
6413 {
6414 return ajTablestrHash(key, hashsize);
6415 }
6416
6417
6418
6419
6420 /* @obsolete ajStrTableHashCase
6421 ** @rename ajTablestrHashCase
6422 */
6423
ajStrTableHashCase(const void * key,ajuint hashsize)6424 __deprecated ajuint ajStrTableHashCase(const void* key, ajuint hashsize)
6425 {
6426 return ajTablestrHashCase(key, hashsize);
6427 }
6428
6429
6430
6431
6432 /* @obsolete ajStrTablePrint
6433 ** @rename ajTablestrPrint
6434 */
6435
ajStrTablePrint(const AjPTable table)6436 __deprecated void ajStrTablePrint(const AjPTable table)
6437 {
6438 ajTablestrPrint(table);
6439 }
6440
6441
6442
6443
6444 /* @obsolete ajStrTableTrace
6445 ** @rename ajTablestrTrace
6446 */
6447
ajStrTableTrace(const AjPTable table)6448 __deprecated void ajStrTableTrace(const AjPTable table)
6449 {
6450 ajTablestrTrace(table);
6451
6452 return;
6453 }
6454 #endif
6455