master
c 771 lines 28 KB
Raw
1 // @(#) $Revision: 4.1 $ $Source: /judy/src/JudyHS/JudyHS.c
2 //=======================================================================
3 // Author Douglas L. Baskins, Dec 2003.
4 // Permission to use this code is freely granted, provided that this
5 // statement is retained.
6 // email - doug@sourcejudy.com -or- dougbaskins@yahoo.com
7 //=======================================================================
8
9 #include <string.h> // for memcmp(), memcpy()
10
11 #include <Judy.h> // for JudyL* routines/macros
12
13 /*
14 This routine is a very fast "string" version of an ADT that stores
15 (JudyHSIns()), retrieves (JudyHSGet()), deletes (JudyHSDel()) and
16 frees the entire ADT (JudyHSFreeArray()) strings. It uses the "Judy
17 arrays" JudyL() API as the main workhorse. The length of the string
18 is included in the calling parameters so that strings with embedded
19 \0s can be used. The string lengths can be from 0 bytes to whatever
20 malloc() can handle (~2GB).
21
22 Compile:
23
24 cc -O JudyHS.c -c needs to link with -lJudy (libJudy.a)
25
26 Note: in gcc version 3.3.1, -O2 generates faster code than -O
27 Note: in gcc version 3.3.2, -O3 generates faster code than -O2
28
29 NOTES:
30
31 1) There may be some performance issues with 64 bit machines, because I
32 have not characterized that it yet.
33
34 2) It appears that a modern CPU (>2Ghz) that the instruction times are
35 much faster that a RAM access, so building up a word from bytes takes
36 no longer that a whole word access. I am taking advantage of this to
37 make this code endian neutral. A side effect of this is strings do
38 not need to be aligned, nor tested to be on to a word boundry. In
39 older and in slow (RISC) machines, this may be a performance issue.
40 I have given up trying to optimize for machines that have very slow
41 mpy, mod, variable shifts and call returns.
42
43 3) JudyHS is very scalable from 1 string to billions (with enough RAM).
44 The memory usage is also scales with population. I have attempted to
45 combine the best characteristics of JudyL arrays with Hashing methods
46 and well designed modern processors (such as the 1.3Ghz Intel
47 Centrino this is being written on).
48
49 HOW JudyHS WORKS: ( 4[8] means 4 bytes in 32 bit machine and 8 in 64)
50
51 A) A JudyL array is used to separate strings of equal lengths into
52 their own structures (a different hash table is used for each length
53 of string). The additional time overhead is very near zero because
54 of the CPU cache. The space efficiency is improved because the
55 length need not be stored with the string (ls_t). The "JLHash" ADT
56 in the test program "StringCompare" is verification of both these
57 assumptions.
58
59 B) A 32 bit hash value is produced from the string. Many thanks to
60 the Internet and the author (Bob Jenkins) for coming up with a very
61 good and fast universal string hash. Next the 32 bit hash number is
62 used as an Index to another JudyL array. Notice that one (1) JudyL
63 array is used as a hash table per each string length. If there are
64 no hash collisions (normally) then the string is copied to a
65 structure (ls_t) along with room for storing a Value. A flag is
66 added to the pointer to note it is pointing to a ls_t structure.
67 Since the lengths of the strings are the same, there is no need to
68 stored length of string in the ls_t structure. This saves about a
69 word per string of memory.
70
71 C) When there is a hashing collision (very rare), a JudyL array is
72 used to decode the next 4[8] bytes of the string. That is, the next
73 4[8] bytes of the string are used as the Index. This process is
74 repeated until the remaining string is unique. The remaining string
75 (if any) is stored in a (now smaller) ls_t structure. If the
76 remaining string is less or equal to 4[8] bytes, then the ls_t
77 structure is not needed and the Value area in the JudyL array is
78 used. A compile option -DDONOTUSEHASH is available to test this
79 structure without using hashing (only the JudyL tree is used). This
80 is equivalent to having all strings hashed to the same bucket. The
81 speed is still better than all other tree based ADTs I have tested.
82 An added benefit of this is a very fast "hash collision" resolving.
83 It could foil hackers that exploit the slow synonym (linked-list)
84 collision handling property used with most hashing algorithms. If
85 this is not a necessary property, then a simpler ADT "JLHash" that is
86 documented the the test program "StringCompare.c" may be used with a
87 little loss of memory efficiency (because it includes the string
88 length with the ls_t structure). JudyHS was written to be the
89 fastest, very scalable, memory efficient, general purpose string ADT
90 possible. (However, I would like to eat those words someday). (dlb)
91
92 */
93
94 #ifdef EXAMPLE_CODE
95 #include <stdio.h>
96 #include <unistd.h>
97 #include <string.h>
98
99 #include <Judy.h>
100
101 //#include "JudyHS.h" // for Judy.h without JudyHS*()
102
103 // By Doug Baskins Apr 2004 - for JudyHS man page
104
105 #define MAXLINE 1000000 /* max length of line */
106 char Index[MAXLINE]; // string to check
107
108 int // Usage: CheckDupLines < file
109 main()
110 {
111 Pvoid_t PJArray = (PWord_t)NULL; // Judy array.
112 PWord_t PValue; // ^ Judy array element.
113 Word_t Bytes; // size of JudyHS array.
114 Word_t LineNumb = 0; // current line number
115 Word_t Dups = 0; // number of duplicate lines
116
117 while (fgets(Index, MAXLINE, stdin) != (char *)NULL)
118 {
119 LineNumb++; // line number
120
121 // store string into array
122 JHSI(PValue, PJArray, Index, strlen(Index));
123 if (*PValue) // check if duplicate
124 {
125 Dups++; // count duplicates
126 printf("Duplicate lines %lu:%lu:%s", *PValue, LineNumb, Index);
127 }
128 else
129 {
130 *PValue = LineNumb; // store Line number
131 }
132 }
133 printf("%lu Duplicates, free JudyHS array of %lu Lines\n",
134 Dups, LineNumb - Dups);
135 JHSFA(Bytes, PJArray); // free array
136 printf("The JudyHS array allocated %lu bytes of memory\n", Bytes);
137 return (0);
138 }
139 #endif // EXAMPLE_CODE
140
141 // Note: Use JLAP_INVALID, which is non-zero, to mark pointers to a ls_t
142 // This makes it compatable with previous versions of JudyL()
143
144 #define IS_PLS(PLS) (((Word_t) (PLS)) & JLAP_INVALID)
145 #define CLEAR_PLS(PLS) (((Word_t) (PLS)) & (~JLAP_INVALID))
146 #define SET_PLS(PLS) (((Word_t) (PLS)) | JLAP_INVALID)
147
148 #define WORDSIZE (sizeof(Word_t))
149
150 // this is the struct used for "leaf" strings. Note that
151 // the Value is followed by a "variable" length ls_String array.
152 //
153 typedef struct L_EAFSTRING
154 {
155 Word_t ls_Value; // Value area (cannot change size)
156 uint8_t ls_String[WORDSIZE]; // to fill out to a Word_t size
157 } ls_t , *Pls_t;
158
159 #define LS_STRUCTOVD (sizeof(ls_t) - WORDSIZE)
160
161 // Calculate size of ls_t including the string of length of LEN.
162 //
163 #define LS_WORDLEN(LEN) (((LEN) + LS_STRUCTOVD + WORDSIZE - 1) / WORDSIZE)
164
165 // Copy from 0..4[8] bytes from string to a Word_t
166 // NOTE: the copy in in little-endian order to take advantage of improved
167 // memory efficiency of JudyLIns() with smaller numbers
168 //
169 #define COPYSTRING4toWORD(WORD,STR,LEN) \
170 { \
171 WORD = 0; \
172 switch(LEN) \
173 { \
174 default: /* four and greater */ \
175 case 4: \
176 WORD += (Word_t)(((uint8_t *)(STR))[3] << 24); \
177 case 3: \
178 WORD += (Word_t)(((uint8_t *)(STR))[2] << 16); \
179 case 2: \
180 WORD += (Word_t)(((uint8_t *)(STR))[1] << 8); \
181 case 1: \
182 WORD += (Word_t)(((uint8_t *)(STR))[0]); \
183 case 0: break; \
184 } \
185 }
186
187 #ifdef JU_64BIT
188
189 // copy from 0..8 bytes from string to Word_t
190 //
191 #define COPYSTRING8toWORD(WORD,STR,LEN) \
192 { \
193 WORD = 0UL; \
194 switch(LEN) \
195 { \
196 default: /* eight and greater */ \
197 case 8: \
198 WORD += ((Word_t)((uint8_t *)(STR))[7] << 56); \
199 case 7: \
200 WORD += ((Word_t)((uint8_t *)(STR))[6] << 48); \
201 case 6: \
202 WORD += ((Word_t)((uint8_t *)(STR))[5] << 40); \
203 case 5: \
204 WORD += ((Word_t)((uint8_t *)(STR))[4] << 32); \
205 case 4: \
206 WORD += ((Word_t)((uint8_t *)(STR))[3] << 24); \
207 case 3: \
208 WORD += ((Word_t)((uint8_t *)(STR))[2] << 16); \
209 case 2: \
210 WORD += ((Word_t)((uint8_t *)(STR))[1] << 8); \
211 case 1: \
212 WORD += ((Word_t)((uint8_t *)(STR))[0]); \
213 case 0: break; \
214 } \
215 }
216
217 #define COPYSTRINGtoWORD COPYSTRING8toWORD
218
219 #else // JU_32BIT
220
221 #define COPYSTRINGtoWORD COPYSTRING4toWORD
222
223 #endif // JU_32BIT
224
225 // set JError_t locally
226
227 #define JU_SET_ERRNO(PJERROR, JERRNO) \
228 { \
229 if (PJERROR != (PJError_t) NULL) \
230 { \
231 if (JERRNO) \
232 JU_ERRNO(PJError) = (JERRNO); \
233 JU_ERRID(PJERROR) = __LINE__; \
234 } \
235 }
236
237 //=======================================================================
238 // This routine must hash string to 24..32 bits. The "goodness" of
239 // the hash is not as important as its speed.
240 //=======================================================================
241
242 // hash to no more than 32 bits
243
244 // extern Word_t gHmask; for hash bits experiments
245
246 #define JUDYHASHSTR(HVALUE,STRING,LENGTH) \
247 { \
248 uint8_t *p_ = (uint8_t *)(STRING); \
249 uint8_t *q_ = p_ + (LENGTH); \
250 uint32_t c_ = 0; \
251 for (; p_ != q_; ++p_) \
252 { \
253 c_ = (c_ * 31) + *p_; \
254 } \
255 /* c_ &= gHmask; see above */ \
256 (HVALUE) = c_; \
257 }
258
259 // Find String of Len in JudyHS structure, return pointer to associated Value
260
261 PPvoid_t
262 JudyHSGet(Pcvoid_t PArray, // pointer (^) to structure
263 void * Str, // pointer to string
264 Word_t Len // length of string
265 )
266 {
267 uint8_t *String = (uint8_t *)Str;
268 PPvoid_t PPValue; // pointer to Value
269 Word_t Index; // 4[8] bytes of String
270
271 JLG(PPValue, PArray, Len); // find hash table for strings of Len
272 if (PPValue == (PPvoid_t) NULL)
273 return ((PPvoid_t) NULL); // no strings of this Len
274
275 // check for caller error (null pointer)
276 //
277 if ((String == (void *) NULL) && (Len != 0))
278 return ((PPvoid_t) NULL); // avoid null-pointer dereference
279
280 #ifndef DONOTUSEHASH
281 if (Len > WORDSIZE) // Hash table not necessary with short
282 {
283 uint32_t HValue; // hash of input string
284 JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits
285 JLG(PPValue, *PPValue, (Word_t)HValue); // get ^ to hash bucket
286 if (PPValue == (PPvoid_t) NULL)
287 return ((PPvoid_t) NULL); // no entry in Hash table
288 }
289 #endif // DONOTUSEHASH
290
291 /*
292 Each JudyL array decodes 4[8] bytes of the string. Since the hash
293 collisions occur very infrequently, the performance is not important.
294 However, even if the Hash code is not used this method still is
295 significantly faster than common tree methods (AVL, Red-Black, Splay,
296 b-tree, etc..). You can compare it yourself with #define DONOTUSEHASH
297 1 or putting -DDONOTUSEHASH in the cc line. Use the "StringCompare.c"
298 code to compare (9Dec2003 dlb).
299 */
300 while (Len > WORDSIZE) // traverse tree of JudyL arrays
301 {
302 if (IS_PLS(*PPValue)) // ^ to JudyL array or ls_t struct?
303 {
304 Pls_t Pls; // ls_t struct, termination of tree
305 Pls = (Pls_t) CLEAR_PLS(*PPValue); // remove flag from ^
306
307 // if remaining string matches, return ^ to Value, else NULL
308
309 if (memcmp(String, Pls->ls_String, Len) == 0)
310 return ((PPvoid_t) (&(Pls->ls_Value)));
311 else
312 return ((PPvoid_t) NULL); // string does not match
313 }
314 else
315 {
316 COPYSTRINGtoWORD(Index, String, WORDSIZE);
317
318 JLG(PPValue, *PPValue, Index); // decode next 4[8] bytes
319 if (PPValue == (PPvoid_t) NULL) // if NULL array, bail out
320 return ((PPvoid_t) NULL); // string does not match
321
322 String += WORDSIZE; // advance
323 Len -= WORDSIZE;
324 }
325 }
326
327 // Get remaining 1..4[8] bytes left in string
328
329 COPYSTRINGtoWORD(Index, String, Len);
330 JLG(PPValue, *PPValue, Index); // decode last 1-4[8] bytes
331 return (PPValue);
332 }
333
334 // Add string to a tree of JudyL arrays (all lengths must be same)
335
336 static PPvoid_t
337 insStrJudyLTree(uint8_t * String, // string to add to tree of JudyL arrays
338 Word_t Len, // length of string
339 PPvoid_t PPValue, // pointer to root pointer
340 PJError_t PJError // for returning error info
341 )
342 {
343 Word_t Index; // next 4[8] bytes of String
344
345 while (Len > WORDSIZE) // add to JudyL tree
346 {
347 // CASE 1, pointer is to a NULL, make a new ls_t leaf
348
349 if (*PPValue == (Pvoid_t)NULL)
350 {
351 Pls_t Pls; // memory for a ls_t
352 Pls = (Pls_t) JudyMalloc(LS_WORDLEN(Len));
353 if (Pls == NULL)
354 {
355 JU_SET_ERRNO(PJError, JU_ERRNO_NOMEM);
356 return (PPJERR);
357 }
358 Pls->ls_Value = 0; // clear Value word
359 memcpy(Pls->ls_String, String, Len); // copy to new struct
360 *PPValue = (Pvoid_t)SET_PLS(Pls); // mark pointer
361 return ((PPvoid_t) (&Pls->ls_Value)); // return ^ to Value
362 } // no exit here
363 // CASE 2: is a ls_t, free (and shorten), then decode into JudyL tree
364
365 if (IS_PLS(*PPValue)) // pointer to a ls_t? (leaf)
366 {
367 Pls_t Pls; // ^ to ls_t
368 uint8_t *String0; // ^ to string in ls_t
369 Word_t Index0; // 4[8] bytes in string
370 Word_t FreeLen; // length of ls_t
371 PPvoid_t PPsplit;
372
373 FreeLen = LS_WORDLEN(Len); // length of ls_t
374
375 Pls = (Pls_t) CLEAR_PLS(*PPValue); // demangle ^ to ls_t
376 String0 = Pls->ls_String;
377 if (memcmp(String, String0, Len) == 0) // check if match?
378 {
379 return ((PPvoid_t) (&Pls->ls_Value)); // yes, duplicate
380 }
381
382 *PPValue = NULL; // clear ^ to ls_t and make JudyL
383
384 // This do loop is technically not required, saves multiple JudyFree()
385 // when storing already sorted strings into structure
386
387 do // decode next 4[8] bytes of string
388 { // with a JudyL array
389 // Note: string0 is always aligned
390
391 COPYSTRINGtoWORD(Index0, String0, WORDSIZE);
392 String0 += WORDSIZE;
393 COPYSTRINGtoWORD(Index, String, WORDSIZE);
394 String += WORDSIZE;
395 Len -= WORDSIZE;
396 PPsplit = PPValue; // save for split below
397 PPValue = JudyLIns(PPValue, Index0, PJError);
398 if (PPValue == PPJERR)
399 {
400 JU_SET_ERRNO(PJError, 0);
401 return (PPJERR);
402 }
403
404 } while ((Index0 == Index) && (Len > WORDSIZE));
405
406 // finish storing remainder of string that was in the ls_t
407
408 PPValue = insStrJudyLTree(String0, Len, PPValue, PJError);
409 if (PPValue == PPJERR)
410 {
411 return (PPJERR);
412 }
413 // copy old Value to Value in new struct
414
415 *(PWord_t)PPValue = Pls->ls_Value;
416
417 // free the string buffer (ls_t)
418
419 JudyFree((Pvoid_t)Pls, FreeLen);
420 PPValue = JudyLIns(PPsplit, Index, PJError);
421 if (PPValue == PPJERR)
422 {
423 JU_SET_ERRNO(PJError, 0);
424 return (PPValue);
425 }
426
427 // finish remainder of newly inserted string
428
429 PPValue = insStrJudyLTree(String, Len, PPValue, PJError);
430 return (PPValue);
431 } // no exit here
432 // CASE 3, more JudyL arrays, decode to next tree
433
434 COPYSTRINGtoWORD(Index, String, WORDSIZE);
435 Len -= WORDSIZE;
436 String += WORDSIZE;
437
438 PPValue = JudyLIns(PPValue, Index, PJError); // next 4[8] bytes
439 if (PPValue == PPJERR)
440 {
441 JU_SET_ERRNO(PJError, 0);
442 return (PPValue);
443 }
444 }
445 // this is done outside of loop so "Len" can be an unsigned number
446
447 COPYSTRINGtoWORD(Index, String, Len);
448 PPValue = JudyLIns(PPValue, Index, PJError); // remaining 4[8] bytes
449
450 return (PPValue);
451 }
452
453
454 // Insert string to JudyHS structure, return pointer to associated Value
455
456 PPvoid_t
457 JudyHSIns(PPvoid_t PPArray, // ^ to JudyHashArray name
458 void * Str, // pointer to string
459 Word_t Len, // length of string
460 PJError_t PJError // optional, for returning error info
461 )
462 {
463 uint8_t * String = (uint8_t *)Str;
464 PPvoid_t PPValue;
465
466 // string can only be NULL if Len is 0.
467
468 if ((String == (uint8_t *) NULL) && (Len != 0UL))
469 {
470 JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX);
471 return (PPJERR);
472 }
473 JLG(PPValue, *PPArray, Len); // JudyL hash table for strings of Len
474 if (PPValue == (PPvoid_t) NULL) // make new if missing, (very rare)
475 {
476 PPValue = JudyLIns(PPArray, Len, PJError);
477 if (PPValue == PPJERR)
478 {
479 JU_SET_ERRNO(PJError, 0);
480 return (PPJERR);
481 }
482 }
483 #ifndef DONOTUSEHASH
484 if (Len > WORDSIZE)
485 {
486 uint32_t HValue; // hash of input string
487 JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits
488 PPValue = JudyLIns(PPValue, (Word_t)HValue, PJError);
489 if (PPValue == PPJERR)
490 {
491 JU_SET_ERRNO(PJError, 0);
492 return (PPJERR);
493 }
494 }
495 #endif // DONOTUSEHASH
496
497 PPValue = insStrJudyLTree(String, Len, PPValue, PJError); // add string
498 return (PPValue); // ^ to Value
499 }
500
501 // Delete string from tree of JudyL arrays (all Lens must be same)
502
503 static int
504 delStrJudyLTree(uint8_t * String, // delete from tree of JudyL arrays
505 Word_t Len, // length of string
506 PPvoid_t PPValue, // ^ to hash bucket
507 PJError_t PJError // for returning error info
508 )
509 {
510 PPvoid_t PPValueN; // next pointer
511 Word_t Index;
512 int Ret; // -1=failed, 1=success, 2=quit del
513
514 if (IS_PLS(*PPValue)) // is pointer to ls_t?
515 {
516 Pls_t Pls;
517 Pls = (Pls_t) CLEAR_PLS(*PPValue); // demangle pointer
518 JudyFree((Pvoid_t)Pls, LS_WORDLEN(Len)); // free the ls_t
519
520 *PPValue = (Pvoid_t)NULL; // clean pointer
521 return (1); // successfully deleted
522 }
523
524 if (Len > WORDSIZE) // delete from JudyL tree, not leaf
525 {
526 COPYSTRINGtoWORD(Index, String, WORDSIZE); // get Index
527 JLG(PPValueN, *PPValue, Index); // get pointer to next JudyL array
528
529 String += WORDSIZE; // advance to next 4[8] bytes
530 Len -= WORDSIZE;
531
532 Ret = delStrJudyLTree(String, Len, PPValueN, PJError);
533 if (Ret != 1) return(Ret);
534
535 if (*PPValueN == (PPvoid_t) NULL)
536 {
537 // delete JudyL element from tree
538
539 Ret = JudyLDel(PPValue, Index, PJError);
540 }
541 }
542 else
543 {
544 COPYSTRINGtoWORD(Index, String, Len); // get leaf element
545
546 // delete last 1-4[8] bytes from leaf element
547
548 Ret = JudyLDel(PPValue, Index, PJError);
549 }
550 return (Ret);
551 }
552
553 // Delete string from JHS structure
554
555 int
556 JudyHSDel(PPvoid_t PPArray, // ^ to JudyHashArray struct
557 void * Str, // pointer to string
558 Word_t Len, // length of string
559 PJError_t PJError // optional, for returning error info
560 )
561 {
562 uint8_t * String = (uint8_t *)Str;
563 PPvoid_t PPBucket, PPHtble;
564 int Ret; // return bool from Delete routine
565 #ifndef DONOTUSEHASH
566 uint32_t HValue = 0; // hash value of input string
567 #endif // DONOTUSEHASH
568
569 if (PPArray == NULL)
570 return (0); // no pointer, return not found
571
572 // This is a little slower than optimum method, but not much in new CPU
573 // Verify that string is in the structure -- simplifies future assumptions
574
575 if (JudyHSGet(*PPArray, String, Len) == (PPvoid_t) NULL)
576 return (0); // string not found, return
577
578 // string is in structure, so testing for absence is not necessary
579
580 JLG(PPHtble, *PPArray, Len); // JudyL hash table for strings of Len
581
582 #ifdef DONOTUSEHASH
583 PPBucket = PPHtble; // simulate below code
584 #else // USEHASH
585 if (Len > WORDSIZE)
586 {
587 JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits
588
589 // get pointer to hash bucket
590
591 JLG(PPBucket, *PPHtble, (Word_t)HValue);
592 }
593 else
594 {
595 PPBucket = PPHtble; // no bucket to JLGet
596 }
597 #endif // USEHASH
598
599 // delete from JudyL tree
600 //
601 Ret = delStrJudyLTree(String, Len, PPBucket, PJError);
602 if (Ret != 1)
603 {
604 JU_SET_ERRNO(PJError, 0);
605 return(-1);
606 }
607 // handle case of missing JudyL array from hash table and length table
608
609 if (*PPBucket == (Pvoid_t)NULL) // if JudyL tree gone
610 {
611 #ifndef DONOTUSEHASH
612 if (Len > WORDSIZE)
613 {
614 // delete entry in Hash table
615
616 Ret = JudyLDel(PPHtble, (Word_t)HValue, PJError);
617 if (Ret != 1)
618 {
619 JU_SET_ERRNO(PJError, 0);
620 return(-1);
621 }
622 }
623 #endif // USEHASH
624 if (*PPHtble == (PPvoid_t) NULL) // if Hash table gone
625 {
626 // delete entry from the String length table
627
628 Ret = JudyLDel(PPArray, Len, PJError);
629 if (Ret != 1)
630 {
631 JU_SET_ERRNO(PJError, 0);
632 return(-1);
633 }
634 }
635 }
636 return (1); // success
637 }
638
639 static Word_t
640 delJudyLTree(PPvoid_t PPValue, // ^ to JudyL root pointer
641 Word_t Len, // length of string
642 PJError_t PJError) // for returning error info
643 {
644 Word_t bytes_freed = 0; // bytes freed at point
645 Word_t bytes_total = 0; // accumulated bytes freed
646 PPvoid_t PPValueN;
647
648 // Pointer is to another tree of JudyL arrays or ls_t struct
649
650 if (Len > WORDSIZE) // more depth to tree
651 {
652 Word_t NEntry;
653
654 // Pointer is to a ls_t struct
655
656 if (IS_PLS(*PPValue))
657 {
658 Pls_t Pls;
659 Word_t freewords;
660
661 freewords = LS_WORDLEN(Len); // calculate length
662 Pls = (Pls_t)CLEAR_PLS(*PPValue); // demangle pointer
663
664 // *PPValue = (Pvoid_t)NULL; // clean pointer
665 JudyFree((Pvoid_t)Pls, freewords); // free the ls_t
666
667 return(freewords * WORDSIZE);
668 }
669 // else
670 // Walk all the entrys in the JudyL array
671
672 NEntry = 0; // start at beginning
673 for (PPValueN = JudyLFirst(*PPValue, &NEntry, PJError);
674 (PPValueN != (PPvoid_t) NULL) && (PPValueN != PPJERR);
675 PPValueN = JudyLNext(*PPValue, &NEntry, PJError))
676 {
677 // recurse to the next level in the tree of arrays
678
679 bytes_freed = delJudyLTree(PPValueN, Len - WORDSIZE, PJError);
680 if (bytes_freed == JERR) return(JERR);
681 bytes_total += bytes_freed;
682 }
683 if (PPValueN == PPJERR) return(JERR);
684
685 // now free this JudyL array
686
687 bytes_freed = JudyLFreeArray(PPValue, PJError);
688 if (bytes_freed == JERR) return(JERR);
689 bytes_total += bytes_freed;
690
691 return(bytes_total); // return amount freed
692 }
693 // else
694
695 // Pointer to simple JudyL array
696
697 bytes_freed = JudyLFreeArray(PPValue, PJError);
698
699 return(bytes_freed);
700 }
701
702
703 Word_t // bytes freed
704 JudyHSFreeArray(PPvoid_t PPArray, // ^ to JudyHashArray struct
705 PJError_t PJError // optional, for returning error info
706 )
707 {
708 Word_t Len; // start at beginning
709 Word_t bytes_freed; // bytes freed at this level.
710 Word_t bytes_total; // bytes total at all levels.
711 PPvoid_t PPHtble;
712
713 if (PPArray == NULL)
714 return (0); // no pointer, return none
715
716 // Walk the string length table for subsidary hash structs
717 // NOTE: This is necessary to determine the depth of the tree
718
719 bytes_freed = 0;
720 bytes_total = 0;
721 Len = 0; // walk to length table
722
723 for (PPHtble = JudyLFirst(*PPArray, &Len, PJError);
724 (PPHtble != (PPvoid_t) NULL) && (PPHtble != PPJERR);
725 PPHtble = JudyLNext(*PPArray, &Len, PJError))
726 {
727 PPvoid_t PPValueH;
728
729 #ifndef DONOTUSEHASH
730 if (Len > WORDSIZE)
731 {
732 Word_t HEntry = 0; // walk the hash tables
733
734 for (PPValueH = JudyLFirst(*PPHtble, &HEntry, PJError);
735 (PPValueH != (PPvoid_t) NULL) && (PPValueH != PPJERR);
736 PPValueH = JudyLNext(*PPHtble, &HEntry, PJError))
737 {
738 bytes_freed = delJudyLTree(PPValueH, Len, PJError);
739 if (bytes_freed == JERR) return(JERR);
740 bytes_total += bytes_freed;
741 }
742
743 if (PPValueH == PPJERR) return(JERR);
744
745 // free the Hash table for this length of string
746
747 bytes_freed = JudyLFreeArray(PPHtble, PJError);
748 if (bytes_freed == JERR) return(JERR);
749 bytes_total += bytes_freed;
750 }
751 else
752 #endif // DONOTUSEHASH
753 {
754 PPValueH = PPHtble; // simulate hash table
755
756 bytes_freed = delJudyLTree(PPValueH, Len, PJError);
757 if (bytes_freed == JERR) return(JERR);
758 bytes_total += bytes_freed;
759 }
760 }
761 if (PPHtble == PPJERR) return(JERR);
762
763 // free the length table
764
765 bytes_freed = JudyLFreeArray(PPArray, PJError);
766 if (bytes_freed == JERR) return(JERR);
767
768 bytes_total += bytes_freed;
769
770 return(bytes_total); // return bytes freed
771 }