1/**
2This module implements a singly-linked list container.
3It can be used as a stack.
4
5This module is a submodule of $(MREF std, container).
6
7Source: $(PHOBOSSRC std/container/slist.d)
8
9Copyright: 2010- Andrei Alexandrescu. All rights reserved by the respective holders.
10
11License: Distributed under the Boost Software License, Version 1.0.
12(See accompanying file LICENSE_1_0.txt or copy at $(HTTP
13boost.org/LICENSE_1_0.txt)).
14
15Authors: $(HTTP erdani.com, Andrei Alexandrescu)
16
17$(SCRIPT inhibitQuickIndex = 1;)
18*/
19module std.container.slist;
20
21///
22@safe unittest
23{
24    import std.algorithm.comparison : equal;
25    import std.container : SList;
26
27    auto s = SList!int(1, 2, 3);
28    assert(equal(s[], [1, 2, 3]));
29
30    s.removeFront();
31    assert(equal(s[], [2, 3]));
32
33    s.insertFront([5, 6]);
34    assert(equal(s[], [5, 6, 2, 3]));
35
36    // If you want to apply range operations, simply slice it.
37    import std.algorithm.searching : countUntil;
38    import std.range : popFrontN, walkLength;
39
40    auto sl = SList!int(1, 2, 3, 4, 5);
41    assert(countUntil(sl[], 2) == 1);
42
43    auto r = sl[];
44    popFrontN(r, 2);
45    assert(walkLength(r) == 3);
46}
47
48public import std.container.util;
49
50/**
51   Implements a simple and fast singly-linked list.
52   It can be used as a stack.
53
54   `SList` uses reference semantics.
55 */
56struct SList(T)
57if (!is(T == shared))
58{
59    import std.exception : enforce;
60    import std.range : Take;
61    import std.range.primitives : isInputRange, isForwardRange, ElementType;
62    import std.traits : isImplicitlyConvertible;
63
64    private struct Node
65    {
66        Node * _next;
67        T _payload;
68    }
69    private struct NodeWithoutPayload
70    {
71        Node* _next;
72    }
73    static assert(NodeWithoutPayload._next.offsetof == Node._next.offsetof);
74
75    private Node * _root;
76
77    private void initialize() @trusted nothrow pure
78    {
79        if (_root) return;
80        _root = cast (Node*) new NodeWithoutPayload();
81    }
82
83    private ref inout(Node*) _first() @property @safe nothrow pure inout
84    {
85        assert(_root, "root pointer must not be null");
86        return _root._next;
87    }
88
89    private static Node * findLastNode(Node * n)
90    {
91        assert(n, "Node n pointer must not be null");
92        auto ahead = n._next;
93        while (ahead)
94        {
95            n = ahead;
96            ahead = n._next;
97        }
98        return n;
99    }
100
101    private static Node * findLastNode(Node * n, size_t limit)
102    {
103        assert(n, "Node n pointer must not be null");
104        assert(limit, "limit must be greater than 0");
105        auto ahead = n._next;
106        while (ahead)
107        {
108            if (!--limit) break;
109            n = ahead;
110            ahead = n._next;
111        }
112        return n;
113    }
114
115    private static Node * findNode(Node * n, Node * findMe)
116    {
117        assert(n, "Node n pointer must not be null");
118        auto ahead = n._next;
119        while (ahead != findMe)
120        {
121            n = ahead;
122            enforce(n);
123            ahead = n._next;
124        }
125        return n;
126    }
127
128    private static Node* findNodeByValue(Node* n, T value)
129    {
130        if (!n) return null;
131        auto ahead = n._next;
132        while (ahead && ahead._payload != value)
133        {
134            n = ahead;
135            ahead = n._next;
136        }
137        return n;
138    }
139
140    private static auto createNodeChain(Stuff)(Stuff stuff)
141    if (isImplicitlyConvertible!(Stuff, T))
142    {
143        import std.range : only;
144        return createNodeChain(only(stuff));
145    }
146
147    private static auto createNodeChain(Stuff)(Stuff stuff)
148    if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
149    {
150        static struct Chain
151        {
152            Node* first;
153            Node* last;
154            size_t length;
155        }
156
157        Chain ch;
158
159        foreach (item; stuff)
160        {
161            auto newNode = new Node(null, item);
162            (ch.first ? ch.last._next : ch.first) = newNode;
163            ch.last = newNode;
164            ++ch.length;
165        }
166
167        return ch;
168    }
169
170    private static size_t insertAfterNode(Stuff)(Node* n, Stuff stuff)
171    {
172        auto ch = createNodeChain(stuff);
173
174        if (!ch.length) return 0;
175
176        ch.last._next = n._next;
177        n._next = ch.first;
178
179        return ch.length;
180    }
181
182/**
183Constructor taking a number of nodes
184     */
185    this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
186    {
187        insertFront(values);
188    }
189
190/**
191Constructor taking an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
192     */
193    this(Stuff)(Stuff stuff)
194    if (isInputRange!Stuff
195            && isImplicitlyConvertible!(ElementType!Stuff, T)
196            && !is(Stuff == T[]))
197    {
198        insertFront(stuff);
199    }
200
201/**
202Comparison for equality.
203
204Complexity: $(BIGOH min(n, n1)) where `n1` is the number of
205elements in `rhs`.
206     */
207    bool opEquals(const SList rhs) const
208    {
209        return opEquals(rhs);
210    }
211
212    /// ditto
213    bool opEquals(ref const SList rhs) const
214    {
215        if (_root is rhs._root) return true;
216        if (_root is null) return rhs._root is null || rhs._first is null;
217        if (rhs._root is null) return _root is null || _first is null;
218
219        const(Node) * n1 = _first, n2 = rhs._first;
220
221        for (;; n1 = n1._next, n2 = n2._next)
222        {
223            if (!n1) return !n2;
224            if (!n2 || n1._payload != n2._payload) return false;
225        }
226    }
227
228/**
229Defines the container's primary range, which embodies a forward range.
230     */
231    struct Range
232    {
233        private Node * _head;
234        private this(Node * p) { _head = p; }
235
236        /// Input range primitives.
237        @property bool empty() const { return !_head; }
238
239        /// ditto
240        @property ref T front()
241        {
242            assert(!empty, "SList.Range.front: Range is empty");
243            return _head._payload;
244        }
245
246        /// ditto
247        void popFront()
248        {
249            assert(!empty, "SList.Range.popFront: Range is empty");
250            _head = _head._next;
251        }
252
253        /// Forward range primitive.
254        @property Range save() { return this; }
255
256        T moveFront()
257        {
258            import std.algorithm.mutation : move;
259
260            assert(!empty, "SList.Range.moveFront: Range is empty");
261            return move(_head._payload);
262        }
263
264        bool sameHead(Range rhs)
265        {
266            return _head && _head == rhs._head;
267        }
268    }
269
270    @safe unittest
271    {
272        static assert(isForwardRange!Range);
273    }
274
275/**
276Property returning `true` if and only if the container has no
277elements.
278
279Complexity: $(BIGOH 1)
280     */
281    @property bool empty() const
282    {
283        return _root is null || _first is null;
284    }
285
286/**
287Duplicates the container. The elements themselves are not transitively
288duplicated.
289
290Complexity: $(BIGOH n).
291     */
292    @property SList dup()
293    {
294        return SList(this[]);
295    }
296
297/**
298Returns a range that iterates over all elements of the container, in
299forward order.
300
301Complexity: $(BIGOH 1)
302     */
303    Range opSlice()
304    {
305        if (empty)
306            return Range(null);
307        else
308            return Range(_first);
309    }
310
311/**
312Forward to `opSlice().front`.
313
314Complexity: $(BIGOH 1)
315     */
316    @property ref T front()
317    {
318        assert(!empty, "SList.front: List is empty");
319        return _first._payload;
320    }
321
322    @safe unittest
323    {
324        auto s = SList!int(1, 2, 3);
325        s.front = 42;
326        assert(s == SList!int(42, 2, 3));
327    }
328
329/**
330Returns a new `SList` that's the concatenation of `this` and its
331argument. `opBinaryRight` is only defined if `Stuff` does not
332define `opBinary`.
333     */
334    SList opBinary(string op, Stuff)(Stuff rhs)
335    if (op == "~" && is(typeof(SList(rhs))))
336    {
337        import std.range : chain, only;
338
339        static if (isInputRange!Stuff)
340            alias r = rhs;
341        else
342            auto r = only(rhs);
343
344        return SList(this[].chain(r));
345    }
346
347    /// ditto
348    SList opBinaryRight(string op, Stuff)(Stuff lhs)
349    if (op == "~" && !is(typeof(lhs.opBinary!"~"(this))) && is(typeof(SList(lhs))))
350    {
351        import std.range : chain, only;
352
353        static if (isInputRange!Stuff)
354            alias r = lhs;
355        else
356            auto r = only(lhs);
357
358        return SList(r.chain(this[]));
359    }
360
361/**
362Removes all contents from the `SList`.
363
364Postcondition: `empty`
365
366Complexity: $(BIGOH 1)
367     */
368    void clear()
369    {
370        if (_root)
371            _first = null;
372    }
373
374/**
375Reverses SList in-place. Performs no memory allocation.
376
377Complexity: $(BIGOH n)
378     */
379    void reverse()
380    {
381        if (!empty)
382        {
383            Node* prev;
384            while (_first)
385            {
386                auto next = _first._next;
387                _first._next = prev;
388                prev = _first;
389                _first = next;
390            }
391            _first = prev;
392        }
393    }
394
395/**
396Inserts `stuff` to the front of the container. `stuff` can be a
397value convertible to `T` or a range of objects convertible to $(D
398T). The stable version behaves the same, but guarantees that ranges
399iterating over the container are never invalidated.
400
401Returns: The number of elements inserted
402
403Complexity: $(BIGOH m), where `m` is the length of `stuff`
404     */
405    size_t insertFront(Stuff)(Stuff stuff)
406    if (isInputRange!Stuff || isImplicitlyConvertible!(Stuff, T))
407    {
408        initialize();
409        return insertAfterNode(_root, stuff);
410    }
411
412    /// ditto
413    alias insert = insertFront;
414
415    /// ditto
416    alias stableInsert = insert;
417
418    /// ditto
419    alias stableInsertFront = insertFront;
420
421/**
422Picks one value in an unspecified position in the container, removes
423it from the container, and returns it. The stable version behaves the same,
424but guarantees that ranges iterating over the container are never invalidated.
425
426Precondition: `!empty`
427
428Returns: The element removed.
429
430Complexity: $(BIGOH 1).
431     */
432    T removeAny()
433    {
434        import std.algorithm.mutation : move;
435
436        assert(!empty, "SList.removeAny: List is empty");
437        auto result = move(_first._payload);
438        _first = _first._next;
439        return result;
440    }
441    /// ditto
442    alias stableRemoveAny = removeAny;
443
444/**
445Removes the value at the front of the container. The stable version
446behaves the same, but guarantees that ranges iterating over the
447container are never invalidated.
448
449Precondition: `!empty`
450
451Complexity: $(BIGOH 1).
452     */
453    void removeFront()
454    {
455        assert(!empty, "SList.removeFront: List is empty");
456        _first = _first._next;
457    }
458
459    /// ditto
460    alias stableRemoveFront = removeFront;
461
462/**
463Removes `howMany` values at the front or back of the
464container. Unlike the unparameterized versions above, these functions
465do not throw if they could not remove `howMany` elements. Instead,
466if $(D howMany > n), all elements are removed. The returned value is
467the effective number of elements removed. The stable version behaves
468the same, but guarantees that ranges iterating over the container are
469never invalidated.
470
471Returns: The number of elements removed
472
473Complexity: $(BIGOH howMany * log(n)).
474     */
475    size_t removeFront(size_t howMany)
476    {
477        size_t result;
478        while (_first && result < howMany)
479        {
480            _first = _first._next;
481            ++result;
482        }
483        return result;
484    }
485
486    /// ditto
487    alias stableRemoveFront = removeFront;
488
489/**
490Inserts `stuff` after range `r`, which must be a range
491previously extracted from this container. Given that all ranges for a
492list end at the end of the list, this function essentially appends to
493the list and uses `r` as a potentially fast way to reach the last
494node in the list. Ideally `r` is positioned near or at the last
495element of the list.
496
497`stuff` can be a value convertible to `T` or a range of objects
498convertible to `T`. The stable version behaves the same, but
499guarantees that ranges iterating over the container are never
500invalidated.
501
502Returns: The number of values inserted.
503
504Complexity: $(BIGOH k + m), where `k` is the number of elements in
505`r` and `m` is the length of `stuff`.
506
507Example:
508--------------------
509auto sl = SList!string(["a", "b", "d"]);
510sl.insertAfter(sl[], "e"); // insert at the end (slowest)
511assert(std.algorithm.equal(sl[], ["a", "b", "d", "e"]));
512sl.insertAfter(std.range.take(sl[], 2), "c"); // insert after "b"
513assert(std.algorithm.equal(sl[], ["a", "b", "c", "d", "e"]));
514--------------------
515     */
516
517    size_t insertAfter(Stuff)(Range r, Stuff stuff)
518    if (isInputRange!Stuff || isImplicitlyConvertible!(Stuff, T))
519    {
520        initialize();
521        if (!_first)
522        {
523            enforce(!r._head);
524            return insertFront(stuff);
525        }
526        enforce(r._head);
527        auto n = findLastNode(r._head);
528        return insertAfterNode(n, stuff);
529    }
530
531/**
532Similar to `insertAfter` above, but accepts a range bounded in
533count. This is important for ensuring fast insertions in the middle of
534the list.  For fast insertions after a specified position `r`, use
535$(D insertAfter(take(r, 1), stuff)). The complexity of that operation
536only depends on the number of elements in `stuff`.
537
538Precondition: $(D r.original.empty || r.maxLength > 0)
539
540Returns: The number of values inserted.
541
542Complexity: $(BIGOH k + m), where `k` is the number of elements in
543`r` and `m` is the length of `stuff`.
544     */
545    size_t insertAfter(Stuff)(Take!Range r, Stuff stuff)
546    if (isInputRange!Stuff || isImplicitlyConvertible!(Stuff, T))
547    {
548        auto orig = r.source;
549        if (!orig._head)
550        {
551            // Inserting after a null range counts as insertion to the
552            // front
553            return insertFront(stuff);
554        }
555        enforce(!r.empty);
556        // Find the last valid element in the range
557        foreach (i; 1 .. r.maxLength)
558        {
559            if (!orig._head._next) break;
560            orig.popFront();
561        }
562        // insert here
563        return insertAfterNode(orig._head, stuff);
564    }
565
566/// ditto
567    alias stableInsertAfter = insertAfter;
568
569/**
570Removes a range from the list in linear time.
571
572Returns: An empty range.
573
574Complexity: $(BIGOH n)
575     */
576    Range linearRemove(Range r)
577    {
578        if (!_first)
579        {
580            enforce(!r._head);
581            return this[];
582        }
583        auto n = findNode(_root, r._head);
584        n._next = null;
585        return Range(null);
586    }
587
588/**
589Removes a `Take!Range` from the list in linear time.
590
591Returns: A range comprehending the elements after the removed range.
592
593Complexity: $(BIGOH n)
594     */
595    Range linearRemove(Take!Range r)
596    {
597        auto orig = r.source;
598        // We have something to remove here
599        if (orig._head == _first)
600        {
601            // remove straight from the head of the list
602            for (; !r.empty; r.popFront())
603            {
604                removeFront();
605            }
606            return this[];
607        }
608        if (!r.maxLength)
609        {
610            // Nothing to remove, return the range itself
611            return orig;
612        }
613        // Remove from somewhere in the middle of the list
614        enforce(_first);
615        auto n1 = findNode(_root, orig._head);
616        auto n2 = findLastNode(orig._head, r.maxLength);
617        n1._next = n2._next;
618        return Range(n1._next);
619    }
620
621/// ditto
622    alias stableLinearRemove = linearRemove;
623
624/**
625Removes the first occurence of an element from the list in linear time.
626
627Returns: True if the element existed and was successfully removed, false otherwise.
628
629Params:
630    value = value of the node to be removed
631
632Complexity: $(BIGOH n)
633     */
634    bool linearRemoveElement(T value)
635    {
636        auto n1 = findNodeByValue(_root, value);
637
638        if (n1 && n1._next)
639        {
640            n1._next = n1._next._next;
641            return true;
642        }
643
644        return false;
645    }
646}
647
648@safe unittest
649{
650    import std.algorithm.comparison : equal;
651
652    auto e = SList!int();
653    auto b = e.linearRemoveElement(2);
654    assert(b == false);
655    assert(e.empty());
656    auto a = SList!int(-1, 1, 2, 1, 3, 4);
657    b = a.linearRemoveElement(1);
658    assert(equal(a[], [-1, 2, 1, 3, 4]));
659    assert(b == true);
660    b = a.linearRemoveElement(-1);
661    assert(b == true);
662    assert(equal(a[], [2, 1, 3, 4]));
663    b = a.linearRemoveElement(1);
664    assert(b == true);
665    assert(equal(a[], [2, 3, 4]));
666    b = a.linearRemoveElement(2);
667    assert(b == true);
668    b = a.linearRemoveElement(20);
669    assert(b == false);
670    assert(equal(a[], [3, 4]));
671    b = a.linearRemoveElement(4);
672    assert(b == true);
673    assert(equal(a[], [3]));
674    b = a.linearRemoveElement(3);
675    assert(b == true);
676    assert(a.empty());
677    a.linearRemoveElement(3);
678}
679
680@safe unittest
681{
682    import std.algorithm.comparison : equal;
683
684    auto a = SList!int(5);
685    auto b = a;
686    auto r = a[];
687    a.insertFront(1);
688    b.insertFront(2);
689    assert(equal(a[], [2, 1, 5]));
690    assert(equal(b[], [2, 1, 5]));
691    r.front = 9;
692    assert(equal(a[], [2, 1, 9]));
693    assert(equal(b[], [2, 1, 9]));
694}
695
696@safe unittest
697{
698    auto s = SList!int(1, 2, 3);
699    auto n = s.findLastNode(s._root);
700    assert(n && n._payload == 3);
701}
702
703@safe unittest
704{
705    import std.range.primitives;
706    auto s = SList!int(1, 2, 5, 10);
707    assert(walkLength(s[]) == 4);
708}
709
710@safe unittest
711{
712    import std.range : take;
713    auto src = take([0, 1, 2, 3], 3);
714    auto s = SList!int(src);
715    assert(s == SList!int(0, 1, 2));
716}
717
718@safe unittest
719{
720    auto a = SList!int();
721    auto b = SList!int();
722    auto c = a ~ b[];
723    assert(c.empty);
724}
725
726@safe unittest
727{
728    auto a = SList!int(1, 2, 3);
729    auto b = SList!int(4, 5, 6);
730    auto c = a ~ b[];
731    assert(c == SList!int(1, 2, 3, 4, 5, 6));
732}
733
734@safe unittest
735{
736    auto a = SList!int(1, 2, 3);
737    auto b = [4, 5, 6];
738    auto c = a ~ b;
739    assert(c == SList!int(1, 2, 3, 4, 5, 6));
740}
741
742@safe unittest
743{
744    auto a = SList!int(1, 2, 3);
745    auto c = a ~ 4;
746    assert(c == SList!int(1, 2, 3, 4));
747}
748
749@safe unittest
750{
751    auto a = SList!int(2, 3, 4);
752    auto b = 1 ~ a;
753    assert(b == SList!int(1, 2, 3, 4));
754}
755
756@safe unittest
757{
758    auto a = [1, 2, 3];
759    auto b = SList!int(4, 5, 6);
760    auto c = a ~ b;
761    assert(c == SList!int(1, 2, 3, 4, 5, 6));
762}
763
764@safe unittest
765{
766    auto s = SList!int(1, 2, 3, 4);
767    s.insertFront([ 42, 43 ]);
768    assert(s == SList!int(42, 43, 1, 2, 3, 4));
769}
770
771@safe unittest
772{
773    auto s = SList!int(1, 2, 3);
774    assert(s.removeAny() == 1);
775    assert(s == SList!int(2, 3));
776    assert(s.stableRemoveAny() == 2);
777    assert(s == SList!int(3));
778}
779
780@safe unittest
781{
782    import std.algorithm.comparison : equal;
783
784    auto s = SList!int(1, 2, 3);
785    s.removeFront();
786    assert(equal(s[], [2, 3]));
787    s.stableRemoveFront();
788    assert(equal(s[], [3]));
789}
790
791@safe unittest
792{
793    auto s = SList!int(1, 2, 3, 4, 5, 6, 7);
794    assert(s.removeFront(3) == 3);
795    assert(s == SList!int(4, 5, 6, 7));
796}
797
798@safe unittest
799{
800    auto a = SList!int(1, 2, 3);
801    auto b = SList!int(1, 2, 3);
802    assert(a.insertAfter(a[], b[]) == 3);
803}
804
805@safe unittest
806{
807    import std.range : take;
808    auto s = SList!int(1, 2, 3, 4);
809    auto r = take(s[], 2);
810    assert(s.insertAfter(r, 5) == 1);
811    assert(s == SList!int(1, 2, 5, 3, 4));
812}
813
814@safe unittest
815{
816    import std.algorithm.comparison : equal;
817    import std.range : take;
818
819    // insertAfter documentation example
820    auto sl = SList!string(["a", "b", "d"]);
821    sl.insertAfter(sl[], "e"); // insert at the end (slowest)
822    assert(equal(sl[], ["a", "b", "d", "e"]));
823    sl.insertAfter(take(sl[], 2), "c"); // insert after "b"
824    assert(equal(sl[], ["a", "b", "c", "d", "e"]));
825}
826
827@safe unittest
828{
829    import std.range.primitives;
830    auto s = SList!int(1, 2, 3, 4, 5);
831    auto r = s[];
832    popFrontN(r, 3);
833    auto r1 = s.linearRemove(r);
834    assert(s == SList!int(1, 2, 3));
835    assert(r1.empty);
836}
837
838@safe unittest
839{
840    auto s = SList!int(1, 2, 3, 4, 5);
841    auto r = s[];
842    auto r1 = s.linearRemove(r);
843    assert(s == SList!int());
844    assert(r1.empty);
845}
846
847@safe unittest
848{
849    import std.algorithm.comparison : equal;
850    import std.range;
851
852    auto s = SList!int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
853    auto r = s[];
854    popFrontN(r, 3);
855    auto r1 = take(r, 4);
856    assert(equal(r1, [4, 5, 6, 7]));
857    auto r2 = s.linearRemove(r1);
858    assert(s == SList!int(1, 2, 3, 8, 9, 10));
859    assert(equal(r2, [8, 9, 10]));
860}
861
862@safe unittest
863{
864    import std.range.primitives;
865    auto lst = SList!int(1, 5, 42, 9);
866    assert(!lst.empty);
867    assert(lst.front == 1);
868    assert(walkLength(lst[]) == 4);
869
870    auto lst2 = lst ~ [ 1, 2, 3 ];
871    assert(walkLength(lst2[]) == 7);
872
873    auto lst3 = lst ~ [ 7 ];
874    assert(walkLength(lst3[]) == 5);
875}
876
877@safe unittest
878{
879    auto s = make!(SList!int)(1, 2, 3);
880}
881
882// https://issues.dlang.org/show_bug.cgi?id=5193
883@safe unittest
884{
885    static struct Data
886    {
887        const int val;
888    }
889    SList!Data list;
890}
891
892@safe unittest
893{
894    auto s = SList!int([1, 2, 3]);
895    s.front = 5; //test frontAssign
896    assert(s.front == 5);
897    auto r = s[];
898    r.front = 1; //test frontAssign
899    assert(r.front == 1);
900}
901
902// https://issues.dlang.org/show_bug.cgi?id=14920
903@safe unittest
904{
905    SList!int s;
906    s.insertAfter(s[], 1);
907    assert(s.front == 1);
908}
909
910// https://issues.dlang.org/show_bug.cgi?id=15659
911@safe unittest
912{
913    SList!int s;
914    s.clear();
915}
916
917@safe unittest
918{
919    SList!int s;
920    s.reverse();
921}
922
923@safe unittest
924{
925    import std.algorithm.comparison : equal;
926
927    auto s = SList!int([1, 2, 3]);
928    assert(s[].equal([1, 2, 3]));
929
930    s.reverse();
931    assert(s[].equal([3, 2, 1]));
932}
933
934@safe unittest
935{
936    auto s = SList!int([4, 6, 8, 12, 16]);
937    auto d = s.dup;
938    assert(d !is s);
939    assert(d == s);
940}
941