1 /**
2     Implementation of linked list `List` (similar to c++ `std::list` and `std::forward_list`).
3 
4     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5     Authors:   Adam Búš
6 */
7 module btl.list;
8 
9 import btl.traits.common;
10 
11 import std.traits : Unqual, Unconst, isSomeChar, isSomeString, CopyTypeQualifiers;
12 import std.meta : AliasSeq;
13 import std.traits : Select;
14 
15 import btl.traits.range;
16 import btl.lifetime;
17 
18 import btl.internal.traits;
19 import btl.internal.allocator;
20 import btl.internal.gc;
21 
22 
23 /**
24     Type used in forward constructors.
25 */
26 alias Forward = btl.traits.common.Forward;
27 
28 
29 /**
30     Default allcoator for `List`.
31 */
32 public alias DefaultAllocator = Mallocator;
33 
34 
35 /**
36     True if `T` is a `List` or implicitly converts to one, otherwise false.
37 */
38 template isList(T...)
39 if(T.length == 1){
40     enum bool isList = is(Unqual!(T[0]) == List!Args, Args...);
41 }
42 
43 private struct ListNode(Type, bool _bidirectional){
44     public alias ElementType = Type;
45     public enum bool bidirectional = _bidirectional;
46 
47     private Type element;
48     private ListNode* next;
49     static if(bidirectional)
50         private ListNode* prev;
51 
52 }
53 
54 public template ListRange(Type, bool _bidirectional, bool _reverse = false){
55     alias Node = ListNode!(Type, _bidirectional);
56 
57     struct ListRange{
58 
59         private Node* node;
60 
61         public alias Reverse = ListRange!(Type, _bidirectional, !_reverse);
62 
63         package this(N)(N* node)pure nothrow @nogc @trusted
64         if(is(immutable N : immutable ListNode!(T, bd), T : const Type, bool bd)){
65             static assert(is(CopyTypeQualifiers!(N, N.ElementType) : Type));
66             static assert(N.bidirectional >= _bidirectional);
67             this.node = cast(Node*)node;
68         }
69 
70         static if(_bidirectional)
71         public Reverse reverse()scope pure nothrow @safe @nogc{
72             return typeof(return)(node);
73 
74         }
75 
76         public bool opEquals(const typeof(null))scope const pure nothrow @safe @nogc{
77             return (this.node is null);
78         }
79 
80         public bool opEquals(N)(scope const N* node)scope const pure nothrow @safe @nogc
81         if(is(immutable N : immutable ListNode!(T, bd), T, bool bd)){
82             return (this.node is node);
83         }
84 
85         public bool opEquals(R)(scope auto ref R rhs)scope const pure nothrow @safe @nogc
86         if(is(immutable R : immutable ListRange!(T, bd, r), T, bool bd, bool r)){
87             return (this.node is rhs.node);
88         }
89 
90         public bool empty()scope const pure nothrow @nogc @safe{
91             return (node is null);
92         }
93 
94         public ref inout(Type) front()inout scope return pure nothrow @nogc @safe{
95             assert(node !is null);
96             return node.element;
97         }
98 
99         public Type moveFront()(){
100             assert(node !is null);
101             return move(node.element);
102         }
103 
104         public template opUnary(string op : "*")
105         if(op == "*"){  //doc
106             alias opUnary = front;
107         }
108 
109         public void popFront()()scope pure nothrow @nogc @safe{
110             assert(node !is null);
111             static if(_reverse){
112                 static assert(_bidirectional);
113                 node = node.prev;
114             }
115             else
116                 node = node.next;
117         }
118 
119         public template opBinary(string op : "++")
120         if(op == "++"){  //doc
121             alias opBinary = popFront;
122         }
123 
124         static if(_bidirectional){
125             public void popBack()scope pure nothrow @nogc @safe{
126                 assert(node !is null);
127                 static if(_reverse)
128                     node = node.next;
129                 else
130                     node = node.prev;
131             }
132 
133 
134             public template opBinary(string op : "--")
135             if(op == "--"){  //doc
136                 alias opBinary = popBack;
137             }
138         }
139 
140     }
141 }
142 
143 
144 
145 /**
146     `List` is a container that supports constant time insertion and removal of elements from anywhere in the container.
147 
148     Fast random access is not supported. It is usually implemented as a linked list
149 
150     Template parameters:
151 
152         `_Type` = element type.
153 
154         `_Allocator` = Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used.
155 
156         `_supportGC`
157 
158         `_bidirectional`
159 */
160 public template List(
161     _Type,
162     _Allocator = DefaultAllocator,
163     bool _supportGC = shouldAddGCRange!_Type,
164     bool _bidirectional = true,
165 ){
166 
167     import core.lifetime : emplace, forward, move;
168     import std.range : empty, front, popFront, ElementEncodingType, hasLength;
169     import std.traits : Unqual, hasElaborateDestructor, hasIndirections, isDynamicArray, isSafe;
170 
171     alias ListNode = .ListNode!(_Type, _bidirectional);
172     alias ListRange = .ListRange!(_Type, _bidirectional);
173 
174     enum bool _hasStatelessAllocator = isStatelessAllocator!_Allocator;
175 
176     struct List{
177 
178         private alias Node = ListNode;
179 
180 
181 
182         /**
183             True if allocator doesn't have state.
184         */
185         public alias hasStatelessAllocator = _hasStatelessAllocator;
186 
187 
188 
189         /**
190             Type of elements.
191         */
192         public alias ElementType = _Type;
193 
194 
195 
196         /**
197             Type of reference to elements.
198         */
199         public alias ElementReferenceType = ElementReferenceTypeImpl!_Type;
200 
201 
202 
203         /**
204             Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used.
205         */
206         public alias AllocatorType = _Allocator;
207 
208 
209 
210         /**
211         */
212         public alias supportGC = _supportGC;
213 
214 
215 
216         /**
217         */
218         public alias bidirectional = _bidirectional;
219 
220 
221 
222         /**
223             Iterator for list.
224         */
225         public alias Iterator = .ListRange!(ElementType, bidirectional);
226 
227 
228 
229         /**
230             Const iterator for list.
231         */
232         public alias ConstIterator = .ListRange!(const(ElementType), bidirectional);
233 
234 
235 
236         /**
237             Returns copy of allocator.
238         */
239         public @property CopyTypeQualifiers!(This, AllocatorType) allocator(this This)()scope{
240             return *(()@trusted => &this._allocator )();
241         }
242 
243 
244 
245         /**
246             Returns whether the list is empty (i.e. whether its length is 0).
247 
248             Examples:
249                 --------------------
250                 List!(int) list;
251                 assert(list.empty);
252 
253                 list.append(42);
254                 assert(!list.empty);
255                 --------------------
256         */
257         public @property bool empty()const scope pure nothrow @safe @nogc{
258             assert((this._first is null) == (this._last is null));
259             return (this._first is null);
260         }
261 
262 
263 
264         /**
265             Returns the length of the list, in terms of number of elements.
266 
267             Examples:
268                 --------------------
269                 List!(int) list = null;
270                 assert(list.length == 0);
271 
272                 list.append(42);
273                 assert(list.length == 1);
274 
275                 list.append(123);
276                 assert(list.length == 2);
277 
278                 list.clear();
279                 assert(list.length == 0);
280                 --------------------
281         */
282         public @property size_t length()const scope pure nothrow @safe @nogc{
283             return this._length;
284         }
285 
286 
287 
288         /**
289         */
290         public @property auto begin(this This)()scope pure nothrow @system @nogc{
291             alias Range = .ListRange!(GetElementType!This, bidirectional);
292             return Range(this._first);
293         }
294 
295 
296 
297         /**
298         */
299         public @property ConstIterator cbegin()const scope pure nothrow @system @nogc{
300             return ConstIterator(this._first);
301         }
302 
303 
304 
305         /**
306         */
307         public enum typeof(null) end = null;
308 
309 
310 
311         /**
312             Destroys the `List` object.
313 
314             This deallocates all the storage capacity allocated by the `List` using its allocator.
315         */
316         public ~this()scope{
317             debug{
318                 this.release();
319             }
320             else{
321                 this._release_impl();
322             }
323         }
324 
325 
326 
327         /**
328             Constructs a empty `List` with allocator `a`.
329 
330             Examples:
331                 --------------------
332                 {
333                     List!(int) list = DefaultAllocator.init;
334                     assert(list.empty);
335                 }
336                 --------------------
337 
338         */
339         public this(AllocatorType a)scope pure nothrow @safe @nogc{
340             static if(!hasStatelessAllocator)
341                 this._allocator = forward!a;
342         }
343 
344 
345 
346         /**
347             Constructs a empty `List`
348 
349             Examples:
350                 --------------------
351                 {
352                     List!(int) list = null;
353                     assert(list.empty);
354                 }
355                 --------------------
356 
357         */
358         public this(typeof(null) nil, Forward = Forward.init)scope pure nothrow @safe @nogc{
359         }
360 
361 
362 
363         /**
364             Constructs a `List` object from other list.
365 
366             Parameters:
367                 `rhs` other list of `List` type.
368 
369                 `allocator` optional allocator parameter.
370 
371             Examples:
372                 --------------------
373                 {
374                     List!(int) list = List!(int).build(1, 2);
375                     assert(list == [1, 2]);
376                 }
377                 {
378                     auto tmp = List!(int).build(1, 2);
379                     List!(int) list = tmp;
380                     assert(list == [1, 2]);
381                 }
382 
383 
384                 {
385                     List!(int) list = List!(int).build(1, 2);
386                     assert(list == [1, 2]);
387                 }
388                 {
389                     auto tmp = List!(int).build(1, 2);
390                     List!(int) list = tmp;
391                     assert(list == [1, 2]);
392                 }
393                 --------------------
394         */
395         public this(Rhs, this This)(scope auto ref Rhs rhs)scope
396         if(    isList!Rhs
397             && isConstructable!(Rhs, This)
398             && (isRef!Rhs || !is(immutable This == immutable Rhs))
399         ){
400             this(forward!rhs, Forward.init);
401         }
402 
403 
404 
405         /**
406             Forward constructor.
407         */
408         public this(Rhs, this This)(scope auto ref Rhs rhs, Forward)scope
409         if(isList!Rhs && isConstructable!(Rhs, This)){
410 
411             //move:
412             static if(isMoveConstructable!(rhs, This)){
413 
414                 static if(!hasStatelessAllocator)
415                     this._allocator = move(rhs._allocator);
416 
417                 this._length = rhs.length;
418                 rhs.length = 0;
419 
420                 static if(backwardList){
421                     this._last = rhs._last;
422                     rhs._last = null;
423                 }
424                 static if(forwardList){
425                     this._first = rhs._first;
426                     rhs._first = null;
427                 }
428             }
429             //move elements:
430             else static if(!isRef!rhs && isMoveConstructableElement!(GetElementType!Rhs, ElementType)){
431                 static if(!hasStatelessAllocator)
432                     this._allocator = rhs._allocator;
433 
434                 Node* node = this._first;
435                 auto range = rhs._op_slice();
436 
437                 while(node !is null && !range.empty){
438                     node.element = move(range.front);
439                     node = node.next;
440                     range.popFront;
441                 }
442 
443                 while(!range.empty){
444                     node = this._make_node(move(range.front));
445 
446                     this._push_back_node!true(node);
447 
448                     this._length += 1;
449                     range.popFront;
450                 }
451             }
452             //copy:
453             else{
454                 static if(hasStatelessAllocator || Rhs.hasStatelessAllocator)
455                     this(rhs._op_slice);
456                 else
457                     this(rhs._op_slice, rhs._allocator);
458             }
459         }
460 
461 
462 
463         /**
464             Constructs a bidirectional `List` object from range of elements.
465 
466             Parameters:
467                 `range` input reange of `ElementType` elements.
468 
469                 `allocator` optional allocator parameter.
470 
471             Examples:
472                 --------------------
473                 import std.range : iota;
474                 {
475                     List!(int) list = iota(0, 5);
476                     assert(list == [0, 1, 2, 3, 4]);
477                 }
478                 --------------------
479         */
480         public this(R, this This)(R range, Forward = Forward.init)scope
481         if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){
482             this._init_from_range(forward!range);
483         }
484 
485         /// ditto
486         public this(R, this This)(R range, AllocatorType allcoator)return
487         if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){
488             static if(!hasStatelessAllocator)
489                 this._allocator = forward!allcoator;
490 
491             this._init_from_range(forward!range);
492         }
493 
494         private void _init_from_range(R, this This)(R range)scope
495         if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){
496             auto self = (()@trusted => (cast(Unqual!This*)&this) )();
497 
498             self.pushBack(forward!range);
499         }
500 
501 
502 
503         /**
504             Copy constructors
505         */
506         static foreach(alias From; AliasSeq!(
507             typeof(this),
508             const typeof(this),
509             immutable typeof(this),
510         )){
511 
512             static if(hasCopyConstructor!(From, typeof(this)))
513                 this(scope ref return From rhs)scope{this(rhs, Forward.init);}
514             else
515                 @disable this(scope ref return From rhs)scope pure nothrow @safe;
516 
517             static if(hasCopyConstructor!(From, const typeof(this)))
518                 this(scope ref return From rhs)const scope{this(rhs, Forward.init);}
519             else
520                 @disable this(scope ref return From rhs)const scope pure nothrow @safe;
521 
522             static if(hasCopyConstructor!(From, immutable typeof(this)))
523                 this(scope ref return From rhs)immutable scope{this(rhs, Forward.init);}
524             else
525                 @disable this(scope ref return From rhs)immutable scope pure nothrow @safe;
526 
527             static if(hasCopyConstructor!(From, shared typeof(this)))
528                 this(scope ref return From rhs)shared scope{this(rhs, Forward.init);}
529             else
530                 @disable this(scope ref return From rhs)shared scope pure nothrow @safe;
531 
532             static if(hasCopyConstructor!(From, const shared typeof(this)))
533                 this(scope ref return From rhs)const shared scope{this(rhs, Forward.init);}
534             else
535                 @disable this(scope ref return From rhs)const shared scope pure nothrow @safe;
536         }
537 
538 
539 
540         /**
541             Assigns a new value `rhs` to the list, replacing its current contents.
542 
543             Parameter `rhs` can by type of `null`, `List` or input range of ElementType elements.
544 
545             Examples:
546                 --------------------
547                 List!(int) list = List!(int).build(1, 2, 3);
548                 assert(!list.empty);
549 
550                 list = null;
551                 assert(list.empty);
552 
553                 list = List!(int).build(3, 2, 1);
554                 assert(list == [3, 2, 1]);
555 
556                 list = List!(int).build(4, 2);
557                 assert(list == [4, 2]);
558                 --------------------
559         */
560         public void opAssign()(typeof(null) rhs)scope{
561             this.clear();
562         }
563 
564         /// ditto
565         public void opAssign(R)(R range)scope
566         if(!isList!R && isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){
567             Node* node = this._first;
568             while(node !is null && !range.empty){
569                 node.element = range.front;
570                 node = node.next;
571                 range.popFront;
572             }
573 
574             this.pushBack(forward!range);
575         }
576 
577         /// ditto
578         public void opAssign(Rhs)(scope auto ref Rhs rhs)scope
579         if(isList!Rhs && isAssignable!(Rhs, typeof(this)) ){
580             ///move:
581             static if(isMoveAssignable!(rhs, typeof(this))){
582                 static if(!hasStatelessAllocator)
583                     this._allocator = move(rhs._allocator);
584 
585                 this._length = rhs._length;
586                 rhs._length = 0;
587 
588                 this._last = rhs._last;
589                 rhs._last = null;
590 
591                 this._first = rhs._first;
592                 rhs._first = null;
593 
594             }
595             else static if(!isRef!rhs
596                 && isMoveAssignableElement!(GetElementType!Rhs, ElementType)
597             ){
598                 Node* node = this._first;
599                 auto range = rhs._op_slice();
600 
601                 while(node !is null && !range.empty){
602                     node.element = move(range.front);
603                     node = node.next;
604                     range.popFront;
605                 }
606 
607                 while(!range.empty){
608                     node = this._make_node(move(range.front));
609 
610                     this._push_back_node!true(node);
611 
612                     this._length += 1;
613                     range.popFront;
614                 }
615             }
616             else{
617                 this.opAssign(rhs._op_slice);
618             }
619         }
620 
621 
622 
623         /**
624             Erases and deallocate the contents of the `List`, which becomes an empty list (with a length of 0 elements).
625 
626             Same as `clear`.
627 
628             Examples:
629                 --------------------
630                 List!(int) list = List!(int).build(1, 2, 3);
631                 assert(list.length == 3);
632 
633                 list.release();
634                 assert(list.length == 0);
635                 --------------------
636         */
637         public void release()()scope nothrow{
638             this._release_impl();
639 
640             this._first = null;
641             this._last = null;
642 
643             this._length = 0;
644         }
645 
646         private void _release_impl()()scope nothrow{
647             ListNode* node = this._first;
648 
649             while(node !is null){
650                 ListNode* tmp = node;
651                 node = node.next;
652                 this._destroy_node(tmp);
653             }
654         }
655 
656 
657 
658         /**
659             Erases and deallocate the contents of the `List`, which becomes an empty list (with a length of 0 elements).
660 
661             Same as `release`.
662 
663             Examples:
664                 --------------------
665                 List!(int) list = List!(int).build(1, 2, 3);
666                 assert(list.length == 3);
667 
668                 list.clear();
669                 assert(list.length == 0);
670                 --------------------
671         */
672         public alias clear = release;
673 
674 
675 
676         /**
677             Same as operator `in`
678 
679             Examples:
680                 --------------------
681                 List!(int) list = List!(int).build(1, 2, 3);
682 
683                 assert(list.contains(1));
684                 assert(!list.contains(42L));
685                 --------------------
686         */
687         public bool contains(Elm)(scope auto ref Elm elm)scope const{
688             foreach(ref e; this._op_slice ){
689                 if(e == elm)
690                     return true;
691             }
692 
693             return false;
694         }
695 
696 
697 
698         /**
699             Operator `in`
700 
701 
702             Examples:
703                 --------------------
704                 List!(int) list = List!(int).build(1, 2, 3);
705 
706                 assert(1 in list);
707                 assert(42L !in list);
708                 --------------------
709         */
710         public bool opBinaryRight(string op, Elm)(scope auto ref Elm elm)scope const
711         if(op == "in"){
712             return this.contains(forward!elm);
713         }
714 
715 
716 
717         /**
718             Compares the contents of a list with another list, range or null.
719 
720             Returns `true` if they are equal, `false` otherwise
721 
722             Examples:
723                 --------------------
724                 List!(int) list = List!(int).build(1, 2, 3);
725 
726                 assert(list != null);
727                 assert(null != list);
728 
729                 assert(list == [1, 2, 3]);
730                 assert([1, 2, 3] == list);
731 
732                 assert(list == typeof(list).build(1, 2, 3));
733                 assert(typeof(list).build(1, 2, 3) == list);
734 
735                 import std.range : only;
736                 assert(list == only(1, 2, 3));
737                 assert(only(1, 2, 3) == list);
738                 --------------------
739         */
740         public bool opEquals(typeof(null) nil)const scope pure nothrow @safe @nogc{
741             return this.empty;
742         }
743 
744         /// ditto
745         public bool opEquals(R)(scope R rhs)const scope nothrow
746         if(isBtlInputRange!R && !isList!R){
747             import std.algorithm.comparison : equal;
748 
749             return equal(this._op_slice, forward!rhs);
750         }
751 
752         /// ditto
753         public bool opEquals(L)(scope const auto ref L rhs)const scope nothrow
754         if(isList!L){
755             import std.algorithm.comparison : equal;
756 
757             return equal(this._op_slice, rhs._op_slice);
758         }
759 
760 
761 
762 
763         /**
764             Compares the contents of a list with another list or range.
765 
766             Examples:
767                 --------------------
768                 auto a1 = List!(int).build(1, 2, 3);
769                 auto a2 = List!(int).build(1, 2, 3, 4);
770                 auto b = List!(int).build(3, 2, 1);
771 
772                 assert(a1 < b);
773                 assert(a1 < a2);
774                 assert(a2 < b);
775                 assert(a1 <= a1);
776                 --------------------
777         */
778         public int opCmp(R)(scope R rhs)const scope nothrow
779         if(isBtlInputRange!R && !isList!R){
780             import std.algorithm.comparison : cmp;
781 
782             return cmp(this._op_slice, forward!rhs);
783         }
784 
785         /// ditto
786         public int opCmp(L)(scope const auto ref L rhs)const scope nothrow
787         if(isList!L){
788             import std.algorithm.comparison : cmp;
789 
790             return cmp(this._op_slice, rhs._op_slice);
791         }
792 
793 
794 
795         /**
796             Return slice of all elements.
797 
798             The slice returned may be invalidated by further calls to other member functions that modify the object.
799 
800             Examples:
801                 --------------------
802                 List!(int) list = List!(int).build(1, 2, 3);
803                 --------------------
804         */
805         public auto opIndex(this This)()return pure nothrow @system @nogc{
806             return this._op_slice();
807         }
808 
809         private @property _op_slice(this This)()return pure nothrow @trusted @nogc{
810             alias Range = .ListRange!(GetElementType!This, bidirectional);
811             return Range(this._first);
812         }
813 
814 
815 
816         /**
817             Returns the length of the list, in terms of number of elements.
818 
819             Same as `length()`.
820         */
821         public size_t opDollar()const scope pure nothrow @safe @nogc{
822             return this.length;
823         }
824 
825 
826 
827         /**
828             Swaps the contents of `this` and `rhs`.
829 
830             Examples:
831                 --------------------
832                 auto a = List!(int).build(1, 2, 3);
833                 auto b = List!(int).build(4, 5, 6);
834 
835                 a.proxySwap(b);
836                 assert(a == [4, 5, 6]);
837                 assert(b == [1, 2, 3]);
838 
839                 import std.algorithm.mutation : swap;
840 
841                 swap(a, b);
842                 assert(a == [1, 2, 3]);
843                 assert(b == [4, 5, 6]);
844                 --------------------
845         */
846         public void proxySwap()(ref scope typeof(this) rhs)scope{
847             import std.algorithm.mutation : swap;
848 
849             (ref typeof(this) a, ref typeof(this) b){
850                 static if(!hasStatelessAllocator)
851                     swap(a._allocator, b._allocator);
852 
853                 swap(a._length, b._length);
854                 swap(a._first, b._first);
855                 swap(a._last, b._last);
856             }(
857                 *(()@trusted => &this )(),
858                 *(()@trusted => &rhs )()
859             );
860 
861             /*static if(!hasStatelessAllocator)
862                 swap(this._allocator, rhs._allocator);
863 
864             swap(this._length, rhs._length);
865             swap(this._first, rhs._first);
866             swap(this._last, rhs._last);*/
867         }
868 
869 
870 
871         /**
872             Returns a reference to the first element in the list.
873 
874             Calling this function on an empty container causes null dereference.
875         */
876         public ref inout(ElementType) front()inout return pure nothrow @system @nogc{
877             assert(this._first !is null);
878             return this._first.element;
879         }
880 
881 
882 
883         /**
884             Returns a copy of the first element in the list.
885 
886             Calling this function on an empty container causes null dereference.
887 
888             Examples:
889                 --------------------
890                 auto list = List!(int).build(1, 2, 3);
891 
892                 assert(list.frontCopy == 1);
893                 assert(list == [1, 2, 3]);
894                 --------------------
895         */
896         public auto frontCopy(this This)()scope{
897             assert(this._first !is null);
898 
899             return this._first.element;
900         }
901 
902 
903 
904         /**
905             Move of the first element in the list and return it.
906 
907             Calling this function on an empty container causes null dereference.
908 
909             Examples:
910                 --------------------
911                 auto list = List!(int).build(1, 2, 3);
912 
913                 assert(list.moveFront == 1);
914                 list.popFront;
915                 assert(list == [2, 3]);
916                 --------------------
917         */
918         public ElementType moveFront()scope pure nothrow @safe @nogc{
919             assert(this._first !is null);
920 
921             return move(this._first.element);
922         }
923 
924 
925 
926         /**
927             Pop the last element of the bidirectional list, effectively reducing its length by 1.
928 
929             Return erased element.
930 
931             Examples:
932                 --------------------
933                 List!(int) list = List!(int).build(30, 20, 10);
934                 assert(list.length == 3);
935 
936                 assert(list.popFront == 30);
937                 assert(list.length == 2);
938 
939                 assert(list.popFront == 20);
940                 assert(list.length == 1);
941 
942                 assert(list.popFront == 10);
943                 assert(list.empty);
944 
945                 assert(list.popFront(int.init) == int.init);
946                 assert(list.empty);
947 
948                 assert(list.popFront(42) == 42);
949                 assert(list.empty);
950                 --------------------
951         */
952         public auto popFront(T = Unqual!ElementType)()scope nothrow
953         if(is(T == Unqual!ElementType) || is(T == void)){
954             assert(!this.empty);
955             return _pop_front_impl!T();
956         }
957 
958         ///ditto
959         public ElementType popFront(T : Unqual!ElementType = Unqual!ElementType)(ElementType def)scope nothrow{
960             return (this.empty)
961                 ? forward!def
962                 : _pop_front_impl!T();
963         }
964 
965         private auto _pop_front_impl(T)()scope nothrow
966         if(is(T == Unqual!ElementType) || is(T == void)){
967             ListNode* node = this._first;
968             this._first = this._first.next;
969 
970             if(this._first is null){
971                 this._last = null;
972             }
973             else{
974                 static if(bidirectional)
975                     this._first.prev = null;
976             }
977 
978 
979             static if(is(T == void)){
980                 destructImpl(*node);
981                 this._length -= 1;
982             }
983             else{
984                 ElementType result = move(node.element);
985                 destructImpl(*node);
986 
987                 this._length -= 1;
988                 return move(result);
989             }
990         }
991 
992 
993 
994         /**
995             Appends a new element to the begin of the list. The element is constructed through `emplace`.
996 
997             Parameters:
998                 `args`  arguments to forward to the constructor of the element.
999 
1000             Examples:
1001                 --------------------
1002                 {
1003                     auto list = List!(int).build(1, 2, 3);
1004 
1005                     list.emplaceFront(42);
1006                     assert(list == [42, 1, 2, 3]);
1007 
1008                     list.emplaceFront();
1009                     assert(list == [0, 42, 1, 2, 3]);
1010                 }
1011 
1012                 {
1013                     static struct Foo{
1014                         int i;
1015                         string str;
1016                     }
1017 
1018                     auto list = List!(Foo).build(Foo(1, "A"));
1019 
1020                     list.emplaceFront(2, "B");
1021                     assert(list == only(Foo(2, "B"), Foo(1, "A")));
1022                 }
1023                 --------------------
1024         */
1025         public void emplaceFront(Args...)(auto ref Args args)scope{
1026             ListNode* node = this._make_node(forward!args);
1027 
1028             this._push_front_node(node);
1029             this._length += 1;
1030         }
1031 
1032 
1033 
1034         /**
1035             Extends the `List` by appending additional elements at the end of list.
1036 
1037             Parameters:
1038                 `val` appended value.
1039 
1040                 `list` appended list.
1041 
1042                 `range` appended input renge.
1043 
1044                 `count` Number of times `val` is appended.
1045 
1046             Examples:
1047                 --------------------
1048                 {
1049                     auto list = List!(int).build(1, 2, 3);
1050 
1051                     list.pushFront(42);
1052                     assert(list == [42, 1, 2, 3]);
1053                 }
1054 
1055                 {
1056                     auto list = List!(int).build(1, 2, 3);
1057 
1058                     list.pushFront(only(4, 5, 6));
1059                     assert(list == [6, 5, 4, 1, 2, 3]);
1060                 }
1061 
1062                 {
1063                     auto a = List!(int).build(1, 2, 3);
1064                     auto b = List!(int).build(4, 5, 6);
1065 
1066                     a.pushFront(b);
1067                     assert(a == [6, 5, 4, 1, 2, 3]);
1068                 }
1069 
1070                 {
1071                     List!(int) list = List!(int).build(1, 2, 3);
1072                     int[3] tmp = [4, 5, 6];
1073                     list.pushFront(tmp[]);
1074                     assert(list == [6, 5, 4, 1, 2, 3]);
1075                 }
1076 
1077                 {
1078                     struct Range{
1079                         int i;
1080 
1081                         bool empty()(){return i == 0;}
1082                         int front()(){return i;}
1083                         void popFront()(){i -= 1;}
1084                         //size_t length(); //no length
1085                     }
1086 
1087                     List!(int) list = List!(int).build(6, 5, 4);
1088                     list.pushFront(Range(3));
1089                     assert(list == [1, 2, 3, 6, 5, 4]);
1090                 }
1091                 --------------------
1092         */
1093         public size_t pushFront(R)(R range)scope
1094         if(isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){
1095             size_t len = 0;
1096 
1097             if(!range.empty){
1098                 scope(exit){
1099                     this._length += len;
1100                 }
1101 
1102                 {
1103                     auto node = this._make_node(range.front);
1104 
1105                     this._push_front_node(node);
1106 
1107                     len += 1;
1108                     range.popFront;
1109                 }
1110 
1111 
1112                 while(!range.empty){
1113                     auto node = this._make_node(range.front);
1114 
1115                     this._push_front_node!true(node);
1116 
1117                     len += 1;
1118                     range.popFront;
1119                 }
1120             }
1121 
1122             return len;
1123         }
1124 
1125         /// ditto
1126         public size_t pushFront(L)(scope auto ref L list)scope
1127         if(isList!L && is(GetElementType!L : ElementType)){
1128             return this.pushFront(list._op_slice);
1129         }
1130 
1131         /// ditto
1132         public size_t pushFront(Val)(auto ref Val val)scope
1133         if(is(Val : ElementType)){
1134             auto node = this._make_node(forward!val);
1135 
1136             this._push_front_node(node);
1137 
1138             this._length += 1;
1139             return 1;
1140 
1141         }
1142 
1143         /// ditto
1144         public size_t pushFront(Val)(auto ref Val val, const size_t count)scope
1145         if(is(Val : ElementType)){
1146             size_t len = 0;
1147 
1148             scope(exit){
1149                 this._length += len;
1150             }
1151 
1152             if(count != 0){
1153                 auto node = this._make_node(val);
1154 
1155                 this._push_front_node(node);
1156                 len += 1;
1157             }
1158 
1159             if(count != len){
1160                 for(; len < count; ++len){
1161                     auto node = this._make_node(val);
1162 
1163                     this._push_front_node!true(node);
1164                 }
1165             }
1166 
1167             return len;
1168         }
1169 
1170 
1171 
1172         /**
1173             Alias to pushFront
1174         */
1175         public alias prepend = pushFront;
1176 
1177 
1178 
1179 
1180         /**
1181             Returns a reference to the last element in the list.
1182 
1183             Calling this function on an empty container causes null dereference.
1184         */
1185         public ref inout(ElementType) back()inout return pure nothrow @system @nogc{
1186             assert(this._last !is null);
1187             return this._last.element;
1188         }
1189 
1190 
1191 
1192         /**
1193             Returns a copy of the first element in the list.
1194 
1195             Calling this function on an empty container causes null dereference.
1196 
1197             Examples:
1198                 --------------------
1199                 auto list = List!(int).build(1, 2, 3);
1200 
1201                 assert(list.backCopy == 3);
1202                 assert(list == [1, 2, 3]);
1203                 --------------------
1204         */
1205         public auto backCopy(this This)()scope {
1206             assert(this._last !is null);
1207 
1208             return this._last.element;
1209         }
1210 
1211 
1212 
1213         /**
1214             Move of the first element in the list and return it.
1215 
1216             Calling this function on an empty container causes null dereference.
1217 
1218             Examples:
1219                 --------------------
1220                 auto list = List!(int).build(1, 2, 3);
1221 
1222                 assert(list.moveBack == 3);
1223                 list.popBack;
1224                 assert(list == [1, 2]);
1225                 --------------------
1226         */
1227         public ElementType moveBack()scope pure nothrow @safe @nogc{
1228             assert(this._last !is null);
1229 
1230             return move(this._last.element);
1231         }
1232 
1233 
1234 
1235         /**
1236             Pop the last element of the bidirectional list, effectively reducing its length by 1.
1237 
1238             Return erased element.
1239 
1240             Examples:
1241                 --------------------
1242                 List!(int) list = List!(int).build(10, 20, 30);
1243                 assert(list.length == 3);
1244 
1245                 assert(list.popBack == 30);
1246                 assert(list.length == 2);
1247 
1248                 assert(list.popBack == 20);
1249                 assert(list.length == 1);
1250 
1251                 assert(list.popBack == 10);
1252                 assert(list.empty);
1253 
1254                 assert(list.popBack(int.init) == int.init);
1255                 assert(list.empty);
1256 
1257                 assert(list.popBack(42) == 42);
1258                 assert(list.empty);
1259                 --------------------
1260         */
1261         public auto popBack(T = Unqual!ElementType)()scope nothrow
1262         if(is(T == Unqual!ElementType) || is(T == void)){
1263             assert(!this.empty);
1264             return _pop_back_impl!T();
1265         }
1266 
1267         ///ditto
1268         public auto popBack(T : Unqual!ElementType = Unqual!ElementType)(ElementType def)scope nothrow{
1269             return this.empty
1270                 ? move(def)
1271                 : _pop_back_impl!T();
1272         }
1273 
1274         private auto _pop_back_impl(T)()scope nothrow
1275         if(is(T == Unqual!ElementType) || is(T == void)){
1276             assert(!this.empty);
1277 
1278             ListNode* node = this._last;
1279             this._last = this._last.prev;
1280 
1281             if(this._last is null)
1282                 this._first = null;
1283             else
1284                 this._last.next = null;
1285 
1286             static if(is(T == void)){
1287                 destructImpl(*node);
1288                 this._length -= 1;
1289             }
1290             else{
1291                 ElementType result = move(node.element);
1292                 destructImpl(*node);
1293 
1294                 this._length -= 1;
1295                 return move(result);
1296             }
1297         }
1298 
1299 
1300 
1301         /**
1302             Appends a new element to the end of the bidirectional list. The element is constructed through `emplace`.
1303 
1304             Parameters:
1305                 `args`  arguments to forward to the constructor of the element.
1306 
1307             Examples:
1308                 --------------------
1309                 {
1310                     auto list = List!(int).build(1, 2, 3);
1311 
1312                     list.emplaceBack(42);
1313                     assert(list == [1, 2, 3, 42]);
1314 
1315                     list.emplaceBack();
1316                     assert(list == [1, 2, 3, 42, 0]);
1317                 }
1318 
1319                 {
1320                     static struct Foo{
1321                         int i;
1322                         string str;
1323                     }
1324 
1325                     auto list = List!(Foo).build(Foo(1, "A"));
1326 
1327                     list.emplaceBack(2, "B");
1328                     assert(list == only(Foo(1, "A"), Foo(2, "B")));
1329                 }
1330                 --------------------
1331         */
1332         public void emplaceBack(Args...)(auto ref Args args)scope return{
1333             ListNode* node = this._make_node(forward!args);
1334 
1335             this._push_back_node(node);
1336             this._length += 1;
1337         }
1338 
1339 
1340 
1341         /**
1342             Extends the `List` by appending additional elements at the end of list.
1343 
1344             Parameters:
1345                 `val` appended value.
1346 
1347                 `list` appended list.
1348 
1349                 `range` appended input renge.
1350 
1351                 `count` Number of times `val` is appended.
1352 
1353             Examples:
1354                 --------------------
1355                 {
1356                     auto list = List!(int).build(1, 2, 3);
1357 
1358                     list.pushBack(42);
1359                     assert(list == [1, 2, 3, 42]);
1360                 }
1361 
1362                 {
1363                     auto list = List!(int).build(1, 2, 3);
1364 
1365                     list.pushBack(only(4, 5, 6));
1366                     assert(list == [1, 2, 3, 4, 5, 6]);
1367                 }
1368 
1369                 {
1370                     auto a = List!(int).build(1, 2, 3);
1371                     auto b = List!(int).build(4, 5, 6);
1372 
1373                     a.pushBack(b);
1374                     assert(a == [1, 2, 3, 4, 5, 6]);
1375                 }
1376 
1377                 {
1378                     List!(int) list = List!(int).build(1, 2, 3);
1379                     int[3] tmp = [4, 5, 6];
1380                     list.pushBack(tmp[]);
1381                     assert(list == [1, 2, 3, 4, 5, 6]);
1382                 }
1383 
1384                 {
1385                     struct Range{
1386                         int i;
1387 
1388                         bool empty()(){return i == 0;}
1389                         int front()(){return i;}
1390                         void popFront()(){i -= 1;}
1391                         //size_t length(); //no length
1392                     }
1393 
1394                     List!(int) list = List!(int).build(6, 5, 4);
1395                     list.pushBack(Range(3));
1396                     assert(list == [6, 5, 4, 3, 2, 1]);
1397                 }
1398                 --------------------
1399         */
1400         public size_t pushBack(R)(R range)scope
1401         if(!isList!R && isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){
1402             size_t len = 0;
1403 
1404             if(!range.empty){
1405                 scope(exit){
1406                     this._length += len;
1407                 }
1408 
1409                 {
1410                     auto node = this._make_node(range.front);
1411 
1412                     this._push_back_node(node);
1413 
1414                     len += 1;
1415                     range.popFront;
1416                 }
1417 
1418 
1419                 while(!range.empty){
1420                     auto node = this._make_node(range.front);
1421 
1422                     this._push_back_node!true(node);
1423 
1424                     len += 1;
1425                     range.popFront;
1426                 }
1427             }
1428 
1429             return len;
1430         }
1431 
1432         /// ditto
1433         public size_t pushBack(L)(scope auto ref L list)scope
1434         if(isList!L && is(GetElementType!L : ElementType)){
1435             return this.pushBack(list._op_slice);
1436         }
1437 
1438         /// ditto
1439         public size_t pushBack(Val)(auto ref Val val)scope
1440         if(is(Val : ElementType)){
1441             auto node = this._make_node(forward!val);
1442 
1443             this._push_back_node(node);
1444 
1445             this._length += 1;
1446             return 1;
1447 
1448         }
1449 
1450         /// ditto
1451         public size_t pushBack(Val)(auto ref Val val, const size_t count)scope
1452         if(is(Val : ElementType)){
1453             size_t len = 0;
1454             scope(exit){
1455                 this._length += len;
1456             }
1457 
1458             if(count != 0){
1459                 auto node = this._make_node(val);
1460 
1461                 this._push_back_node(node);
1462                 len += 1;
1463             }
1464 
1465             if(count != len){
1466                 for(; len < count; ++len){
1467                     auto node = this._make_node(val);
1468 
1469                     this._push_back_node!true(node);
1470                 }
1471             }
1472 
1473             return len;
1474         }
1475 
1476 
1477 
1478         /**
1479             Alias to pushBack
1480         */
1481         public alias append = pushBack;
1482 
1483 
1484 
1485         /**
1486             Operator `~=` is same as append/pushBack
1487         */
1488         public template opOpAssign(string op)
1489         if(op == "~"){
1490             alias opOpAssign = pushBack;
1491         }
1492 
1493 
1494 
1495         /**
1496             Alias to pushBack
1497         */
1498         public alias put = pushBack;
1499 
1500 
1501 
1502         /**
1503             Static function which return `List` construct from arguments `args`.
1504 
1505             Parameters:
1506                 `allocator` exists only if template parameter `_Allocator` has state.
1507 
1508                 `args` values of type `ElementType`, input range or `List`.
1509 
1510             Examples:
1511                 --------------------
1512                 import std.range : only;
1513 
1514                 int[2] tmp = [3, 4];
1515                 auto list = List!(int).build(1, 2, tmp[], only(5, 6), List!(int).build(7, 8));
1516                 assert(list == [1, 2, 3, 4, 5, 6, 7, 8]);
1517                 --------------------
1518         */
1519         public static typeof(this) build(Args...)(auto ref Args args){
1520             import core.lifetime : forward;
1521 
1522             auto result = List.init;
1523 
1524             result._build_impl(forward!args);
1525 
1526             return ()@trusted{
1527                 return *&result;
1528             }();
1529         }
1530 
1531         /// ditto
1532         public static typeof(this) build(Args...)(AllocatorType allocator, auto ref Args args){
1533             import core.lifetime : forward;
1534 
1535             auto result = (()@trusted => List(forward!allocator))();
1536 
1537             result._build_impl(forward!args);
1538 
1539             return ()@trusted{
1540                 return *&result;
1541             }();
1542         }
1543 
1544         private void _build_impl(Args...)(auto ref Args args)scope{
1545             import std.traits : isArray;
1546 
1547             static foreach(alias arg; args)
1548                 this.pushBack(forward!arg);
1549         }
1550 
1551 
1552 
1553 
1554 
1555         //internals:
1556         static if(hasStatelessAllocator){
1557             public alias _allocator = statelessAllcoator!AllocatorType;
1558 
1559             private enum safeAllocate = isSafe!((){
1560                 size_t capacity = size_t.max;
1561 
1562                 cast(void)_allocator.allocate(capacity);
1563             });
1564         }
1565         else{
1566             public AllocatorType _allocator;
1567 
1568             private enum safeAllocate = isSafe!((ref AllocatorType a){
1569                 size_t capacity = size_t.max;
1570 
1571                 cast(void)a.allocate(capacity);
1572             });
1573         }
1574 
1575         private size_t _length;
1576         private ListNode* _first;
1577         private ListNode* _last;
1578 
1579         private ListNode* _make_node(Args...)(auto ref Args args)scope{
1580 
1581             ListNode* node = ()@trusted{
1582                 return cast(ListNode*)_allocator.allocate(ListNode.sizeof).ptr;
1583             }();
1584 
1585             _enforce(node !is null, "allocation fail");
1586 
1587             static if(supportGC)
1588                 gcAddRange(node, ListNode.sizeof);
1589 
1590             emplaceImpl(node.element, forward!args);
1591             node.next = null;
1592             static if(bidirectional)
1593                 node.prev = null;
1594 
1595             return node;
1596         }
1597 
1598         private void _destroy_node()(ListNode* node)scope nothrow{
1599             assert(node !is null);
1600 
1601             destructImpl(node.element);
1602 
1603             void[] data = ()@trusted{
1604                 return (cast(void*)node)[0 .. ListNode.sizeof];
1605             }();
1606 
1607             static if(supportGC)
1608                 gcRemoveRange(data);
1609 
1610             static if(safeAllcoate!(typeof(_allocator)))
1611                 const d = ()@trusted{
1612                     return _allocator.deallocate(data);
1613                 }();
1614 
1615             else
1616                 const d = _allocator.deallocate(data);
1617 
1618             _enforce(d, "deallocation fail");
1619         }
1620 
1621 
1622         //enforce:
1623         private void _enforce(bool con, string msg)const pure nothrow @safe @nogc{
1624             if(!con)assert(0, msg);
1625         }
1626 
1627         private void _push_front_node(bool not_empty = false)(scope ListNode* node)scope pure nothrow @trusted @nogc{
1628             assert(node !is null);
1629             static if(not_empty)
1630                 assert(!this.empty);
1631 
1632             const bool is_empty = not_empty
1633                 ? false
1634                 : (this._first is null);
1635 
1636             if(is_empty){
1637                 this._last = node;
1638             }
1639             else{
1640                 node.next = this._first;
1641                 static if(bidirectional)
1642                     this._first.prev = node;
1643             }
1644 
1645             this._first = node;
1646         }
1647 
1648         private void _push_back_node(bool not_empty = false)(scope ListNode* node)scope pure nothrow @trusted @nogc{
1649             assert(node !is null);
1650             static if(not_empty)
1651                 assert(!this.empty);
1652 
1653             const bool is_empty = not_empty
1654                 ? false
1655                 : (this._first is null);
1656 
1657             if(is_empty){
1658                 this._first = node;
1659             }
1660             else{
1661                 static if(bidirectional)
1662                     node.prev = this._last;
1663 
1664                 this._last.next = node;
1665             }
1666 
1667             this._last = node;
1668         }
1669 
1670     }
1671 }
1672 
1673 
1674 ///
1675 unittest{
1676     import std.range : only;
1677     import std.algorithm : map, equal;
1678 
1679     static struct Foo{
1680         int i;
1681         string str;
1682     }
1683 
1684     List!(Foo) list;
1685 
1686     assert(list.empty);
1687 
1688     list.append(Foo(1, "A"));
1689     assert(list.length == 1);
1690 
1691     list.append(only(Foo(2, "B"), Foo(3, "C")));
1692     assert(list.length == 3);
1693 
1694     list.emplaceBack(4, "D");
1695     assert(list.length == 4);
1696 
1697 
1698     list = List!(Foo).build(Foo(-1, "X"), Foo(-2, "Y"));
1699     assert(equal(list[].map!(e => e.str), only("X", "Y")));
1700 
1701     list.release();
1702     assert(list.length == 0);
1703 
1704 }
1705 
1706 
1707 /// Alias to `List` with parameter `_bidirectional = true` (single linked list)
1708 public template ForwardList(
1709     _Type,
1710     _Allocator = DefaultAllocator,
1711     bool _supportGC = shouldAddGCRange!_Type
1712 ){
1713     alias ForwardList = .List!(_Type, _Allocator, _supportGC, false);
1714 }
1715 
1716 //local traits:
1717 private{
1718 
1719     enum bool safeAllcoate(A) = __traits(compiles, (ref A allcoator)@safe{
1720         const size_t size;
1721         allcoator.allocate(size);
1722     }(*cast(A*)null));
1723 
1724 
1725     //copy ctor:
1726     template hasCopyConstructor(From, To)
1727     if(is(immutable From == immutable To)){
1728 
1729         enum bool hasCopyConstructor = true
1730             && !is(From == shared)
1731             && isConstructable!(From, To)
1732             && isCopyConstructableElement!(
1733                 GetElementType!From,
1734                 GetElementType!To
1735             )
1736             && (From.hasStatelessAllocator
1737                 || isCopyConstructableElement!(
1738                     GetAllocatorType!From,
1739                     GetAllocatorType!To
1740                 )
1741             )
1742             && (From.hasStatelessAllocator
1743                 || isCopyConstructableElement!(
1744                     GetAllocatorType!From,
1745                     To.AllocatorType
1746                 )
1747             );
1748     }
1749 
1750     //Move Constructable:
1751     template isMoveConstructable(alias from, To){
1752         alias From = typeof(from);
1753 
1754         enum isMoveConstructable = true
1755             && !isRef!from
1756             && isConstructable!(From, To)
1757             && (From.bidirectional == To.bidirectional)
1758             && is(GetElementReferenceType!From : GetElementReferenceType!To)
1759             && is(immutable From.AllocatorType == immutable To.AllocatorType)
1760             && (From.hasStatelessAllocator
1761                 || isMoveConstructableElement!(
1762                         GetAllocatorType!From,
1763                         GetAllocatorType!To
1764                 )
1765             );
1766     }
1767 
1768     //Move Assignable:
1769     template isMoveAssignable(alias from, To){
1770         alias From = typeof(from);
1771 
1772         enum isMoveAssignable = true
1773             && !isRef!from
1774             && isAssignable!(From, To)
1775             && (From.bidirectional == To.bidirectional)
1776             && is(GetElementReferenceType!From : GetElementReferenceType!To)
1777             && is(immutable From.AllocatorType == immutable To.AllocatorType)
1778             && (From.hasStatelessAllocator
1779                 || isMoveAssignableElement!(
1780                         GetAllocatorType!From,
1781                         GetAllocatorType!To
1782                 )
1783             );
1784     }
1785 
1786     //Constructable:
1787     template isConstructable(From, To){
1788 
1789         enum isConstructable = true
1790             && !is(From == shared)
1791             && (From.supportGC == To.supportGC)
1792             && is(GetElementType!From : GetElementType!To)
1793             && (From.hasStatelessAllocator
1794                 ? is(immutable From.AllocatorType == immutable To.AllocatorType)
1795                 : is(immutable From.AllocatorType : immutable To.AllocatorType)
1796             );
1797     }
1798 
1799     //Assignable:
1800     template isAssignable(From, To){
1801         import std.traits : isMutable;
1802 
1803         enum isAssignable = true
1804             && isMutable!To
1805             && !is(From == shared) && !is(To == shared)
1806             && (From.supportGC == To.supportGC)
1807             && is(GetElementType!From : GetElementType!To);
1808     }
1809 
1810 
1811 
1812     template GetElementType(Container){
1813         alias GetElementType = CopyTypeQualifiers!(Container, Container.ElementType);
1814     }
1815 
1816     template GetAllocatorType(Container){
1817         alias GetAllocatorType = CopyTypeQualifiers!(Container, Container.AllocatorType);
1818     }
1819 
1820     template GetElementReferenceType(Container){
1821         alias GetElementReferenceType = ElementReferenceTypeImpl!(GetElementType!Container);
1822     }
1823 
1824     template ElementReferenceTypeImpl(T){
1825         import std.traits : Select, isDynamicArray;
1826         import std.range : ElementEncodingType;
1827 
1828         static if(false
1829             || is(T == class) || is(T == interface)
1830             || is(T == function) || is(T == delegate)
1831             || is(T : U*, U)
1832         ){
1833             alias ElementReferenceTypeImpl = T;
1834         }
1835         else static if(isDynamicArray!T){
1836             alias ElementReferenceTypeImpl = ElementEncodingType!T[];
1837         }
1838         else{
1839             alias ElementReferenceTypeImpl = T*;
1840         }
1841     }
1842 
1843 
1844 }
1845 
1846 //List examples:
1847 version(unittest){
1848 
1849     import std.range : only;
1850     static foreach(alias List; AliasSeq!(.List)){
1851 
1852         //List.empty
1853         pure nothrow @safe @nogc unittest{
1854             List!(int) list;
1855             assert(list.empty);
1856 
1857             list.append(42);
1858             assert(!list.empty);
1859         }
1860 
1861         //List.length
1862         pure nothrow @safe @nogc unittest{
1863             List!(int) list = null;
1864             assert(list.length == 0);
1865 
1866             list.append(42);
1867             assert(list.length == 1);
1868 
1869             list.append(123);
1870             assert(list.length == 2);
1871 
1872             list.clear();
1873             assert(list.length == 0);
1874         }
1875 
1876         //List.ctor(allocator)
1877         pure nothrow @safe @nogc unittest{
1878             {
1879                 List!(int) list = DefaultAllocator.init;
1880                 assert(list.empty);
1881             }
1882         }
1883 
1884         //List.ctor(null)
1885         pure nothrow @safe @nogc unittest{
1886             {
1887                 List!(int) list = null;
1888                 assert(list.empty);
1889             }
1890         }
1891 
1892         //List.ctor(list)
1893         pure nothrow @safe @nogc unittest{
1894             {
1895                 List!(int) list = List!(int).build(1, 2);
1896                 assert(list == [1, 2]);
1897             }
1898             {
1899                 auto tmp = List!(int).build(1, 2);
1900                 List!(int) list = tmp;
1901                 assert(list == [1, 2]);
1902             }
1903 
1904 
1905             {
1906                 List!(int) list = List!(int).build(1, 2);
1907                 assert(list == [1, 2]);
1908             }
1909             {
1910                 auto tmp = List!(int).build(1, 2);
1911                 List!(int) list = tmp;
1912                 assert(list == [1, 2]);
1913             }
1914         }
1915 
1916         //List.ctor(range)
1917         pure nothrow @safe @nogc unittest{
1918             import std.range : iota;
1919             {
1920                 List!(int) list = iota(0, 5);
1921                 assert(list == [0, 1, 2, 3, 4]);
1922             }
1923         }
1924 
1925         //List.opAssign
1926         pure nothrow @safe @nogc unittest{
1927             List!(int) list = List!(int).build(1, 2, 3);
1928             assert(!list.empty);
1929 
1930             list = null;
1931             assert(list.empty);
1932 
1933             list = List!(int).build(3, 2, 1);
1934             assert(list == [3, 2, 1]);
1935 
1936             list = List!(int).build(4, 2);
1937             assert(list == [4, 2]);
1938         }
1939 
1940         //List.release
1941         pure nothrow @safe @nogc unittest{
1942             List!(int) list = List!(int).build(1, 2, 3);
1943             assert(list.length == 3);
1944 
1945             list.release();
1946             assert(list.length == 0);
1947         }
1948 
1949         //List.clear
1950         pure nothrow @safe @nogc unittest{
1951             List!(int) list = List!(int).build(1, 2, 3);
1952             assert(list.length == 3);
1953 
1954             list.clear();
1955             assert(list.length == 0);
1956         }
1957 
1958         //List.contains
1959         pure nothrow @safe @nogc unittest{
1960             List!(int) list = List!(int).build(1, 2, 3);
1961 
1962             assert(list.contains(1));
1963             assert(!list.contains(42L));
1964         }
1965 
1966         //List.opBinaryRight!"in"
1967         pure nothrow @safe @nogc unittest{
1968             List!(int) list = List!(int).build(1, 2, 3);
1969 
1970             assert(1 in list);
1971             assert(42L !in list);
1972         }
1973 
1974         //List.opEquals
1975         pure nothrow @safe @nogc unittest{
1976             List!(int) list = List!(int).build(1, 2, 3);
1977 
1978             assert(list != null);
1979             assert(null != list);
1980 
1981             assert(list == [1, 2, 3]);
1982             assert([1, 2, 3] == list);
1983 
1984             assert(list == typeof(list).build(1, 2, 3));
1985             assert(typeof(list).build(1, 2, 3) == list);
1986 
1987             import std.range : only;
1988             assert(list == only(1, 2, 3));
1989             assert(only(1, 2, 3) == list);
1990         }
1991 
1992         //List.opCmp
1993         pure nothrow @safe @nogc unittest{
1994             auto a1 = List!(int).build(1, 2, 3);
1995             auto a2 = List!(int).build(1, 2, 3, 4);
1996             auto b = List!(int).build(3, 2, 1);
1997 
1998             assert(a1 < b);
1999             assert(a1 < a2);
2000             assert(a2 < b);
2001             assert(a1 <= a1);
2002         }
2003 
2004         //List.opIndex
2005         pure nothrow @safe @nogc unittest{
2006             List!(int) list = List!(int).build(1, 2, 3);
2007         }
2008 
2009         //List.proxySwap
2010         pure nothrow @safe @nogc unittest{
2011             auto a = List!(int).build(1, 2, 3);
2012             auto b = List!(int).build(4, 5, 6);
2013 
2014             a.proxySwap(b);
2015             assert(a == [4, 5, 6]);
2016             assert(b == [1, 2, 3]);
2017 
2018             import std.algorithm.mutation : swap;
2019 
2020             swap(a, b);
2021             assert(a == [1, 2, 3]);
2022             assert(b == [4, 5, 6]);
2023         }
2024 
2025         //List.frontCopy
2026         pure nothrow @safe @nogc unittest{
2027             auto list = List!(int).build(1, 2, 3);
2028 
2029             assert(list.frontCopy == 1);
2030             assert(list == [1, 2, 3]);
2031         }
2032 
2033         //List.moveFront
2034         pure nothrow @safe @nogc unittest{
2035             auto list = List!(int).build(1, 2, 3);
2036 
2037             assert(list.moveFront == 1);
2038             list.popFront;
2039             assert(list == [2, 3]);
2040         }
2041 
2042         //List.popFront
2043         pure nothrow @safe @nogc unittest{
2044             List!(int) list = List!(int).build(30, 20, 10);
2045             assert(list.length == 3);
2046 
2047             assert(list.popFront == 30);
2048             assert(list.length == 2);
2049 
2050             assert(list.popFront == 20);
2051             assert(list.length == 1);
2052 
2053             assert(list.popFront == 10);
2054             assert(list.empty);
2055 
2056             assert(list.popFront(int.init) == int.init);
2057             assert(list.empty);
2058 
2059             assert(list.popFront(42) == 42);
2060             assert(list.empty);
2061         }
2062 
2063         //List.emplaceFront
2064         pure nothrow @safe @nogc unittest{
2065             {
2066                 auto list = List!(int).build(1, 2, 3);
2067 
2068                 list.emplaceFront(42);
2069                 assert(list == [42, 1, 2, 3]);
2070 
2071                 list.emplaceFront();
2072                 assert(list == [0, 42, 1, 2, 3]);
2073             }
2074 
2075             {
2076                 static struct Foo{
2077                     int i;
2078                     string str;
2079                 }
2080 
2081                 auto list = List!(Foo).build(Foo(1, "A"));
2082 
2083                 list.emplaceFront(2, "B");
2084                 assert(list == only(Foo(2, "B"), Foo(1, "A")));
2085             }
2086         }
2087 
2088         //List.pushFront
2089         pure nothrow @safe @nogc unittest{
2090             {
2091                 auto list = List!(int).build(1, 2, 3);
2092 
2093                 list.pushFront(42);
2094                 assert(list == [42, 1, 2, 3]);
2095             }
2096 
2097             {
2098                 auto list = List!(int).build(1, 2, 3);
2099 
2100                 list.pushFront(only(4, 5, 6));
2101                 assert(list == [6, 5, 4, 1, 2, 3]);
2102             }
2103 
2104             {
2105                 auto a = List!(int).build(1, 2, 3);
2106                 auto b = List!(int).build(4, 5, 6);
2107 
2108                 a.pushFront(b);
2109                 assert(a == [6, 5, 4, 1, 2, 3]);
2110             }
2111 
2112             {
2113                 List!(int) list = List!(int).build(1, 2, 3);
2114                 int[3] tmp = [4, 5, 6];
2115                 list.pushFront(tmp[]);
2116                 assert(list == [6, 5, 4, 1, 2, 3]);
2117             }
2118 
2119             {
2120                 struct Range{
2121                     int i;
2122 
2123                     bool empty()(){return i == 0;}
2124                     int front()(){return i;}
2125                     void popFront()(){i -= 1;}
2126                     //size_t length(); //no length
2127                 }
2128 
2129                 List!(int) list = List!(int).build(6, 5, 4);
2130                 list.pushFront(Range(3));
2131                 assert(list == [1, 2, 3, 6, 5, 4]);
2132             }
2133         }
2134 
2135         //List.backCopy
2136         pure nothrow @safe @nogc unittest{
2137             auto list = List!(int).build(1, 2, 3);
2138 
2139             assert(list.backCopy == 3);
2140             assert(list == [1, 2, 3]);
2141         }
2142 
2143         //List.moveBack
2144         pure nothrow @safe @nogc unittest{
2145             auto list = List!(int).build(1, 2, 3);
2146 
2147             assert(list.moveBack == 3);
2148             list.popBack;
2149             assert(list == [1, 2]);
2150         }
2151 
2152         //List.popBack
2153         pure nothrow @safe @nogc unittest{
2154             List!(int) list = List!(int).build(10, 20, 30);
2155             assert(list.length == 3);
2156 
2157             assert(list.popBack == 30);
2158             assert(list.length == 2);
2159 
2160             assert(list.popBack == 20);
2161             assert(list.length == 1);
2162 
2163             assert(list.popBack == 10);
2164             assert(list.empty);
2165 
2166             assert(list.popBack(int.init) == int.init);
2167             assert(list.empty);
2168 
2169             assert(list.popBack(42) == 42);
2170             assert(list.empty);
2171         }
2172 
2173         //List.emplaceBack
2174         pure nothrow @safe @nogc unittest{
2175             {
2176                 auto list = List!(int).build(1, 2, 3);
2177 
2178                 list.emplaceBack(42);
2179                 assert(list == [1, 2, 3, 42]);
2180 
2181                 list.emplaceBack();
2182                 assert(list == [1, 2, 3, 42, 0]);
2183             }
2184 
2185             {
2186                 static struct Foo{
2187                     int i;
2188                     string str;
2189                 }
2190 
2191                 auto list = List!(Foo).build(Foo(1, "A"));
2192 
2193                 list.emplaceBack(2, "B");
2194                 assert(list == only(Foo(1, "A"), Foo(2, "B")));
2195             }
2196         }
2197 
2198         //List.pushBack
2199         pure nothrow @safe @nogc unittest{
2200             {
2201                 auto list = List!(int).build(1, 2, 3);
2202 
2203                 list.pushBack(42);
2204                 assert(list == [1, 2, 3, 42]);
2205             }
2206 
2207             {
2208                 auto list = List!(int).build(1, 2, 3);
2209 
2210                 list.pushBack(only(4, 5, 6));
2211                 assert(list == [1, 2, 3, 4, 5, 6]);
2212             }
2213 
2214             {
2215                 auto a = List!(int).build(1, 2, 3);
2216                 auto b = List!(int).build(4, 5, 6);
2217 
2218                 a.pushBack(b);
2219                 assert(a == [1, 2, 3, 4, 5, 6]);
2220             }
2221 
2222             {
2223                 List!(int) list = List!(int).build(1, 2, 3);
2224                 int[3] tmp = [4, 5, 6];
2225                 list.pushBack(tmp[]);
2226                 assert(list == [1, 2, 3, 4, 5, 6]);
2227             }
2228 
2229             {
2230                 struct Range{
2231                     int i;
2232 
2233                     bool empty()(){return i == 0;}
2234                     int front()(){return i;}
2235                     void popFront()(){i -= 1;}
2236                     //size_t length(); //no length
2237                 }
2238 
2239                 List!(int) list = List!(int).build(6, 5, 4);
2240                 list.pushBack(Range(3));
2241                 assert(list == [6, 5, 4, 3, 2, 1]);
2242             }
2243         }
2244 
2245         //List.build
2246         pure nothrow @safe @nogc unittest{
2247             import std.range : only;
2248 
2249             int[2] tmp = [3, 4];
2250             auto list = List!(int).build(1, 2, tmp[], only(5, 6), List!(int).build(7, 8));
2251             assert(list == [1, 2, 3, 4, 5, 6, 7, 8]);
2252         }
2253     }
2254 
2255 
2256 }