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