1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
|
// Copyright (C) 2000 - 2002 Hewlett-Packard Company
//
// This program is free software; you can redistribute it and/or modify it
// under the term of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// _________________
// TBD: It would probably be faster for the caller if the JudyL version took
// PIndex as an interleaved array of indexes and values rather than just
// indexes with a separate values array (PValue), especially considering
// indexes and values are copied here with for-loops anyway and not the
// equivalent of memcpy(). All code could be revised to simply count by two
// words for JudyL? Supports "streaming" the data to/from disk better later?
// In which case get rid of JU_ERRNO_NULLPVALUE, no longer needed, and simplify
// the API to this code.
// _________________
// @(#) $Revision: 4.21 $ $Source: /judy/src/JudyCommon/JudyInsArray.c $
//
// Judy1SetArray() and JudyLInsArray() functions for Judy1 and JudyL.
// Compile with one of -DJUDY1 or -DJUDYL.
#if (! (defined(JUDY1) || defined(JUDYL)))
#error: One of -DJUDY1 or -DJUDYL must be specified.
#endif
#ifdef JUDY1
#include "Judy1.h"
#else
#include "JudyL.h"
#endif
#include "JudyPrivate1L.h"
DBGCODE(extern void JudyCheckPop(Pvoid_t PArray);)
// IMMED AND LEAF SIZE AND BRANCH TYPE ARRAYS:
//
// These support fast and easy lookup by level.
static uint8_t immed_maxpop1[] = {
0,
cJU_IMMED1_MAXPOP1,
cJU_IMMED2_MAXPOP1,
cJU_IMMED3_MAXPOP1,
#ifdef JU_64BIT
cJU_IMMED4_MAXPOP1,
cJU_IMMED5_MAXPOP1,
cJU_IMMED6_MAXPOP1,
cJU_IMMED7_MAXPOP1,
#endif
// note: There are no IMMEDs for whole words.
};
static uint8_t leaf_maxpop1[] = {
0,
#if (defined(JUDYL) || (! defined(JU_64BIT)))
cJU_LEAF1_MAXPOP1,
#else
0, // 64-bit Judy1 has no Leaf1.
#endif
cJU_LEAF2_MAXPOP1,
cJU_LEAF3_MAXPOP1,
#ifdef JU_64BIT
cJU_LEAF4_MAXPOP1,
cJU_LEAF5_MAXPOP1,
cJU_LEAF6_MAXPOP1,
cJU_LEAF7_MAXPOP1,
#endif
// note: Root-level leaves are handled differently.
};
static uint8_t branchL_JPtype[] = {
0,
0,
cJU_JPBRANCH_L2,
cJU_JPBRANCH_L3,
#ifdef JU_64BIT
cJU_JPBRANCH_L4,
cJU_JPBRANCH_L5,
cJU_JPBRANCH_L6,
cJU_JPBRANCH_L7,
#endif
cJU_JPBRANCH_L,
};
static uint8_t branchB_JPtype[] = {
0,
0,
cJU_JPBRANCH_B2,
cJU_JPBRANCH_B3,
#ifdef JU_64BIT
cJU_JPBRANCH_B4,
cJU_JPBRANCH_B5,
cJU_JPBRANCH_B6,
cJU_JPBRANCH_B7,
#endif
cJU_JPBRANCH_B,
};
static uint8_t branchU_JPtype[] = {
0,
0,
cJU_JPBRANCH_U2,
cJU_JPBRANCH_U3,
#ifdef JU_64BIT
cJU_JPBRANCH_U4,
cJU_JPBRANCH_U5,
cJU_JPBRANCH_U6,
cJU_JPBRANCH_U7,
#endif
cJU_JPBRANCH_U,
};
// Subexpanse masks are similer to JU_DCDMASK() but without the need to clear
// the first digits bits. Avoid doing variable shifts by precomputing a
// lookup array.
static Word_t subexp_mask[] = {
0,
~cJU_POP0MASK(1),
~cJU_POP0MASK(2),
~cJU_POP0MASK(3),
#ifdef JU_64BIT
~cJU_POP0MASK(4),
~cJU_POP0MASK(5),
~cJU_POP0MASK(6),
~cJU_POP0MASK(7),
#endif
};
// FUNCTION PROTOTYPES:
static bool_t j__udyInsArray(Pjp_t PjpParent, int Level, PWord_t PPop1,
PWord_t PIndex,
#ifdef JUDYL
Pjv_t PValue,
#endif
Pjpm_t Pjpm);
// ****************************************************************************
// J U D Y 1 S E T A R R A Y
// J U D Y L I N S A R R A Y
//
// Main entry point. See the manual entry for external overview.
//
// TBD: Until thats written, note that the function returns 1 for success or
// JERRI for serious error, including insufficient memory to build whole array;
// use Judy*Count() to see how many were stored, the first N of the total
// Count. Also, since it takes Count == Pop1, it cannot handle a full array.
// Also, "sorted" means ascending without duplicates, otherwise you get the
// "unsorted" error.
//
// The purpose of these functions is to allow rapid construction of a large
// Judy array given a sorted list of indexes (and for JudyL, corresponding
// values). At least one customer saw this as useful, and probably it would
// also be useful as a sufficient workaround for fast(er) unload/reload to/from
// disk.
//
// This code is written recursively for simplicity, until/unless someone
// decides to make it faster and more complex. Hopefully recursion is fast
// enough simply because the function is so much faster than a series of
// Set/Ins calls.
#ifdef JUDY1
FUNCTION int Judy1SetArray
#else
FUNCTION int JudyLInsArray
#endif
(
PPvoid_t PPArray, // in which to insert, initially empty.
Word_t Count, // number of indexes (and values) to insert.
const Word_t * const PIndex, // list of indexes to insert.
#ifdef JUDYL
const Word_t * const PValue, // list of corresponding values.
#endif
PJError_t PJError // optional, for returning error info.
)
{
Pjlw_t Pjlw; // new root-level leaf.
Pjlw_t Pjlwindex; // first index in root-level leaf.
int offset; // in PIndex.
// CHECK FOR NULL OR NON-NULL POINTER (error by caller):
if (PPArray == (PPvoid_t) NULL)
{ JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return(JERRI); }
if (*PPArray != (Pvoid_t) NULL)
{ JU_SET_ERRNO(PJError, JU_ERRNO_NONNULLPARRAY); return(JERRI); }
if (PIndex == (PWord_t) NULL)
{ JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return(JERRI); }
#ifdef JUDYL
if (PValue == (PWord_t) NULL)
{ JU_SET_ERRNO(PJError, JU_ERRNO_NULLPVALUE); return(JERRI); }
#endif
// HANDLE LARGE COUNT (= POP1) (typical case):
//
// Allocate and initialize a JPM, set the root pointer to point to it, and then
// build the tree underneath it.
// Common code for unusual error handling when no JPM available:
if (Count > cJU_LEAFW_MAXPOP1) // too big for root-level leaf.
{
Pjpm_t Pjpm; // new, to allocate.
// Allocate JPM:
Pjpm = j__udyAllocJPM();
JU_CHECKALLOC(Pjpm_t, Pjpm, JERRI);
*PPArray = (Pvoid_t) Pjpm;
// Set some JPM fields:
(Pjpm->jpm_Pop0) = Count - 1;
// note: (Pjpm->jpm_TotalMemWords) is now initialized.
// Build Judy tree:
//
// In case of error save the final Count, possibly modified, unless modified to
// 0, in which case free the JPM itself:
if (! j__udyInsArray(&(Pjpm->jpm_JP), cJU_ROOTSTATE, &Count,
(PWord_t) PIndex,
#ifdef JUDYL
(Pjv_t) PValue,
#endif
Pjpm))
{
JU_COPY_ERRNO(PJError, Pjpm);
if (Count) // partial success, adjust pop0:
{
(Pjpm->jpm_Pop0) = Count - 1;
}
else // total failure, free JPM:
{
j__udyFreeJPM(Pjpm, (Pjpm_t) NULL);
*PPArray = (Pvoid_t) NULL;
}
DBGCODE(JudyCheckPop(*PPArray);)
return(JERRI);
}
DBGCODE(JudyCheckPop(*PPArray);)
return(1);
} // large count
// HANDLE SMALL COUNT (= POP1):
//
// First ensure indexes are in sorted order:
for (offset = 1; offset < Count; ++offset)
{
if (PIndex[offset - 1] >= PIndex[offset])
{ JU_SET_ERRNO(PJError, JU_ERRNO_UNSORTED); return(JERRI); }
}
if (Count == 0) return(1); // *PPArray remains null.
{
Pjlw = j__udyAllocJLW(Count + 1);
JU_CHECKALLOC(Pjlw_t, Pjlw, JERRI);
*PPArray = (Pvoid_t) Pjlw;
Pjlw[0] = Count - 1; // set pop0.
Pjlwindex = Pjlw + 1;
}
// Copy whole-word indexes (and values) to the root-level leaf:
JU_COPYMEM(Pjlwindex, PIndex, Count);
JUDYLCODE(JU_COPYMEM(JL_LEAFWVALUEAREA(Pjlw, Count), PValue, Count));
DBGCODE(JudyCheckPop(*PPArray);)
return(1);
} // Judy1SetArray() / JudyLInsArray()
// ****************************************************************************
// __ J U D Y I N S A R R A Y
//
// Given:
//
// - a pointer to a JP
//
// - the JPs level in the tree, that is, the number of digits left to decode
// in the indexes under the JP (one less than the level of the JPM or branch
// in which the JP resides); cJU_ROOTSTATE on first entry (when JP is the one
// in the JPM), down to 1 for a Leaf1, LeafB1, or FullPop
//
// - a pointer to the number of indexes (and corresponding values) to store in
// this subtree, to modify in case of partial success
//
// - a list of indexes (and for JudyL, corresponding values) to store in this
// subtree
//
// - a JPM for tracking memory usage and returning errors
//
// Recursively build a subtree (immediate indexes, leaf, or branch with
// subtrees) and modify the JP accordingly. On the way down, build a BranchU
// (only) for any expanse with *PPop1 too high for a leaf; on the way out,
// convert the BranchU to a BranchL or BranchB if appropriate. Keep memory
// statistics in the JPM.
//
// Return TRUE for success, or FALSE with error information set in the JPM in
// case of error, in which case leave a partially constructed but healthy tree,
// and modify parent population counts on the way out.
//
// Note: Each call of this function makes all modifications to the PjpParent
// it receives; neither the parent nor child calls do this.
FUNCTION static bool_t j__udyInsArray(
Pjp_t PjpParent, // parent JP in/under which to store.
int Level, // initial digits remaining to decode.
PWord_t PPop1, // number of indexes to store.
PWord_t PIndex, // list of indexes to store.
#ifdef JUDYL
Pjv_t PValue, // list of corresponding values.
#endif
Pjpm_t Pjpm) // for memory and errors.
{
Pjp_t Pjp; // lower-level JP.
Word_t Pjbany; // any type of branch.
int levelsub; // actual, of Pjps node, <= Level.
Word_t pop1 = *PPop1; // fast local value.
Word_t pop1sub; // population of one subexpanse.
uint8_t JPtype; // current JP type.
uint8_t JPtype_null; // precomputed value for new branch.
jp_t JPnull; // precomputed for speed.
Pjbu_t PjbuRaw; // constructed BranchU.
Pjbu_t Pjbu;
int digit; // in BranchU.
Word_t digitmask; // for a digit in a BranchU.
Word_t digitshifted; // shifted to correct offset.
Word_t digitshincr; // increment for digitshifted.
int offset; // in PIndex, or a bitmap subexpanse.
int numJPs; // number non-null in a BranchU.
bool_t retval; // to return from this func.
JUDYLCODE(Pjv_t PjvRaw); // destination value area.
JUDYLCODE(Pjv_t Pjv);
// MACROS FOR COMMON CODE:
//
// Note: These use function and local parameters from the context.
// Note: Assume newly allocated memory is zeroed.
// Indicate whether a sorted list of indexes in PIndex, based on the first and
// last indexes in the list using pop1, are in the same subexpanse between
// Level and L_evel:
//
// This can be confusing! Note that SAMESUBEXP(L) == TRUE means the indexes
// are the same through level L + 1, and it says nothing about level L and
// lower; they might be the same or they might differ.
//
// Note: In principle SAMESUBEXP needs a mask for the digits from Level,
// inclusive, to L_evel, exclusive. But in practice, since the indexes are all
// known to be identical above Level, it just uses a mask for the digits
// through L_evel + 1; see subexp_mask[].
#define SAMESUBEXP(L_evel) \
(! ((PIndex[0] ^ PIndex[pop1 - 1]) & subexp_mask[L_evel]))
// Set PjpParent to a null JP appropriate for the level of the node to which it
// points, which is 1 less than the level of the node in which the JP resides,
// which is by definition Level:
//
// Note: This can set the JPMs JP to an invalid jp_Type, but it doesnt
// matter because the JPM is deleted by the caller.
#define SETJPNULL_PARENT \
JU_JPSETADT(PjpParent, 0, 0, cJU_JPNULL1 + Level - 1);
// Variation to set a specified JP (in a branch being built) to a precomputed
// null JP:
#define SETJPNULL(Pjp) *(Pjp) = JPnull
// Handle complete (as opposed to partial) memory allocation failure: Set the
// parent JP to an appropriate null type (to leave a consistent tree), zero the
// callers population count, and return FALSE:
//
// Note: At Level == cJU_ROOTSTATE this sets the JPMs JPs jp_Type to a bogus
// value, but it doesnt matter because the JPM should be deleted by the
// caller.
#define NOMEM { SETJPNULL_PARENT; *PPop1 = 0; return(FALSE); }
// Allocate a Leaf1-N and save the address in Pjll; in case of failure, NOMEM:
#define ALLOCLEAF(AllocLeaf) \
if ((PjllRaw = AllocLeaf(pop1, Pjpm)) == (Pjll_t) NULL) NOMEM; \
Pjll = P_JLL(PjllRaw);
// Copy indexes smaller than words (and values which are whole words) from
// given arrays to immediate indexes or a leaf:
//
// TBD: These macros overlap with some of the code in JudyCascade.c; do some
// merging? That file has functions while these are macros.
#define COPYTOLEAF_EVEN_SUB(Pjll,LeafType) \
{ \
LeafType * P_leaf = (LeafType *) (Pjll); \
Word_t p_op1 = pop1; \
PWord_t P_Index = PIndex; \
\
assert(pop1 > 0); \
\
do { *P_leaf++ = *P_Index++; /* truncates */\
} while (--(p_op1)); \
}
#define COPYTOLEAF_ODD_SUB(cLevel,Pjll,Copy) \
{ \
uint8_t * P_leaf = (uint8_t *) (Pjll); \
Word_t p_op1 = pop1; \
PWord_t P_Index = PIndex; \
\
assert(pop1 > 0); \
\
do { \
Copy(P_leaf, *P_Index); \
P_leaf += (cLevel); ++P_Index; \
} while (--(p_op1)); \
}
#ifdef JUDY1
#define COPYTOLEAF_EVEN(Pjll,LeafType) COPYTOLEAF_EVEN_SUB(Pjll,LeafType)
#define COPYTOLEAF_ODD(cLevel,Pjll,Copy) COPYTOLEAF_ODD_SUB(cLevel,Pjll,Copy)
#else // JUDYL adds copying of values:
#define COPYTOLEAF_EVEN(Pjll,LeafType) \
{ \
COPYTOLEAF_EVEN_SUB(Pjll,LeafType) \
JU_COPYMEM(Pjv, PValue, pop1); \
}
#define COPYTOLEAF_ODD(cLevel,Pjll,Copy) \
{ \
COPYTOLEAF_ODD_SUB( cLevel,Pjll,Copy) \
JU_COPYMEM(Pjv, PValue, pop1); \
}
#endif
// Set the JP type for an immediate index, where BaseJPType is JPIMMED_*_02:
#define SETIMMTYPE(BaseJPType) (PjpParent->jp_Type) = (BaseJPType) + pop1 - 2
// Allocate and populate a Leaf1-N:
//
// Build MAKELEAF_EVEN() and MAKELEAF_ODD() using macros for common code.
#define MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType) \
ALLOCLEAF(AllocLeaf); \
JUDYLCODE(Pjv = ValueArea(Pjll, pop1))
#define MAKELEAF_SUB2(cLevel,JPType) \
{ \
Word_t D_cdP0; \
assert(pop1 - 1 <= cJU_POP0MASK(cLevel)); \
D_cdP0 = (*PIndex & cJU_DCDMASK(cLevel)) | (pop1 - 1); \
JU_JPSETADT(PjpParent, (Word_t)PjllRaw, D_cdP0, JPType); \
}
#define MAKELEAF_EVEN(cLevel,JPType,AllocLeaf,ValueArea,LeafType) \
MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType); \
COPYTOLEAF_EVEN(Pjll, LeafType); \
MAKELEAF_SUB2(cLevel, JPType)
#define MAKELEAF_ODD(cLevel,JPType,AllocLeaf,ValueArea,Copy) \
MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType); \
COPYTOLEAF_ODD(cLevel, Pjll, Copy); \
MAKELEAF_SUB2(cLevel, JPType)
// Ensure that the indexes to be stored in immediate indexes or a leaf are
// sorted:
//
// This check is pure overhead, but required in order to protect the Judy array
// against caller error, to avoid a later corruption or core dump from a
// seemingly valid Judy array. Do this check piecemeal at the leaf level while
// the indexes are already in the cache. Higher-level order-checking occurs
// while building branches.
//
// Note: Any sorting error in the expanse of a single immediate indexes JP or
// a leaf => save no indexes in that expanse.
#define CHECKLEAFORDER \
{ \
for (offset = 1; offset < pop1; ++offset) \
{ \
if (PIndex[offset - 1] >= PIndex[offset]) \
{ \
SETJPNULL_PARENT; \
*PPop1 = 0; \
JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED); \
return(FALSE); \
} \
} \
}
// ------ START OF CODE ------
assert( Level >= 1);
assert( Level <= cJU_ROOTSTATE);
assert((Level < cJU_ROOTSTATE) || (pop1 > cJU_LEAFW_MAXPOP1));
// CHECK FOR TOP LEVEL:
//
// Special case: If at the top level (PjpParent is in the JPM), a top-level
// branch must be created, even if its a BranchL with just one JP. (The JPM
// cannot point to a leaf because the leaf would have to be a lower-level,
// higher-capacity leaf under a narrow pointer (otherwise a root-level leaf
// would suffice), and the JPMs JP cant handle a narrow pointer because the
// jp_DcdPopO field isnt big enough.) Otherwise continue to check for a pop1
// small enough to support immediate indexes or a leaf before giving up and
// making a lower-level branch.
if (Level == cJU_ROOTSTATE)
{
levelsub = cJU_ROOTSTATE;
goto BuildBranch2;
}
assert(Level < cJU_ROOTSTATE);
// SKIP JPIMMED_*_01:
//
// Immeds with pop1 == 1 should be handled in-line during branch construction.
assert(pop1 > 1);
// BUILD JPIMMED_*_02+:
//
// The starting address of the indexes depends on Judy1 or JudyL; also, JudyL
// includes a pointer to a values-only leaf.
if (pop1 <= immed_maxpop1[Level]) // note: always < root level.
{
JUDY1CODE(uint8_t * Pjll = (uint8_t *) (PjpParent->jp_1Index);)
JUDYLCODE(uint8_t * Pjll = (uint8_t *) (PjpParent->jp_LIndex);)
CHECKLEAFORDER; // indexes to be stored are sorted.
#ifdef JUDYL
if ((PjvRaw = j__udyLAllocJV(pop1, Pjpm)) == (Pjv_t) NULL)
NOMEM;
(PjpParent->jp_Addr) = (Word_t) PjvRaw;
Pjv = P_JV(PjvRaw);
#endif
switch (Level)
{
case 1: COPYTOLEAF_EVEN(Pjll, uint8_t);
SETIMMTYPE(cJU_JPIMMED_1_02);
break;
#if (defined(JUDY1) || defined(JU_64BIT))
case 2: COPYTOLEAF_EVEN(Pjll, uint16_t);
SETIMMTYPE(cJU_JPIMMED_2_02);
break;
case 3: COPYTOLEAF_ODD(3, Pjll, JU_COPY3_LONG_TO_PINDEX);
SETIMMTYPE(cJU_JPIMMED_3_02);
break;
#endif
#if (defined(JUDY1) && defined(JU_64BIT))
case 4: COPYTOLEAF_EVEN(Pjll, uint32_t);
SETIMMTYPE(cJ1_JPIMMED_4_02);
break;
case 5: COPYTOLEAF_ODD(5, Pjll, JU_COPY5_LONG_TO_PINDEX);
SETIMMTYPE(cJ1_JPIMMED_5_02);
break;
case 6: COPYTOLEAF_ODD(6, Pjll, JU_COPY6_LONG_TO_PINDEX);
SETIMMTYPE(cJ1_JPIMMED_6_02);
break;
case 7: COPYTOLEAF_ODD(7, Pjll, JU_COPY7_LONG_TO_PINDEX);
SETIMMTYPE(cJ1_JPIMMED_7_02);
break;
#endif
default: assert(FALSE); // should be impossible.
}
return(TRUE); // note: no children => no *PPop1 mods.
} // JPIMMED_*_02+
// BUILD JPLEAF*:
//
// This code is a little tricky. The method is: For each level starting at
// the present Level down through levelsub = 1, and then as a special case for
// LeafB1 and FullPop (which are also at levelsub = 1 but have different
// capacity, see later), check if pop1 fits in a leaf (using leaf_maxpop1[])
// at that level. If so, except for Level == levelsub, check if all of the
// current indexes to be stored are in the same (narrow) subexpanse, that is,
// the digits from Level to levelsub + 1, inclusive, are identical between the
// first and last index in the (sorted) list (in PIndex). If this condition is
// satisfied at any level, build a leaf at that level (under a narrow pointer
// if Level > levelsub).
//
// Note: Doing the search in this order results in storing the indexes in
// "least compressed form."
for (levelsub = Level; levelsub >= 1; --levelsub)
{
Pjll_t PjllRaw;
Pjll_t Pjll;
// Check if pop1 is too large to fit in a leaf at levelsub; if so, try the next
// lower level:
if (pop1 > leaf_maxpop1[levelsub]) continue;
// If pop1 fits in a leaf at levelsub, but levelsub is lower than Level, must
// also check whether all the indexes in the expanse to store can in fact be
// placed under a narrow pointer; if not, a leaf cannot be used, at this or any
// lower level (levelsub):
if ((levelsub < Level) && (! SAMESUBEXP(levelsub)))
goto BuildBranch; // cant use a narrow, need a branch.
// Ensure valid pop1 and all indexes are in fact common through Level:
assert(pop1 <= cJU_POP0MASK(Level) + 1);
assert(! ((PIndex[0] ^ PIndex[pop1 - 1]) & cJU_DCDMASK(Level)));
CHECKLEAFORDER; // indexes to be stored are sorted.
// Build correct type of leaf:
//
// Note: The jp_DcdPopO and jp_Type assignments in MAKELEAF_* happen correctly
// for the levelsub (not Level) of the new leaf, even if its under a narrow
// pointer.
switch (levelsub)
{
#if (defined(JUDYL) || (! defined(JU_64BIT)))
case 1: MAKELEAF_EVEN(1, cJU_JPLEAF1, j__udyAllocJLL1,
JL_LEAF1VALUEAREA, uint8_t);
break;
#endif
case 2: MAKELEAF_EVEN(2, cJU_JPLEAF2, j__udyAllocJLL2,
JL_LEAF2VALUEAREA, uint16_t);
break;
case 3: MAKELEAF_ODD( 3, cJU_JPLEAF3, j__udyAllocJLL3,
JL_LEAF3VALUEAREA, JU_COPY3_LONG_TO_PINDEX);
break;
#ifdef JU_64BIT
case 4: MAKELEAF_EVEN(4, cJU_JPLEAF4, j__udyAllocJLL4,
JL_LEAF4VALUEAREA, uint32_t);
break;
case 5: MAKELEAF_ODD( 5, cJU_JPLEAF5, j__udyAllocJLL5,
JL_LEAF5VALUEAREA, JU_COPY5_LONG_TO_PINDEX);
break;
case 6: MAKELEAF_ODD( 6, cJU_JPLEAF6, j__udyAllocJLL6,
JL_LEAF6VALUEAREA, JU_COPY6_LONG_TO_PINDEX);
break;
case 7: MAKELEAF_ODD( 7, cJU_JPLEAF7, j__udyAllocJLL7,
JL_LEAF7VALUEAREA, JU_COPY7_LONG_TO_PINDEX);
break;
#endif
default: assert(FALSE); // should be impossible.
}
return(TRUE); // note: no children => no *PPop1 mods.
} // JPLEAF*
// BUILD JPLEAF_B1 OR JPFULLPOPU1:
//
// See above about JPLEAF*. If pop1 doesnt fit in any level of linear leaf,
// it might still fit in a LeafB1 or FullPop, perhaps under a narrow pointer.
if ((Level == 1) || SAMESUBEXP(1)) // same until last digit.
{
Pjlb_t PjlbRaw; // for bitmap leaf.
Pjlb_t Pjlb;
assert(pop1 <= cJU_JPFULLPOPU1_POP0 + 1);
CHECKLEAFORDER; // indexes to be stored are sorted.
#ifdef JUDY1
// JPFULLPOPU1:
if (pop1 == cJU_JPFULLPOPU1_POP0 + 1)
{
Word_t Addr = PjpParent->jp_Addr;
Word_t DcdP0 = (*PIndex & cJU_DCDMASK(1))
| cJU_JPFULLPOPU1_POP0;
JU_JPSETADT(PjpParent, Addr, DcdP0, cJ1_JPFULLPOPU1);
return(TRUE);
}
#endif
// JPLEAF_B1:
if ((PjlbRaw = j__udyAllocJLB1(Pjpm)) == (Pjlb_t) NULL)
NOMEM;
Pjlb = P_JLB(PjlbRaw);
for (offset = 0; offset < pop1; ++offset)
JU_BITMAPSETL(Pjlb, PIndex[offset]);
retval = TRUE; // default.
#ifdef JUDYL
// Build subexpanse values-only leaves (LeafVs) under LeafB1:
for (offset = 0; offset < cJU_NUMSUBEXPL; ++offset)
{
if (! (pop1sub = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, offset))))
continue; // skip empty subexpanse.
// Allocate one LeafV = JP subarray; if out of memory, clear bitmaps for higher
// subexpanses and adjust *PPop1:
if ((PjvRaw = j__udyLAllocJV(pop1sub, Pjpm))
== (Pjv_t) NULL)
{
for (/* null */; offset < cJU_NUMSUBEXPL; ++offset)
{
*PPop1 -= j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, offset));
JU_JLB_BITMAP(Pjlb, offset) = 0;
}
retval = FALSE;
break;
}
// Populate values-only leaf and save the pointer to it:
Pjv = P_JV(PjvRaw);
JU_COPYMEM(Pjv, PValue, pop1sub);
JL_JLB_PVALUE(Pjlb, offset) = PjvRaw; // first-tier pointer.
PValue += pop1sub;
} // for each subexpanse
#endif // JUDYL
// Attach new LeafB1 to parent JP; note use of *PPop1 possibly < pop1:
JU_JPSETADT(PjpParent, (Word_t) PjlbRaw,
(*PIndex & cJU_DCDMASK(1)) | (*PPop1 - 1), cJU_JPLEAF_B1);
return(retval);
} // JPLEAF_B1 or JPFULLPOPU1
// BUILD JPBRANCH_U*:
//
// Arriving at BuildBranch means Level < top level but the pop1 is too large
// for immediate indexes or a leaf, even under a narrow pointer, including a
// LeafB1 or FullPop at level 1. This implies SAMESUBEXP(1) == FALSE, that is,
// the indexes to be stored "branch" at level 2 or higher.
BuildBranch: // come here directly if a leaf wont work.
assert(Level >= 2);
assert(Level < cJU_ROOTSTATE);
assert(! SAMESUBEXP(1)); // sanity check, see above.
// Determine the appropriate level for a new branch node; see if a narrow
// pointer can be used:
//
// This can be confusing. The branch is required at the lowest level L where
// the indexes to store are not in the same subexpanse at level L-1. Work down
// from Level to tree level 3, which is 1 above the lowest tree level = 2 at
// which a branch can be used. Theres no need to check SAMESUBEXP at level 2
// because its known to be false at level 2-1 = 1.
//
// Note: Unlike for a leaf node, a narrow pointer is always used for a branch
// if possible, that is, maximum compression is always used, except at the top
// level of the tree, where a JPM cannot support a narrow pointer, meaning a
// top BranchL can have a single JP (fanout = 1); but that case jumps directly
// to BuildBranch2.
//
// Note: For 32-bit systems the only usable values for a narrow pointer are
// Level = 3 and levelsub = 2; 64-bit systems have many more choices; but
// hopefully this for-loop is fast enough even on a 32-bit system.
//
// TBD: If not fast enough, #ifdef JU_64BIT and handle the 32-bit case faster.
for (levelsub = Level; levelsub >= 3; --levelsub) // see above.
if (! SAMESUBEXP(levelsub - 1)) // at limit of narrow pointer.
break; // put branch at levelsub.
BuildBranch2: // come here directly for Level = levelsub = cJU_ROOTSTATE.
assert(levelsub >= 2);
assert(levelsub <= Level);
// Initially build a BranchU:
//
// Always start with a BranchU because the number of populated subexpanses is
// not yet known. Use digitmask, digitshifted, and digitshincr to avoid
// expensive variable shifts within JU_DIGITATSTATE within the loop.
//
// TBD: The use of digitmask, etc. results in more increment operations per
// loop, is there an even faster way?
//
// TBD: Would it pay to pre-count the populated JPs (subexpanses) and
// pre-compress the branch, that is, build a BranchL or BranchB immediately,
// also taking account of opportunistic uncompression rules? Probably not
// because at high levels of the tree there might be huge numbers of indexes
// (hence cache lines) to scan in the PIndex array to determine the fanout
// (number of JPs) needed.
if ((PjbuRaw = j__udyAllocJBU(Pjpm)) == (Pjbu_t) NULL) NOMEM;
Pjbu = P_JBU(PjbuRaw);
JPtype_null = cJU_JPNULL1 + levelsub - 2; // in new BranchU.
JU_JPSETADT(&JPnull, 0, 0, JPtype_null);
Pjp = Pjbu->jbu_jp; // for convenience in loop.
numJPs = 0; // non-null in the BranchU.
digitmask = cJU_MASKATSTATE(levelsub); // see above.
digitshincr = 1UL << (cJU_BITSPERBYTE * (levelsub - 1));
retval = TRUE;
// Scan and populate JPs (subexpanses):
//
// Look for all indexes matching each digit in the BranchU (at the correct
// levelsub), and meanwhile notice any sorting error. Increment PIndex (and
// PValue) and reduce pop1 for each subexpanse handled successfully.
for (digit = digitshifted = 0;
digit < cJU_BRANCHUNUMJPS;
++digit, digitshifted += digitshincr, ++Pjp)
{
DBGCODE(Word_t pop1subprev;)
assert(pop1 != 0); // end of indexes is handled elsewhere.
// Count indexes in digits subexpanse:
for (pop1sub = 0; pop1sub < pop1; ++pop1sub)
if (digitshifted != (PIndex[pop1sub] & digitmask)) break;
// Empty subexpanse (typical, performance path) or sorting error (rare):
if (pop1sub == 0)
{
if (digitshifted < (PIndex[0] & digitmask))
{ SETJPNULL(Pjp); continue; } // empty subexpanse.
assert(pop1 < *PPop1); // did save >= 1 index and decr pop1.
JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED);
goto AbandonBranch;
}
// Non-empty subexpanse:
//
// First shortcut by handling pop1sub == 1 (JPIMMED_*_01) inline locally.
if (pop1sub == 1) // note: can be at root level.
{
Word_t Addr = 0;
JUDYLCODE(Addr = (Word_t) (*PValue++);)
JU_JPSETADT(Pjp, Addr, *PIndex, cJU_JPIMMED_1_01 + levelsub -2);
++numJPs;
if (--pop1) { ++PIndex; continue; } // more indexes to store.
++digit; ++Pjp; // skip JP just saved.
goto ClearBranch; // save time.
}
// Recurse to populate one digits (subexpanses) JP; if successful, skip
// indexes (and values) just stored (performance path), except when expanse is
// completely stored:
DBGCODE(pop1subprev = pop1sub;)
if (j__udyInsArray(Pjp, levelsub - 1, &pop1sub, (PWord_t) PIndex,
#ifdef JUDYL
(Pjv_t) PValue,
#endif
Pjpm))
{ // complete success.
++numJPs;
assert(pop1subprev == pop1sub);
assert(pop1 >= pop1sub);
if ((pop1 -= pop1sub) != 0) // more indexes to store:
{
PIndex += pop1sub; // skip indexes just stored.
JUDYLCODE(PValue += pop1sub;)
continue;
}
// else leave PIndex in BranchUs expanse.
// No more indexes to store in BranchUs expanse:
++digit; ++Pjp; // skip JP just saved.
goto ClearBranch; // save time.
}
// Handle any error at a lower level of recursion:
//
// In case of partial success, pop1sub != 0, but it was reduced from the value
// passed to j__udyInsArray(); skip this JP later during ClearBranch.
assert(pop1subprev > pop1sub); // check j__udyInsArray().
assert(pop1 > pop1sub); // check j__udyInsArray().
if (pop1sub) // partial success.
{ ++digit; ++Pjp; ++numJPs; } // skip JP just saved.
pop1 -= pop1sub; // deduct saved indexes if any.
// Same-level sorting error, or any lower-level error; abandon the rest of the
// branch:
//
// Arrive here with pop1 = remaining unsaved indexes (always non-zero). Adjust
// the *PPop1 value to record and return, modify retval, and use ClearBranch to
// finish up.
AbandonBranch:
assert(pop1 != 0); // more to store, see above.
assert(pop1 <= *PPop1); // sanity check.
*PPop1 -= pop1; // deduct unsaved indexes.
pop1 = 0; // to avoid error later.
retval = FALSE;
// Error (rare), or end of indexes while traversing new BranchU (performance
// path); either way, mark the remaining JPs, if any, in the BranchU as nulls
// and exit the loop:
//
// Arrive here with digit and Pjp set to the first JP to set to null.
ClearBranch:
for (/* null */; digit < cJU_BRANCHUNUMJPS; ++digit, ++Pjp)
SETJPNULL(Pjp);
break; // saves one more compare.
} // for each digit
// FINISH JPBRANCH_U*:
//
// Arrive here with a BranchU built under Pjbu, numJPs set, and either: retval
// == TRUE and *PPop1 unmodified, or else retval == FALSE, *PPop1 set to the
// actual number of indexes saved (possibly 0 for complete failure at a lower
// level upon the first call of j__udyInsArray()), and the Judy error set in
// Pjpm. Either way, PIndex points to an index within the expanse just
// handled.
Pjbany = (Word_t) PjbuRaw; // default = use this BranchU.
JPtype = branchU_JPtype[levelsub];
// Check for complete failure above:
assert((! retval) || *PPop1); // sanity check.
if ((! retval) && (*PPop1 == 0)) // nothing stored, full failure.
{
j__udyFreeJBU(PjbuRaw, Pjpm);
SETJPNULL_PARENT;
return(FALSE);
}
// Complete or partial success so far; watch for sorting error after the
// maximum digit (255) in the BranchU, which is indicated by having more
// indexes to store in the BranchUs expanse:
//
// For example, if an index to store has a digit of 255 at levelsub, followed
// by an index with a digit of 254, the for-loop above runs out of digits
// without reducing pop1 to 0.
if (pop1 != 0)
{
JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED);
*PPop1 -= pop1; // deduct unsaved indexes.
retval = FALSE;
}
assert(*PPop1 != 0); // branch (still) cannot be empty.
// OPTIONALLY COMPRESS JPBRANCH_U*:
//
// See if the BranchU should be compressed to a BranchL or BranchB; if so, do
// that and free the BranchU; otherwise just use the existing BranchU. Follow
// the same rules as in JudyIns.c (version 4.95): Only check local population
// (cJU_OPP_UNCOMP_POP0) for BranchL, and only check global memory efficiency
// (JU_OPP_UNCOMPRESS) for BranchB. TBD: Have the rules changed?
//
// Note: Because of differing order of operations, the latter compression
// might not result in the same set of branch nodes as a series of sequential
// insertions.
//
// Note: Allocating a BranchU only to sometimes convert it to a BranchL or
// BranchB is unfortunate, but attempting to work with a temporary BranchU on
// the stack and then allocate and keep it as a BranchU in many cases is worse
// in terms of error handling.
// COMPRESS JPBRANCH_U* TO JPBRANCH_L*:
if (numJPs <= cJU_BRANCHLMAXJPS) // JPs fit in a BranchL.
{
Pjbl_t PjblRaw = (Pjbl_t) NULL; // new BranchL; init for cc.
Pjbl_t Pjbl;
if ((*PPop1 > JU_BRANCHL_MAX_POP) // pop too high.
|| ((PjblRaw = j__udyAllocJBL(Pjpm)) == (Pjbl_t) NULL))
{ // cant alloc BranchL.
goto SetParent; // just keep BranchU.
}
Pjbl = P_JBL(PjblRaw);
// Copy BranchU JPs to BranchL:
(Pjbl->jbl_NumJPs) = numJPs;
offset = 0;
for (digit = 0; digit < cJU_BRANCHUNUMJPS; ++digit)
{
if ((((Pjbu->jbu_jp) + digit)->jp_Type) == JPtype_null)
continue;
(Pjbl->jbl_Expanse[offset ]) = digit;
(Pjbl->jbl_jp [offset++]) = Pjbu->jbu_jp[digit];
}
assert(offset == numJPs); // found same number.
// Free the BranchU and prepare to use the new BranchL instead:
j__udyFreeJBU(PjbuRaw, Pjpm);
Pjbany = (Word_t) PjblRaw;
JPtype = branchL_JPtype[levelsub];
} // compress to BranchL
// COMPRESS JPBRANCH_U* TO JPBRANCH_B*:
//
// If unable to allocate the BranchB or any JP subarray, free all related
// memory and just keep the BranchU.
//
// Note: This use of JU_OPP_UNCOMPRESS is a bit conservative because the
// BranchU is already allocated while the (presumably smaller) BranchB is not,
// the opposite of how its used in single-insert code.
else
{
Pjbb_t PjbbRaw = (Pjbb_t) NULL; // new BranchB; init for cc.
Pjbb_t Pjbb;
Pjp_t Pjp2; // in BranchU.
if ((*PPop1 > JU_BRANCHB_MAX_POP) // pop too high.
|| ((PjbbRaw = j__udyAllocJBB(Pjpm)) == (Pjbb_t) NULL))
{ // cant alloc BranchB.
goto SetParent; // just keep BranchU.
}
Pjbb = P_JBB(PjbbRaw);
// Set bits in bitmap for populated subexpanses:
Pjp2 = Pjbu->jbu_jp;
for (digit = 0; digit < cJU_BRANCHUNUMJPS; ++digit)
if ((((Pjbu->jbu_jp) + digit)->jp_Type) != JPtype_null)
JU_BITMAPSETB(Pjbb, digit);
// Copy non-null JPs to BranchB JP subarrays:
for (offset = 0; offset < cJU_NUMSUBEXPB; ++offset)
{
Pjp_t PjparrayRaw;
Pjp_t Pjparray;
if (! (numJPs = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, offset))))
continue; // skip empty subexpanse.
// If unable to allocate a JP subarray, free all BranchB memory so far and
// continue to use the BranchU:
if ((PjparrayRaw = j__udyAllocJBBJP(numJPs, Pjpm))
== (Pjp_t) NULL)
{
while (offset-- > 0)
{
if (JU_JBB_PJP(Pjbb, offset) == (Pjp_t) NULL) continue;
j__udyFreeJBBJP(JU_JBB_PJP(Pjbb, offset),
j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, offset)),
Pjpm);
}
j__udyFreeJBB(PjbbRaw, Pjpm);
goto SetParent; // keep BranchU.
}
// Set one JP subarray pointer and copy the subexpanses JPs to the subarray:
//
// Scan the BranchU for non-null JPs until numJPs JPs are copied.
JU_JBB_PJP(Pjbb, offset) = PjparrayRaw;
Pjparray = P_JP(PjparrayRaw);
while (numJPs-- > 0)
{
while ((Pjp2->jp_Type) == JPtype_null)
{
++Pjp2;
assert(Pjp2 < (Pjbu->jbu_jp) + cJU_BRANCHUNUMJPS);
}
*Pjparray++ = *Pjp2++;
}
} // for each subexpanse
// Free the BranchU and prepare to use the new BranchB instead:
j__udyFreeJBU(PjbuRaw, Pjpm);
Pjbany = (Word_t) PjbbRaw;
JPtype = branchB_JPtype[levelsub];
} // compress to BranchB
// COMPLETE OR PARTIAL SUCCESS:
//
// Attach new branch (under Pjp, with JPtype) to parent JP; note use of *PPop1,
// possibly reduced due to partial failure.
SetParent:
(PjpParent->jp_Addr) = Pjbany;
(PjpParent->jp_Type) = JPtype;
if (Level < cJU_ROOTSTATE) // PjpParent not in JPM:
{
Word_t DcdP0 = (*PIndex & cJU_DCDMASK(levelsub)) | (*PPop1 - 1);
JU_JPSETADT(PjpParent ,Pjbany, DcdP0, JPtype);
}
return(retval);
} // j__udyInsArray()
|