1 module judy.judyl;
2 
3 import core.exception;
4 import core.memory;
5 import std.array;
6 import std.range;
7 import std.traits;
8 
9 import judy.libjudy;
10 
11 /*
12     Provides D like wrapper around the libjudy C library.  Items in the array
13     are indexed by size_t.
14 
15     Supports containing the following types:
16 
17         - Heap allocated references (classes)
18         - Pointers to heap allocated structs, primitives (no arrays)
19         - Scalar types (these are copied, see std.traits.isScalarType)
20 
21     Since libjudy is a C library, management of memory becomes an issue.
22     By default for non scalar types JudyLArray will add stored
23     items to the GC's roots.  This ensures that if the only pointer
24     to your items is within the judy array that the items will not
25     be collected.
26 
27     If you don't want to use the GC (you're using malloc or your own allocator),
28     then it can be turned off by passing UseGC = false to the template
29     parameters.
30 
31     NOTE: Passing in pointers to anything on the stack is very bad
32     and will probably cause nasty things to happen.  JudyLArray
33     assumes (other than for scalars which it just copies into itself)
34     that your items are long living and won't be freed
35     out from underneath it. You have been warned.
36 */
37 
38 struct JudyLArray(ElementType, bool UseGC = true) if (
39     isPointer!ElementType || // ElementType is a pointer
40     is(ElementType : Object) || // ElementType is an object
41     isScalarType!ElementType // ElementType is a scalar
42 )
43 {
44     public:
45         @disable this(this);
46 
47         ~this()
48         {
49             static if (UseGC && hasIndirections!ElementType)
50             {
51                 // Iterate over all entries and remove them from the GC
52                 // roots
53                 foreach(ref entry; this[])
54                 {
55                     GC.removeRoot(cast(void*)entry.value);
56                     GC.clrAttr(cast(void*)entry.value, GC.BlkAttr.NO_MOVE);
57                 }
58             }
59             // Free the actual array structure
60             JudyLFreeArray(&array_, NO_ERROR);
61         }
62 
63         // Is the array empty?
64         @property bool empty() const nothrow @nogc
65         {
66             return count == 0;
67         }
68 
69         // Returns number of elements in the Judy array
70         @property size_t count() const nothrow @nogc
71         {
72             return JudyLCount(array_, 0, -1, NO_ERROR);
73         }
74 
75         @property auto length() const nothrow @nogc
76         {
77             return size_t.sizeof;
78         }
79 
80         // Returns the index and element of first entry. Throws range error if empty.
81         @property JudyLEntry front()
82         {
83             size_t index = 0;
84             auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR);
85 
86             if (value !is null)
87             {
88                 return JudyLEntry(index, *value);
89             }
90             throw new RangeError();
91         }
92 
93         // Returns the index and element of first entry. Throws range error if empty.
94         @property const(JudyLEntry) front() const
95         {
96             size_t index = 0;
97             auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR);
98 
99             if (value !is null)
100             {
101                 return JudyLEntry(index, *value);
102             }
103             throw new RangeError();
104         }
105 
106         // Removes first element. Throws RangeError if empty.
107         void popFront()
108         {
109             remove(first());
110         }
111 
112         // Gets index and element of last entry. Throws RangeError if empty.
113         @property JudyLEntry back()
114         {
115             size_t index = -1;
116             auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR);
117 
118             if (value !is null)
119             {
120                 return JudyLEntry(index, *value);
121             }
122             throw new RangeError();
123         }
124 
125         // Gets index and element of last entry. Throws RangeError if empty.
126         @property const(JudyLEntry) back() const
127         {
128             size_t index = -1;
129             auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR);
130 
131             if (value !is null)
132             {
133                 return JudyLEntry(index, *value);
134             }
135             throw new RangeError();
136         }
137 
138         // Removes last element. Throws RangeError if empty.
139         void popBack()
140         {
141             remove(last());
142         }
143 
144         // Create a slice over the underlying Judy array
145         auto opSlice() nothrow @nogc
146         {
147             return JudyLArrayRange!()(array_);
148         }
149 
150         // Create a slice over the underlying Judy array
151         auto opSlice() const nothrow @nogc
152         {
153             return JudyLArrayRange!(true)(array_);
154         }
155 
156         // Create a slice with given indices over the underlying Judy array
157         auto opSlice(const size_t start, const size_t end) nothrow @nogc
158         {
159             return JudyLArrayRange!()(array_, start, end);
160         }
161 
162         // Create a slice with given indices over the underlying Judy array
163         auto opSlice(const size_t start, const size_t end) const nothrow @nogc
164         {
165             return JudyLArrayRange!(true)(array_, start, end);
166         }
167 
168         // Return highest index of element in array
169         size_t opDollar() const
170         {
171             if (empty)
172             {
173                 throw new RangeError();
174             }
175             return back.index;
176         }
177         
178         // Get element at index
179         ElementType opIndex(const size_t index)
180         {
181             return get(index);
182         }
183         
184         // Get element at index
185         const(ElementType) opIndex(const size_t index) const
186         {
187             return get(index);
188         }
189         
190         // Assign element to index
191         void opIndexAssign(ElementType value, const size_t index)
192         {
193             insert(index, value);
194         }
195 
196         // Add element at index
197         void add(const size_t index, ElementType value)
198         {
199             insert(index, value);
200         }
201 
202         // Remove element at index
203         bool remove(const size_t index) nothrow
204         {
205             ElementType element;
206             if (!at(index, element))
207             {
208                 return false;
209             }
210 
211             auto deleted = JudyLDel(&array_, index, NO_ERROR) == 1;
212 
213             // Remove explicit root from GC since instance is back under runtime
214             static if (UseGC && hasIndirections!ElementType)
215             {
216                 if (deleted)
217                 {
218                     GC.removeRoot(cast(void*)element);
219                     GC.clrAttr(cast(void*)element, GC.BlkAttr.NO_MOVE);
220                 }
221             }
222 
223             return deleted;
224         }
225 
226         // Get element at. Return true if found. Places element into value.
227         bool at(const size_t index, out ElementType value) const nothrow @nogc
228         {
229             auto element = JudyLGet(array_, index, NO_ERROR);
230             if (element is null)
231             {
232                 return false;
233             }
234             value = cast(ElementType)(*element);
235             return true;
236         }
237 
238         // Check if has element at index
239         bool has(const size_t index) const nothrow @nogc
240         {
241             return JudyLGet(array_, index, NO_ERROR) !is null;
242         }
243 
244         // Find first element >= index. Returns true if found, sets index and element.
245         bool first(ref size_t index, out ElementType found) const nothrow @nogc
246         {
247             auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR);
248             if (value == null)
249             {
250                 return false;
251             }
252             found = cast(ElementType)(*value);
253             return true;
254         }
255 
256         // Find first elem >= index. Returns true if found. Sets index.
257         bool first(ref size_t index) const nothrow @nogc
258         {
259             return JudyLFirst(array_, &index, NO_ERROR) !is null;
260         }
261 
262         // Get index of first element. Throws RangeError if empty.
263         size_t first() const
264         {
265             return front.index;
266         }
267 
268         // Find next element > index. Returns true if found. Sets index and element.
269         bool next(ref size_t index, out ElementType found) const nothrow @nogc
270         {
271             auto value = cast(ElementType**)JudyLNext(array_, &index, NO_ERROR);
272             if (value == null)
273             {
274                 return false;
275             }
276             found = cast(ElementType)(*value);
277             return true;
278         }
279 
280         // Find next element > index. Returns true if found. Sets index.
281         bool next(ref size_t index) const nothrow @nogc
282         {
283             return JudyLNext(array_, &index, NO_ERROR) !is null;
284         }
285 
286         // Find prev element < index. Returns true if found. Sets index and element.
287         bool prev(ref size_t index, out ElementType found) const nothrow @nogc
288         {
289             auto value = cast(ElementType**)JudyLPrev(array_, &index, NO_ERROR);
290             if (value == null)
291             {
292                 return false;
293             }
294             found = cast(ElementType)(*value);
295             return true;
296         }
297 
298         // Find prev element < index. Returns true if found. Sets index
299         bool prev(ref size_t index) const nothrow @nogc
300         {
301             return JudyLPrev(array_, &index, NO_ERROR) !is null;
302         }
303 
304         // Find last element <= index. Returns true if found. Sets index and element.
305         bool last(ref size_t index, out ElementType found) const nothrow @nogc
306         {
307             auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR);
308             if (value == null)
309             {
310                 return false;
311             }
312             found = cast(ElementType)(*value);
313             return true;
314         }
315 
316         // Find last element <= index. Returns true if found. Sets index.
317         bool last(ref size_t index) const
318         {
319             return JudyLLast(array_, &index, NO_ERROR) !is null;
320         }
321 
322         // Get index of last element. Throws RangeError if empty.
323         size_t last() const
324         {
325             return back.index;
326         }
327 
328 
329         // Find first empty slot >= index. Returns true if found. Sets index.
330         bool firstEmpty(ref size_t index) const nothrow @nogc
331         {
332             return JudyLFirstEmpty(array_, &index, NO_ERROR) == 1;
333         }
334 
335         // Find next empty slot > index. Returns true if found. Sets index.
336         bool nextEmpty(ref size_t index) const nothrow @nogc
337         {
338             return JudyLNextEmpty(array_, &index, NO_ERROR) == 1;
339         }
340 
341         // Find prev empty slot < index. Returns true if found. Sets index.
342         bool prevEmpty(ref size_t index) const nothrow @nogc
343         {
344             return JudyLPrevEmpty(array_, &index, NO_ERROR) == 1;
345         }
346 
347         // Find last empty slot <= index. Returns true if found. Sets index.
348         bool lastEmpty(ref size_t index) const nothrow @nogc
349         {
350             return JudyLLastEmpty(array_, &index, NO_ERROR) == 1;
351         }
352 
353 
354         // Gets total amount of memory used by population and infrastructure
355         @property size_t memUsed() const nothrow @nogc
356         {
357             return JudyLMemUsed(array_);
358         }
359 
360         // Gets total amount of memory used by population (pointers only)
361         @property size_t memActive() const nothrow @nogc
362         {
363             return JudyLMemActive(array_);
364         }
365 
366     private:
367         void* array_;
368 
369         // Insert element at index. Throws RangeError on insertion error.
370         void insert(const size_t index, ElementType value)
371         {
372             auto element = JudyLIns(&array_, index, NO_ERROR);
373             if (element is null)
374             {
375                 throw new RangeError();
376             }
377 
378             // Add the element's address to the GC roots so it won't
379             // be collected
380             static if (UseGC && hasIndirections!ElementType)
381             {
382                 GC.addRoot(cast(void*)value);
383                 GC.setAttr(cast(void*)value, GC.BlkAttr.NO_MOVE);
384             }
385 
386             *element = cast(ElementType*)value;
387         }
388 
389         /* Get element at index. Throws RangeError if not found. See `at`
390            for exception safe version
391         */
392         ElementType get(const size_t index) const
393         {
394             auto element = JudyLGet(array_, index, NO_ERROR);
395             if (element is null)
396             {
397                 throw new RangeError();
398             }
399             return cast(ElementType)(*element);
400         }
401 
402         // An entry containing the index and element. Used for iteration
403         struct JudyLEntry
404         {
405             private:
406                 const size_t index_;
407                 ElementType* value_;
408 
409             public:
410                 this(const size_t index, ElementType* value)
411                 {
412                     this.index_ = index;
413                     this.value_ = value;
414                 }
415 
416                 @property size_t index() const nothrow @nogc
417                 {
418                     return index_;
419                 }
420 
421                 @property inout(ElementType) value() inout nothrow @nogc
422                 {
423                     return cast(ElementType)(value_);
424                 }
425         }
426 
427         // Iteration struct, allows fast read only iteration of the underlying Judy array
428         struct JudyLArrayRange(bool isConst=false)
429         {
430             public:
431                 // Construct slice over entire array
432                 this(const void* array) nothrow @nogc
433                 {
434                     this(array, 0UL, -1UL);
435                 }
436 
437                 // Construct slice over given range
438                 this (const void* array, const size_t firstIndex, const size_t lastIndex) nothrow @nogc
439                 {
440                     array_ = array;
441                     leftBound_ = firstIndex_ = firstIndex;
442                     rightBound_ = lastIndex_ = lastIndex;
443 
444                     frontPtr_ = cast(ElementType**)JudyLFirst(array, &firstIndex_, NO_ERROR);
445                     backPtr_ = cast(ElementType**)JudyLLast(array, &lastIndex_, NO_ERROR);
446                 }
447 
448                 // Is slice empty?
449                 @property bool empty() const nothrow @nogc
450                 {
451                     return frontPtr_ is null;
452                 }
453 
454                 // Get first element/index of slice.
455                 @property auto front() nothrow @nogc
456                 in
457                 {
458                     assert(!empty);
459                 }
460                 body
461                 {
462                     static if (isConst)
463                     {
464                         return const(JudyLEntry)(firstIndex_, *frontPtr_);
465                     }
466                     else
467                     {
468                         return JudyLEntry(firstIndex_, *frontPtr_);
469                     }
470                 }
471 
472                 // Discard first element and find next
473                 void popFront() nothrow @nogc
474                 {
475                     frontPtr_ = cast(ElementType**)JudyLNext(array_, &firstIndex_, NO_ERROR);
476 
477                     // Empty check
478                     if (frontPtr_ is null)
479                     {
480                        backPtr_ = null;
481                     }
482                 }
483 
484                 // Get last element/index of slice.
485                 @property auto back() nothrow @nogc
486                 in
487                 {
488                     assert(!empty);
489                 }
490                 body
491                 {
492                     static if (isConst)
493                     {
494                         return const(JudyLEntry)(lastIndex_, *backPtr_);
495                     }
496                     else
497                     {
498                         return JudyLEntry(lastIndex_, *backPtr_);
499                     }
500                 }
501 
502                 // Discard last element of slice and find prev
503                 void popBack() nothrow @nogc
504                 {
505                     backPtr_ = cast(ElementType**)JudyLPrev(array_, &lastIndex_, NO_ERROR);
506 
507                     // Empty check
508                     if (backPtr_ is null)
509                     {
510                         frontPtr_ = null;
511                     }
512                 }
513 
514                 // Get element at index. Throws RangeError if out of bounds or not found.
515                 auto opIndex(size_t index) const
516                 {
517                     if (index < leftBound_ || index > rightBound_)
518                     {
519                         throw new RangeError();
520                     }
521 
522                     auto element = cast(ElementType**)JudyLGet(array_, index, NO_ERROR);
523 
524                     if (element is null)
525                     {
526                         throw new RangeError();
527                     }
528 
529                     static if (isConst)
530                     {
531                         return cast(const(ElementType))*element;
532                     }
533                     else
534                     {
535                         return cast(ElementType)*element;
536                     }
537                 }
538 
539                 // Save iteration state
540                 @property auto save() nothrow @nogc
541                 {
542                     return this;
543                 }
544 
545                 // Get count of population in slice
546                 @property auto count() const nothrow @nogc
547                 {
548                     return JudyLCount(array_, leftBound_, rightBound_, NO_ERROR);
549                 }
550 
551                 @property auto length() const nothrow @nogc
552                 {
553                     return size_t.sizeof;
554                 }
555 
556             private:
557                 ElementType** frontPtr_;
558                 ElementType** backPtr_;
559                 size_t leftBound_;
560                 size_t rightBound_;
561                 size_t firstIndex_;
562                 size_t lastIndex_;
563                 const void* array_;
564         }
565 
566         static assert(isInputRange!JudyLArray);
567 
568         static assert(isInputRange!(JudyLArrayRange!(false)));
569         static assert(isForwardRange!(JudyLArrayRange!(false)));
570         static assert(isBidirectionalRange!(JudyLArrayRange!(false)));
571 
572         static assert(isInputRange!(JudyLArrayRange!(true)));
573         static assert(isForwardRange!(JudyLArrayRange!(true)));
574         static assert(isBidirectionalRange!(JudyLArrayRange!(true)));
575 }
576 
577 
578 
579 version (unittest)
580 {
581     import std.algorithm;
582     import std.conv;
583     import std.exception;
584     import std.stdio;
585 
586     class Data
587     {
588       public:
589         this(int x)
590         {
591             this.x = x;
592         }
593 
594         int x;
595     }
596 
597     struct Point
598     {
599         int x;
600         int y;
601     }
602 }
603 
604 
605 unittest
606 {
607     writeln("[UnitTest JudyL] - count");
608 
609     auto array = JudyLArray!Data();
610 
611     auto data = new Data(0);
612 
613     assert(array.count == 0, "Array starting count is 0");
614 
615     array[0] = data;
616     assert(array.count == 1, "Array count updated");
617 
618     array[1] = data;
619     assert(array.count == 2, "Array count updated");
620 
621     array.remove(0);
622     assert(array.count == 1, "Array count updated");
623 
624     array.remove(1);
625     assert(array.count == 0, "Array count updated");
626 }
627 
628 unittest
629 {
630     writeln("[UnitTest JudyL] - empty");
631 
632     auto array = JudyLArray!Data();
633 
634     auto data = new Data(0);
635 
636     assert(array.empty, "Array starts empty");
637 
638     array[0] = data;
639     assert(!array.empty, "Array not empty");
640 
641     array.add(1, data);
642     assert(!array.empty, "Array not empty");
643 
644     array.remove(0);
645     array.remove(1);
646     assert(array.empty, "Array now empty");
647 }
648 
649 unittest
650 {
651     writeln("[UnitTest JudyL] - has");
652 
653     auto array = JudyLArray!Data();
654 
655     auto data = new Data(0);
656 
657     assert(!array.has(0), "Array doesn't have element");
658     assert(!array.has(1), "Array doesn't have element");
659 
660     array[0] = data;
661 
662     assert(array.has(0), "Array has element");
663     assert(!array.has(1), "Array doesn't have element");
664 
665     array[1] = data;
666 
667     assert(array.has(0), "Array has element");
668     assert(array.has(1), "Array has element");
669 }
670 
671 unittest
672 {
673     writeln("[UnitTest JudyL] - at");
674 
675     {
676         auto array = JudyLArray!Data();
677 
678         auto data0 = new Data(0);
679         auto data1 = new Data(1);
680 
681         Data value;
682 
683         assert(!array.at(0, value), "Array doesn't have element");
684         assert(!array.at(1, value), "Array doesn't have element");
685 
686         array[0] = data0;
687         array[1] = data1;
688 
689         assert(array.at(0, value), "Array has element");
690         assert(value == data0);
691 
692         assert(array.at(1, value), "Array has element");
693         assert(value == data1);
694     }
695 
696     {
697         auto array = JudyLArray!(Point*)();
698 
699         auto point0 = new Point(0, 0);
700         auto point1 = new Point(1, 1);
701 
702         Point* value;
703 
704         assert(!array.at(0, value), "Array doesn't have element");
705         assert(!array.at(1, value), "Array doesn't have element");
706 
707         array[0] = point0;
708         array[1] = point1;
709 
710         assert(array.at(0, value), "Array has element");
711         assert(value == point0);
712 
713         assert(array.at(1, value), "Array has element");
714         assert(value == point1);
715     }
716 }
717 
718 unittest
719 {
720     writeln("[UnitTest JudyL] - add");
721 
722     auto array = JudyLArray!Data();
723 
724     auto data0 = new Data(0);
725     auto data1 = new Data(1);
726 
727     array.add(0, data0);
728     array.add(1, data1);
729 
730     assert(array[0] == data0, "Array has element");
731     assert(array[1] == data1, "Array has element");
732 
733     array.add(0,  data1);
734     assert(array[0] == data1, "Element updated");
735 }
736 
737 unittest
738 {
739     writeln("[UnitTest JudyL] - opIndexAssign");
740 
741     auto array = JudyLArray!Data();
742 
743     auto data0 = new Data(0);
744     auto data1 = new Data(1);
745 
746     array.add(0, data0);
747     array.add(1, data1);
748 
749     array[0] = data0;
750     assert(array[0] == data0, "Array has element");
751 
752     array[1] = data1;
753     assert(array[1] == data1, "Array has element");
754 
755     array[0] = data1;
756     assert(array[0] == data1, "Element updated");
757 }
758 
759 unittest
760 {
761     writeln("[UnitTest JudyL] - opIndex");
762 
763     auto array = JudyLArray!Data();
764 
765     auto data0 = new Data(0);
766     auto data1 = new Data(1);
767 
768     assertThrown!RangeError(array[0], "Array doesn't have element");
769     assertThrown!RangeError(array[1], "Array doesn't have element");
770 
771     array[0] = data0;
772     assert(array[0] == data0, "Array has element");
773 
774     array[1] = data1;
775     assert(array[1] == data1, "Array has element");
776 }
777 
778 unittest
779 {
780     writeln("[UnitTest JudyL] - remove");
781 
782     auto array = JudyLArray!Data();
783 
784     auto data = new Data(0);
785 
786     assert(!array.remove(0), "Array doesn't have element");
787 
788     array[0] = data;
789     assert(array.remove(0), "Array had element");
790 
791     assert(!array.has(0), "Element removed");
792 }
793 
794 unittest
795 {
796     writeln("[UnitTest JudyL] - forward iteration");
797 
798     auto array = JudyLArray!Data();
799 
800     auto testrange = iota(100, 1000, 10);
801 
802     Data[int] datas = assocArray(
803         zip(
804             testrange,
805             map!(a => new Data(a))(testrange).array
806         )
807     );
808 
809     foreach(data; array)
810     {
811         assert(false, "Empty array");
812     }
813 
814     // Insert some elements
815     foreach(i; testrange)
816     {
817         array[i] = datas[i];
818     }
819 
820     auto j = 0;
821     foreach(ref data; array)
822     {
823         assert(data.index == testrange[j]);
824         assert(data.value == array[testrange[j++]]);
825     }
826     assert(array.count == testrange.length, "Forward iteration leaves data intact");
827 }
828 
829 unittest
830 {
831     writeln("[UnitTest JudyL] - forward const iteration");
832 
833     auto array = JudyLArray!Data();
834 
835     auto testrange = iota(100, 1000, 10);
836 
837     Data[int] datas = assocArray(
838         zip(
839             testrange,
840             map!(a => new Data(a))(testrange).array
841         )
842     );
843 
844     foreach(data; array)
845     {
846         assert(false, "Empty array");
847     }
848 
849     // Insert some elements
850     foreach(i; testrange)
851     {
852         array[i] = datas[i];
853     }
854 
855     auto cb = (const ref JudyLArray!Data array)
856     {
857         auto j = 0;
858         foreach(const data; array)
859         {
860             assert(data.index == testrange[j]);
861             assert(data.value == array[testrange[j++]]);
862         }
863     };
864 
865     cb(array);
866 
867     assert(array.count == testrange.length, "Forward iteration leaves data intact");
868 }
869 
870 unittest
871 {
872     writeln("[UnitTest JudyL] - front and back");
873 
874     auto array = JudyLArray!Data();
875 
876     auto testrange = iota(100, 1000, 10);
877 
878     Data[int] datas = assocArray(
879         zip(
880             testrange,
881             map!(a => new Data(a))(testrange).array
882         )
883     );
884 
885     // Insert some elements
886     foreach(i; testrange)
887     {
888         array[i] = datas[i];
889     }
890 
891     // Verify front and back
892     assert(array.front.index == 100, "Correct front");
893     assert(array.front.value == datas[100], "Correct front");
894     assert(array.back.index == 990, "Correct back");
895     assert(array.back.value == datas[990], "Correct back");
896 
897 
898     // Remove front
899     array.remove(100);
900     assert(array.front.index == 110, "Front updated");
901     assert(array.front.value == datas[110], "Front updated");
902     assert(array.back.index == 990, "Back unchanged");
903     assert(array.back.value == datas[990], "Back unchanged");
904 
905     // Remove back
906     array.remove(990);
907     assert(array.front.index == 110, "Front unchanged");
908     assert(array.front.value == datas[110], "Front unchanged");
909     assert(array.back.index == 980, "Back updated");
910     assert(array.back.value == datas[980], "Back updated");
911 
912     // Remove middle
913     array.remove(550);
914     assert(array.front.index == 110, "Front unchanged");
915     assert(array.front.value == datas[110], "Front unchanged");
916     assert(array.back.index == 980, "Back updated");
917     assert(array.back.value == datas[980], "Back updated");
918 }
919 
920 unittest
921 {
922     writeln("[UnitTest JudyL] - popFront and popBack");
923 
924     auto array = JudyLArray!Data();
925 
926     auto testrange = iota(0, 10);
927 
928     Data[int] datas = assocArray(
929         zip(
930             testrange,
931             map!(a => new Data(a))(testrange).array
932         )
933     );
934 
935     // Insert some elements
936     foreach(i; testrange)
937     {
938         array[i] = datas[i];
939     }
940 
941     auto first = array.first();
942 
943     auto second = first;
944     array.next(second);
945 
946     auto last = array.last();
947     
948     auto second_last = last;
949     array.prev(second_last);
950 
951     array.popFront();
952     assert(!array.has(first), "Front removed");
953     assert(array.front.index == second, "Front updated");
954     assert(array.has(last), "Back unchanged");
955 
956     array.popBack();
957     assert(!array.has(last), "Back removed");
958     assert(array.back.index == second_last, "Back updated");
959     assert(array.has(second), "Front unchanged");
960 }
961 
962 unittest
963 {
964     writeln("[UnitTest JudyL] - free memory");
965 
966     JudyLArray!Data* ptr;
967 
968     {
969         auto array = JudyLArray!Data();
970 
971         assert(array.memUsed == 0, "No memory used on empty array");
972         assert(array.memActive == 0, "No memory active on empty array");
973 
974         auto testrange = iota(0, 100);
975 
976         Data[int] datas = assocArray(
977             zip(
978                 testrange,
979                 map!(a => new Data(a))(testrange).array
980             )
981         );
982 
983         // Insert some elements
984         foreach(i; testrange)
985         {
986             array[i] = datas[i];
987         }
988 
989         assert(array.count == 100, "Count updated");
990         assert(array.memUsed > 0, "Memory used");
991         assert(array.memActive > 0, "Memory active");
992 
993         ptr = &array;
994     }
995 
996     assert(ptr.count == 0, "Count cleared");
997     assert(ptr.memUsed == 0, "Memory reclaimed");
998     assert(ptr.memActive == 0, "Memory reclaimed");
999 }
1000 
1001 
1002 unittest
1003 {
1004     writeln("[UnitTest JudyL] - opSlice");
1005 
1006     auto array = JudyLArray!Data();
1007 
1008     auto testrange = iota(0, 100);
1009 
1010     Data[int] datas = assocArray(
1011         zip(
1012             testrange,
1013             map!(a => new Data(a))(testrange).array
1014         )
1015     );
1016 
1017     // Test empty
1018     foreach(data; array[])
1019     {
1020         assert(false, "empty array");
1021     }
1022 
1023     // Test one element
1024     array[1000] = datas[0];
1025     int j = 0;
1026     foreach(ref data; array[])
1027     {
1028         assert(j++ == 0, "Called once");
1029         assert(data.index == 1000, "Index preserved");
1030         assert(data.value == datas[0]);
1031     }
1032     array.remove(1000);
1033     
1034     // Insert some elements
1035     foreach(i; testrange)
1036     {
1037         array[i] = datas[i];
1038     }
1039 
1040     assert(array.count == array[].count, "Array and slice count the same");
1041 
1042     j = 0;
1043     foreach(ref data; array[])
1044     {
1045         assert(data.index == testrange[j]);
1046         assert(data.value == datas[j++], "Forward range iteration");
1047     }
1048 
1049     // backwards iteration
1050     j = testrange[$-1];
1051     foreach(ref data; retro(array[]))
1052     {
1053         assert(data.index == testrange[j]);
1054         assert(data.value == datas[j--], "Retrograde range iteration");
1055     }
1056 
1057     auto slice = array[];
1058     foreach(i; testrange)
1059     {
1060         assert(slice[i] == array[i], "Slice random access");
1061     }
1062 
1063     assertThrown!RangeError(slice[200], "Out of bounds");
1064 
1065     auto data1 = new Data(-7);
1066     auto data2 = new Data(-10);
1067 
1068     array[50] = data1;
1069     array[10000] = data2;
1070 
1071     assert(slice[50] == data1, "Array mutation reflected in slice");
1072     assert(slice[10000] == data2, "Array insertion reflected in slice");
1073 }
1074 
1075 unittest
1076 {
1077     writeln("[UnitTest JudyL] - const opSlice");
1078 
1079     auto array = JudyLArray!Data();
1080 
1081     auto testrange = iota(0, 100);
1082 
1083     Data[int] datas = assocArray(
1084         zip(
1085             testrange,
1086             map!(a => new Data(a))(testrange).array
1087         )
1088     );
1089 
1090     // Insert some elements
1091     foreach(i; testrange)
1092     {
1093         array[i] = datas[i];
1094     }
1095 
1096 
1097     array.front.value.x = 7;
1098 
1099     auto testIt = delegate(const ref JudyLArray!Data constArray)
1100     {
1101         assert(array.count == constArray[].count, "Array and slice count the same");
1102 
1103         int j = 0;
1104         foreach(ref data; constArray[])
1105         {
1106             assert(data.index == testrange[j]);
1107             assert(data.value == datas[j++], "Forward range iteration");
1108         }
1109 
1110         // backwards iteration
1111         j = testrange[$-1];
1112         foreach(ref data; retro(constArray[]))
1113         {
1114             assert(data.index == testrange[j]);
1115             assert(data.value == datas[j--], "Retrograde range iteration");
1116         }
1117 
1118         auto slice = constArray[];
1119         foreach(i; testrange)
1120         {
1121             assert(slice[i] == constArray[i], "Slice random access");
1122         }
1123 
1124         assertThrown!RangeError(slice[200], "Out of bounds");
1125 
1126         // can't modify the underlying element
1127         assert(!__traits(compiles, constArray[].front.value.x = 3));
1128     };
1129 
1130     testIt(array);
1131 }
1132 
1133 unittest
1134 {
1135     writeln("[UnitTest JudyL] - opSlice[x..y]");
1136 
1137     auto array = JudyLArray!Data();
1138 
1139     auto testrange = iota(0, 100);
1140 
1141     Data[int] datas = assocArray(
1142         zip(
1143             testrange,
1144             map!(a => new Data(a))(testrange).array
1145         )
1146     );
1147 
1148     // Test empty
1149     foreach(data; array[1..2])
1150     {
1151         assert(false, "empty array");
1152     }
1153 
1154     // Test one element
1155     array[2] = datas[0];
1156     int j = 0;
1157     foreach(ref data; array[0..5])
1158     {
1159         assert(j == 0, "Called once");
1160         assert(data.index == 2);
1161         assert(data.value == datas[0]);
1162     }
1163     array.remove(2);
1164     
1165     // Insert some elements
1166     foreach(i; testrange)
1167     {
1168         array[i] = datas[i];
1169     }
1170 
1171     j = 20;
1172     foreach(ref data; array[20..30])
1173     {
1174         assert(data.index == j);
1175         assert(data.value == datas[j++], "Indexed slice");
1176     }
1177 
1178     j = 20;
1179     foreach(ref data; array[20..500])
1180     {
1181         assert(data.index == j);
1182         assert(data.value == datas[j++], "Indexed slice beyond population");
1183     }
1184 
1185     j = 90;
1186     foreach(ref data; array[90..$])
1187     {
1188         assert(data.index == j);
1189         assert(data.value == datas[j++], "OpDollar slice");
1190     }
1191 
1192     j = 20;
1193     foreach(ref data; retro(array[10..20]))
1194     {
1195         assert(data.index == j);
1196         assert(data.value == datas[j--], "Retrograde slice");
1197     }
1198 
1199     auto slice = array[50..$];
1200     foreach(i; 50..100)
1201     {
1202         assert(slice[i] == array[i], "Random access");
1203     }
1204 
1205     assertThrown!RangeError(array[10..20][9], "Out of bounds");
1206     assertThrown!RangeError(array[10..20][21], "Out of bounds");
1207 
1208     auto data1 = new Data(-3);
1209     auto data2 = new Data(-4);
1210 
1211     array[67] = data1;
1212 
1213     assert(slice[67] == data1, "Array mutation reflected in slice");
1214 }
1215 
1216 unittest
1217 {
1218     writeln("[UnitTest JudyL] - opDollar");
1219 
1220     auto array = JudyLArray!Data();
1221 
1222     auto testrange = iota(0, 100, 5);
1223 
1224     Data[int] datas = assocArray(
1225         zip(
1226             testrange,
1227             map!(a => new Data(a))(testrange).array
1228         )
1229     );
1230 
1231     // Test empty
1232     assertThrown!RangeError(array[$]);
1233 
1234     // Test one element
1235     array[0] = datas[0];
1236     array[$] = datas[5];
1237     assert(array[0] == datas[5]);
1238     array.remove(0);
1239 
1240     
1241     // Insert some elements
1242     foreach(i; testrange)
1243     {
1244         array[i] = datas[i];
1245     }
1246 
1247     array[$] = datas[0];
1248 
1249     assert(array[95] == datas[0], "opDollar is last index");
1250 
1251     auto data1 = new Data(77);
1252     array[size_t.max] = data1;
1253 
1254     auto slice = array[95..$];
1255     assert(slice.count == 2);
1256     assert(slice[95] == datas[0]);
1257     assert(slice[size_t.max] == data1);
1258 }
1259 
1260 
1261 unittest
1262 {
1263     writeln("[UnitTest JudyL] - find in empty array");
1264 
1265     auto array = JudyLArray!Data();
1266 
1267     Data found;
1268     size_t index = 0;
1269     assert(!array.first(index, found), "Empty array");
1270     assert(!array.first(index), "Empty array");
1271     assertThrown!RangeError(array.first(), "Empty array");
1272 
1273     index = 0;
1274     assert(!array.next(index, found), "Empty array");
1275     assert(!array.next(index), "Empty array");
1276 
1277     index = -1;
1278     assert(!array.prev(index, found), "Empty array");
1279     assert(!array.prev(index), "Empty array");
1280 
1281     index = -1;
1282     assert(!array.last(index, found), "Empty array");
1283     assert(!array.last(index), "Empty array");
1284     assertThrown!RangeError(array.last(), "Empty array");
1285 }
1286 
1287 unittest
1288 {
1289     writeln("[UnitTest JudyL] - find with single element at start");
1290 
1291     auto array = JudyLArray!Data();
1292 
1293     auto data = new Data(1);
1294     array[0] = data;
1295 
1296     Data found;
1297 
1298 
1299 
1300     size_t index = 0;
1301     assert(array.first(index, found));
1302     assert(index == 0);
1303     assert(found == data);
1304 
1305     index = 0;
1306     assert(array.first(index));
1307     assert(index == 0);
1308     assert(array.first() == 0);
1309 
1310     index = 0;
1311     assert(!array.next(index, found));
1312 
1313     index = 0;
1314     assert(!array.next(index));
1315 
1316     index = 0;
1317     assert(!array.prev(index, found));
1318 
1319     index = 0;
1320     assert(!array.prev(index));
1321 
1322     index = 0;
1323     assert(array.last(index, found));
1324     assert(index == 0);
1325     assert(found == data);
1326 
1327     index = 0;
1328     assert(array.last(index));
1329     assert(index == 0);
1330     assert(array.last() == 0);
1331 
1332 
1333 
1334     index = 1;
1335     assert(!array.first(index, found));
1336     assert(!array.first(index));
1337 
1338     index = 1;
1339     assert(!array.next(index, found));
1340     assert(!array.next(index));
1341 
1342     index = 1;
1343     assert(array.prev(index, found));
1344     assert(index == 0);
1345     assert(found == data);
1346 
1347     index = 1;
1348     assert(array.prev(index));
1349     assert(index == 0);
1350 
1351     index = 1;
1352     assert(array.last(index, found));
1353     assert(index == 0);
1354     assert(found == data);
1355 
1356     index = 1;
1357     assert(array.last(index));
1358     assert(index == 0);
1359 
1360 
1361 
1362     index = -1;
1363     assert(!array.first(index, found));
1364 
1365     index = -1;
1366     assert(!array.first(index));
1367 
1368     index = -1;
1369     assert(!array.next(index, found));
1370 
1371     index = -1;
1372     assert(!array.next(index));
1373 
1374     index = -1;
1375     assert(array.prev(index, found));
1376     assert(index == 0);
1377     assert(found == data);
1378 
1379     index = -1;
1380     assert(array.prev(index));
1381     assert(index == 0);
1382 
1383     index = -1;
1384     assert(array.last(index, found));
1385     assert(index == 0);
1386     assert(found == data);
1387 
1388     index = -1;
1389     assert(array.last(index));
1390     assert(index == 0);
1391 
1392 }
1393 
1394 unittest
1395 {
1396     writeln("[UnitTest JudyL] - find with single element at end");
1397 
1398     auto array = JudyLArray!Data();
1399 
1400     const auto END = size_t.max;
1401 
1402     auto data = new Data(0);
1403     array[END] = data;
1404 
1405     Data found;
1406 
1407 
1408 
1409     size_t index = 0;
1410     assert(array.first(index, found));
1411     assert(index == END);
1412     assert(found == data);
1413 
1414     index = 0;
1415     assert(array.first(index));
1416     assert(index == END);
1417     assert(array.first() == END);
1418 
1419     index = 0;
1420     assert(array.next(index, found));
1421     assert(index == END);
1422     assert(found == data);
1423 
1424     index = 0;
1425     assert(array.next(index));
1426     assert(index == END);
1427 
1428     index = 0;
1429     assert(!array.prev(index, found));
1430     assert(!array.prev(index));
1431 
1432     index = 0;
1433     assert(!array.last(index, found));
1434 
1435     index = 0;
1436     assert(!array.last(index));
1437     assert(array.last() == END);
1438 
1439 
1440 
1441     index = END - 1;
1442     assert(array.first(index, found));
1443     assert(index == END);
1444     assert(found == data);
1445 
1446     index = END - 1;
1447     assert(array.first(index));
1448     assert(index == END);
1449             
1450     index = END - 1;
1451     assert(array.next(index, found));
1452     assert(index == END);
1453     assert(found == data);
1454 
1455     index = END - 1;
1456     assert(array.next(index));
1457     assert(index == END);
1458 
1459     index = END - 1;
1460     assert(!array.prev(index, found));
1461     assert(!array.prev(index));
1462 
1463     index = END - 1;
1464     assert(!array.last(index, found));
1465     assert(!array.last(index));
1466 
1467 
1468 
1469     index = -1;
1470     assert(array.first(index, found));
1471     assert(index == END);
1472     assert(found == data);
1473 
1474     index = -1;
1475     assert(array.first(index));
1476     assert(index == END);
1477 
1478     index = -1;
1479     assert(!array.next(index, found));
1480 
1481     index = -1;
1482     assert(!array.next(index));
1483 
1484     index = -1;
1485     assert(!array.prev(index, found));
1486 
1487     index = -1;
1488     assert(!array.prev(index));
1489 
1490     index = -1;
1491     assert(array.last(index, found));
1492     assert(index == END);
1493     assert(found == data);
1494 
1495     index = -1;
1496     assert(array.last(index));
1497     assert(index == END);
1498 }
1499 
1500 unittest
1501 {
1502     writeln("[UnitTest JudyL] - find with single element in middle");
1503 
1504     auto array = JudyLArray!Data();
1505 
1506     auto data = new Data(0);
1507     array[10] = data;
1508 
1509     Data found;
1510 
1511 
1512     
1513     size_t index = 0;
1514     assert(array.first(index, found));
1515     assert(index == 10);
1516     assert(found == data);
1517 
1518     index = 0;
1519     assert(array.first(index));
1520     assert(index == 10);
1521     assert(array.first() == 10);
1522 
1523     index = 0;
1524     assert(array.next(index, found));
1525     assert(index == 10);
1526     assert(found == data);
1527 
1528     index = 0;
1529     assert(array.next(index));
1530     assert(index == 10);
1531 
1532     index = 0;
1533     assert(!array.prev(index, found));
1534 
1535     index = 0;
1536     assert(!array.prev(index));
1537 
1538     index = 0;
1539     assert(!array.last(index, found));
1540 
1541     index = 0;
1542     assert(!array.last(index));
1543     assert(array.last() == 10);
1544 
1545 
1546 
1547     index = 10;
1548     assert(array.first(index, found));
1549     assert(index == 10);
1550     assert(found == data);
1551 
1552     index = 10;
1553     assert(array.first(index));
1554     assert(index == 10);
1555 
1556     index = 10;
1557     assert(!array.next(index, found));
1558     assert(!array.next(index));
1559 
1560     index = 10;
1561     assert(!array.prev(index, found));
1562     assert(!array.prev(index));
1563 
1564     index = 10;
1565     assert(array.last(index, found));
1566     assert(index == 10);
1567     assert(found == data);
1568 
1569     index = 10;
1570     assert(array.last(index));
1571     assert(index == 10);
1572    
1573 
1574  
1575     index = 11;
1576     assert(!array.first(index, found));
1577     assert(!array.first(index));
1578 
1579     index = 11;
1580     assert(!array.next(index, found));
1581     assert(!array.next(index));
1582 
1583     index = 11;
1584     assert(array.prev(index, found));
1585     assert(index == 10);
1586     assert(found == data);
1587 
1588     index = 11;
1589     assert(array.prev(index));
1590     assert(index == 10);
1591 
1592     index = 11;
1593     assert(array.last(index, found));
1594     assert(index == 10);
1595     assert(found == data);
1596 
1597     index = 11;
1598     assert(array.last(index));
1599     assert(index == 10);
1600 
1601 
1602 
1603     index = -1;
1604     assert(array.prev(index, found));
1605     assert(index == 10);
1606     assert(found == data);
1607 
1608     index = -1;
1609     assert(array.prev(index));
1610     assert(index == 10);
1611 
1612     index = -1;
1613     assert(array.last(index, found));
1614     assert(index == 10);
1615     assert(found == data);
1616 
1617     index = -1;
1618     assert(array.last(index));
1619     assert(index == 10);
1620 }
1621 
1622 unittest
1623 {
1624     writeln("[UnitTest JudyL] - find with multiple elements");
1625 
1626     auto array = JudyLArray!Data();
1627 
1628     auto data1 = new Data(0);
1629     auto data2 = new Data(1);
1630 
1631     array[0] = data1;
1632     array[10] = data2;
1633 
1634     Data found;
1635 
1636 
1637     
1638     size_t index = 0;
1639     assert(array.first(index, found));
1640     assert(index == 0);
1641     assert(found == data1);
1642 
1643     index = 0;
1644     assert(array.first(index));
1645     assert(index == 0);
1646     assert(array.first() == 0);
1647 
1648     index = 0;
1649     assert(array.next(index, found));
1650     assert(index == 10);
1651     assert(found == data2);
1652 
1653     index = 0;
1654     assert(array.next(index));
1655     assert(index == 10);
1656 
1657     index = 0;
1658     assert(!array.prev(index, found));
1659 
1660     index = 0;
1661     assert(!array.prev(index));
1662 
1663     index = 0;
1664     assert(array.last(index, found));
1665     assert(index == 0);
1666     assert(found == data1);
1667 
1668     index = 0;
1669     assert(array.last(index));
1670     assert(index == 0);
1671     assert(array.last() == 10);
1672 
1673 
1674 
1675     index = 1;
1676     assert(array.first(index, found));
1677     assert(index == 10);
1678     assert(found == data2);
1679 
1680     index = 1;
1681     assert(array.first(index));
1682     assert(index == 10);
1683 
1684     index = 1;
1685     assert(array.next(index, found));
1686     assert(index == 10);
1687     assert(found == data2);
1688 
1689     index = 1;
1690     assert(array.next(index));
1691     assert(index == 10);
1692 
1693     index = 1;
1694     assert(array.prev(index, found));
1695     assert(index == 0);
1696     assert(found == data1);
1697 
1698     index = 1;
1699     assert(array.prev(index));
1700     assert(index == 0);
1701 
1702     index = 1;
1703     assert(array.last(index, found));
1704     assert(index == 0);
1705     assert(found == data1);
1706 
1707     index = 1;
1708     assert(array.last(index));
1709     assert(index == 0);
1710 
1711 
1712 
1713     index = 10;
1714     assert(array.first(index, found));
1715     assert(index == 10);
1716     assert(found == data2);
1717 
1718     index = 10;
1719     assert(array.first(index));
1720     assert(index == 10);
1721 
1722     index = 10;
1723     assert(!array.next(index, found));
1724     assert(!array.next(index));
1725 
1726     index = 10;
1727     assert(array.prev(index, found));
1728     assert(index == 0);
1729     assert(found == data1);
1730 
1731     index = 10;
1732     assert(array.prev(index));
1733     assert(index == 0);
1734 
1735     index = 10;
1736     assert(array.last(index, found));
1737     assert(index == 10);
1738     assert(found == data2);
1739 
1740     index = 10;
1741     assert(array.last(index));
1742     assert(index == 10);
1743 }
1744 
1745 unittest
1746 {
1747     writeln("[UnitTest JudyL] - find empty in empty array");
1748 
1749     auto array = JudyLArray!Data();
1750 
1751     const auto END = size_t.max;
1752 
1753     size_t index = 0;
1754     assert(array.firstEmpty(index), "Find first empty");
1755     assert(index == 0);
1756 
1757     index = 0;
1758     assert(array.nextEmpty(index), "Find next empty");
1759     assert(index == 1);
1760 
1761     index = -1;
1762     assert(array.prevEmpty(index), "Find prev empty");
1763     assert(index == END - 1);
1764 
1765     index = -1;
1766     assert(array.lastEmpty(index), "Find last empty");
1767     assert(index == END);
1768 }
1769 
1770 unittest
1771 {
1772     writeln("[UnitTest JudyL] - find empty with single element at start");
1773 
1774     auto array = JudyLArray!Data();
1775 
1776     const auto END = size_t.max;
1777 
1778     auto data = new Data(0);
1779     array[0] = data;
1780 
1781     size_t index = 0;
1782     assert(array.firstEmpty(index), "Find first empty");
1783     assert(index == 1);
1784 
1785     index = 0;
1786     assert(array.nextEmpty(index), "Find next empty");
1787     assert(index == 1);
1788 
1789     index = -1;
1790     assert(array.prevEmpty(index), "Find prev empty");
1791     assert(index == END - 1);
1792 
1793     index = -1;
1794     assert(array.lastEmpty(index), "Find last empty");
1795     assert(index == END);
1796 }
1797 
1798 unittest
1799 {
1800     writeln("[UnitTest JudyL] - find empty with single element at end");
1801 
1802     auto array = JudyLArray!Data();
1803 
1804     const auto END = size_t.max;
1805 
1806     auto data = new Data(0);
1807     array[END] = data;
1808 
1809     size_t index = END;
1810     assert(!array.firstEmpty(index), "Find first empty");
1811 
1812     index = END;
1813     assert(!array.nextEmpty(index), "Find next empty");
1814 
1815     index = -1;
1816     assert(array.prevEmpty(index), "Find prev empty");
1817     assert(index == END - 1);
1818 
1819     index = -1;
1820     assert(array.lastEmpty(index), "Find last empty");
1821     assert(index == END - 1);
1822 }
1823 
1824 unittest
1825 {
1826     writeln("[UnitTest JudyL] - find empty with single element in middle");
1827 
1828     auto array = JudyLArray!Data();
1829 
1830     const auto END = size_t.max;
1831 
1832     auto data = new Data(0);
1833     array[10] = data;
1834 
1835     size_t index = 0;
1836     assert(array.firstEmpty(index), "Find first empty");
1837     assert(index == 0);
1838 
1839     index = 0;
1840     assert(array.nextEmpty(index), "Find next empty");
1841     assert(index == 1);
1842 
1843     index = -1;
1844     assert(array.prevEmpty(index), "Find prev empty");
1845     assert(index == END - 1);
1846 
1847     index = -1;
1848     assert(array.lastEmpty(index), "Find last empty");
1849     assert(index == END);
1850 
1851 
1852 
1853     index = 9;
1854     assert(array.firstEmpty(index), "Find first empty");
1855     assert(index == 9);
1856 
1857     index = 9;
1858     assert(array.nextEmpty(index), "Find next empty");
1859     assert(index == 11);
1860 
1861     index = 11;
1862     assert(array.prevEmpty(index), "Find prev empty");
1863     assert(index == 9);
1864 
1865     index = 11;
1866     assert(array.lastEmpty(index), "Find last empty");
1867     assert(index == 11);
1868 
1869 
1870 
1871     index = 10;
1872     assert(array.firstEmpty(index), "Find first empty");
1873     assert(index == 11);
1874 
1875     index = 10;
1876     assert(array.nextEmpty(index), "Find next empty");
1877     assert(index == 11);
1878 
1879     index = 10;
1880     assert(array.prevEmpty(index), "Find prev empty");
1881     assert(index == 9);
1882 
1883     index = 10;
1884     assert(array.lastEmpty(index), "Find last empty");
1885     assert(index == 9);
1886 }
1887 
1888 unittest
1889 {
1890     writeln("[UnitTest JudyL] - struct pointer");
1891 
1892     auto array = JudyLArray!(Point*)();
1893 
1894     {
1895         auto point1 = new Point(1, 1);
1896         auto point2 = new Point(2, 2);
1897 
1898         array[0] = point1;
1899         array[1] = point2;
1900     }
1901 
1902     assert(array[0].x == 1);
1903     assert(array[0].y == 1);
1904 
1905     assert(array[1].x == 2);
1906     assert(array[1].y == 2);
1907 
1908     array.remove(0);
1909     array.remove(1);
1910 }
1911 
1912 unittest
1913 {
1914     writeln("[UnitTest JudyL] - primitive pointer");
1915 
1916     auto array = JudyLArray!(int*)();
1917 
1918     {
1919         auto data1 = new int(7);
1920         auto data2 = new int(10);
1921 
1922         array[0] = data1;
1923         array[1] = data2;
1924     }
1925 
1926     assert(*array[0] == 7);
1927     assert(*array[1] == 10);
1928 
1929     array.remove(0);
1930     array.remove(1);
1931 }
1932 
1933 unittest
1934 {
1935     writeln("[UnitTest JudyL] - primitive");
1936 
1937     auto array = JudyLArray!(int)();
1938 
1939     {
1940         array[0] = 7;
1941         array[1] = 10;
1942         array[0] = 3;
1943         array[2] = array[0] * array[1];
1944     }
1945 
1946     assert(array[0] == 3);
1947     assert(array[1] == 10);
1948     assert(array[2] == 30);
1949 
1950     array.remove(0);
1951     array.remove(1);
1952 }
1953 
1954 unittest
1955 {
1956     writeln("[UnitTest JudyL] - type restrictions");
1957 
1958     assert(__traits(compiles, JudyLArray!Data), "Classes are allowed");
1959     assert(__traits(compiles, JudyLArray!(Data*)), "Pointers to class are allowed");
1960     assert(!__traits(compiles, JudyLArray!Point), "Structs are not allowed");
1961     assert(__traits(compiles, JudyLArray!(Point*)), "Pointers to struct are allowed");
1962     assert(!__traits(compiles, JudyLArray!(Data[])), "Arrays are not allowed");
1963     assert(__traits(compiles, JudyLArray!(Data[]*)), "Pointers to arrays allowed");
1964 
1965     assert(__traits(compiles, JudyLArray!(long)), "long allowed");
1966     assert(__traits(compiles, JudyLArray!(ulong)), "ulong allowed");
1967     assert(__traits(compiles, JudyLArray!(int)), "int allowed");
1968     assert(__traits(compiles, JudyLArray!(uint)), "uint allowed");
1969     assert(__traits(compiles, JudyLArray!(short)), "short allowed");
1970     assert(__traits(compiles, JudyLArray!(ushort)), "ushort allowed");
1971     assert(__traits(compiles, JudyLArray!(double)), "double allowed");
1972     assert(__traits(compiles, JudyLArray!(float)), "float allowed");
1973     assert(__traits(compiles, JudyLArray!(byte)), "byte allowed");
1974     assert(__traits(compiles, JudyLArray!(ubyte)), "ubyte allowed");
1975     assert(__traits(compiles, JudyLArray!(char)), "char allowed");
1976     assert(__traits(compiles, JudyLArray!(bool)), "bool allowed");
1977 
1978     assert(__traits(compiles, JudyLArray!(long*)), "long pointer allowed");
1979     assert(__traits(compiles, JudyLArray!(ulong*)), "ulong pointer allowed");
1980     assert(__traits(compiles, JudyLArray!(int*)), "int pointer allowed");
1981     assert(__traits(compiles, JudyLArray!(uint*)), "uint pointer allowed");
1982     assert(__traits(compiles, JudyLArray!(short*)), "short pointer allowed");
1983     assert(__traits(compiles, JudyLArray!(ushort*)), "ushort pointer allowed");
1984     assert(__traits(compiles, JudyLArray!(double*)), "double pointer allowed");
1985     assert(__traits(compiles, JudyLArray!(float*)), "float pointer allowed");
1986     assert(__traits(compiles, JudyLArray!(byte*)), "byte pointer allowed");
1987     assert(__traits(compiles, JudyLArray!(ubyte*)), "ubyte pointer allowed");
1988     assert(__traits(compiles, JudyLArray!(char*)), "char pointer allowed");
1989     assert(__traits(compiles, JudyLArray!(bool*)), "bool pointer allowed");
1990 }