1 module carbon.memory;
2 
3 import carbon.functional;
4 
5 import core.exception;
6 import core.stdc.stdlib;
7 import core.memory;
8 
9 import std.algorithm;
10 import std.conv;
11 import std.stdio;
12 import std.exception;
13 import std.range;
14 import std.traits;
15 import std.typecons;
16 
17 
18 void callAllPostblit(T)(ref T obj)
19 if(is(T == struct))
20 {
21     foreach(ref e; obj.tupleof)
22         callAllPostblit(e);
23 
24     static if(is(typeof(obj.__postblit())))
25         obj.__postblit();
26 }
27 
28 
29 void callAllPostblit(T)(ref T obj)
30 if(!is(T == struct))
31 {}
32 
33 
34 void callAllDtor(T)(ref T obj)
35 if(is(T == struct))
36 {
37     static if(is(typeof(obj.__dtor())))
38         obj.__dtor();
39 
40     foreach(ref e; obj.tupleof)
41         callAllDtor(e);
42 }
43 
44 
45 void callAllDtor(T)(ref T obj)
46 if(!is(T == struct))
47 {}
48 
49 
50 
51 // copy from core.exception
52 extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @nogc @trusted pure nothrow /* dmd @@@BUG11461@@@ */
53 {
54     // NOTE: Since an out of memory condition exists, no allocation must occur
55     //       while generating this object.
56     throw cast(OutOfMemoryError) cast(void*) typeid(OutOfMemoryError).init;
57 }
58 
59 
60 private
61 E[] uninitializedCHeapArray(E)(size_t n) @trusted nothrow
62 {
63     if(n){
64         auto p = cast(E*)core.stdc.stdlib.malloc(n * E.sizeof);
65         if(p is null)
66             onOutOfMemoryError();
67 
68       static if(hasIndirections!E)
69       {
70         core.stdc..string.memset(p, 0, n * E.sizeof);
71         GC.addRange(p, n * E.sizeof);
72       }
73 
74         return p[0 .. n];
75     }else
76         return null;
77 }
78 
79 
80 private
81 void destroyCHeapArray(E)(ref E[] arr) nothrow @nogc
82 {
83     static if(hasElaborateDestructor!E)
84         foreach(ref e; arr)
85             callAllDtor(e);
86 
87     static if(hasIndirections!E)
88         GC.removeRange(arr.ptr);
89 
90     assumeTrusted!(core.stdc.stdlib.free)(arr.ptr);
91     arr = null;
92 }
93 
94 
95 private
96 void reallocCHeapArray(E)(ref E[] arr, size_t n)
97 {
98     if(n <= arr.length)     // n == 0 なら常に return される
99         return;
100 
101     immutable oldLen = arr.length;
102 
103   static if(hasIndirections!T)
104   {
105     auto newarr = uninitializedCHeapArray!E(n);
106     assumeTrusted!(core.stdc..string.memcpy)(newarr.ptr, arr.ptr, E.sizeof * oldLen);
107     assumeTrusted!(core.stdc..string.memset)(assumeTrusted!"a+b"(newarr.ptr + oldLen), 0, (n - oldLen) * E.sizeof);
108     GC.addRange(newarr.ptr, n * E.sizeof);
109     GC.removeRange(arr.ptr);
110     assumeTrusted!(core.stdc.stdlib.free)(arr.ptr);
111 
112     arr = newarr;
113   }
114   else
115   {
116     void* p = assumeTrusted!(core.stdc.stdlib.realloc)(arr.ptr, n * E.sizeof);
117     if(p is null)
118         onOutOfMemoryError();
119 
120     arr = assumeTrusted!((a, b) => (cast(E*)a)[0 .. b])(p, n);
121   }
122 }
123 
124 
125 auto onGCMemory(T)(T obj)
126 {
127     static struct Result {
128         alias _val this;
129         ref inout(T) _val() inout pure nothrow @safe @property { return *_v; }
130         T* _v;
131     }
132 
133     Result res = Result(new T);
134     *res._v = obj;
135     return res;
136 }
137 
138 unittest
139 {
140     auto r = [1, 2, 3, 4, 5].map!"a+2".onGCMemory;
141 
142     static void popN(R)(R r, size_t n)
143     {
144         foreach(i; 0 .. n) r.popFront();
145     }
146 
147     assert(equal(r.save, [3, 4, 5, 6, 7]));
148     popN(r, 2);
149     assert(equal(r.save, [5, 6, 7]));
150 }
151 
152 
153 
154 /**
155 */
156 struct UninitializedTemporaryBuffer(T)
157 {
158     import core.stdc.stdlib;
159 
160     @disable
161     this(this);
162 
163 
164     this(size_t n) @trusted
165     {
166         slice = uninitializedCHeapArray!T(n);
167     }
168 
169 
170     ~this() @trusted
171     {
172         destroyCHeapArray(slice);
173     }
174 
175 
176     T[] slice;
177     alias slice this;
178 }
179 
180 
181 /**
182 Defines a reference-counted object containing a $(D T) value as
183 payload. $(D RefCountedNoGC) keeps track of all references of an object,
184 and when the reference count goes down to zero, frees the underlying
185 store. $(D RefCountedNoGC) uses $(D malloc) and $(D free) for operation.
186 
187 $(D RefCountedNoGC) is unsafe and should be used with care. No references
188 to the payload should be escaped outside the $(D RefCountedNoGC) object.
189 
190 The $(D autoInit) option makes the object ensure the store is
191 automatically initialized. Leaving $(D autoInit ==
192 RefCountedAutoInitialize.yes) (the default option) is convenient but
193 has the cost of a test whenever the payload is accessed. If $(D
194 autoInit == RefCountedAutoInitialize.no), user code must call either
195 $(D refCountedStore.isInitialized) or $(D refCountedStore.ensureInitialized)
196 before attempting to access the payload. Not doing so results in null
197 pointer dereference.
198 
199 Example:
200 ----
201 // A pair of an $(D int) and a $(D size_t) - the latter being the
202 // reference count - will be dynamically allocated
203 auto rc1 = RefCountedNoGC!int(5);
204 assert(rc1 == 5);
205 // No more allocation, add just one extra reference count
206 auto rc2 = rc1;
207 // Reference semantics
208 rc2 = 42;
209 assert(rc1 == 42);
210 // the pair will be freed when rc1 and rc2 go out of scope
211 ----
212  */
213 struct RefCountedNoGC(T, RefCountedAutoInitialize autoInit =
214         RefCountedAutoInitialize.yes)
215 if (!is(T == class))
216 {
217     /// $(D RefCountedNoGC) storage implementation.
218     struct RefCountedStore
219     {
220         private struct Impl
221         {
222             T _payload;
223             size_t _count;
224         }
225 
226         private Impl* _store;
227 
228         private void initialize(A...)(auto ref A args)
229         {
230             import core.memory : GC;
231             import core.stdc.stdlib : malloc;
232             import std.conv : emplace;
233             import std.exception : enforce;
234 
235             _store = cast(Impl*)malloc(Impl.sizeof);
236             if(!_store)
237                 onOutOfMemoryError();
238 
239             static if (hasIndirections!T)
240                 GC.addRange(&_store._payload, T.sizeof);
241             emplace(&_store._payload, args);
242             _store._count = 1;
243         }
244 
245         /**
246            Returns $(D true) if and only if the underlying store has been
247            allocated and initialized.
248         */
249         @property nothrow @safe @nogc
250         bool isInitialized() const
251         {
252             return _store !is null;
253         }
254 
255         /**
256            Returns underlying reference count if it is allocated and initialized
257            (a positive integer), and $(D 0) otherwise.
258         */
259         @property nothrow @safe @nogc
260         size_t refCount() const
261         {
262             return isInitialized ? _store._count : 0;
263         }
264 
265         /**
266            Makes sure the payload was properly initialized. Such a
267            call is typically inserted before using the payload.
268         */
269         void ensureInitialized()
270         {
271             if (!isInitialized) initialize();
272         }
273 
274     }
275     RefCountedStore _refCounted;
276 
277     /// Returns storage implementation struct.
278     @property nothrow @safe
279     ref inout(RefCountedStore) refCountedStore() inout
280     {
281         return _refCounted;
282     }
283 
284 /**
285 Constructor that initializes the payload.
286 
287 Postcondition: $(D refCountedStore.isInitialized)
288  */
289     this(A...)(auto ref A args) if (A.length > 0)
290     {
291         _refCounted.initialize(args);
292     }
293 
294 /**
295 Constructor that tracks the reference count appropriately. If $(D
296 !refCountedStore.isInitialized), does nothing.
297  */
298     this(this)
299     {
300         if (!_refCounted.isInitialized) return;
301         ++_refCounted._store._count;
302     }
303 
304 /**
305 Destructor that tracks the reference count appropriately. If $(D
306 !refCountedStore.isInitialized), does nothing. When the reference count goes
307 down to zero, calls $(D destroy) agaist the payload and calls $(D free)
308 to deallocate the corresponding resource.
309  */
310     ~this()
311     {
312         if (!_refCounted.isInitialized) return;
313         assert(_refCounted._store._count > 0);
314         if (--_refCounted._store._count)
315             return;
316         // Done, deallocate
317         static if(hasElaborateDestructor!T)
318             callAllDtor(_refCounted._store._payload);
319 
320         static if (hasIndirections!T)
321         {
322             import core.memory : GC;
323             GC.removeRange(&_refCounted._store._payload);
324         }
325         import core.stdc.stdlib : free;
326         free(_refCounted._store);
327         _refCounted._store = null;
328     }
329 
330 /**
331 Assignment operators
332  */
333     void opAssign(typeof(this) rhs)
334     {
335         import std.algorithm : swap;
336 
337         swap(_refCounted._store, rhs._refCounted._store);
338     }
339 
340 /// Ditto
341     void opAssign(T rhs)
342     {
343         import std.algorithm : move;
344 
345         static if (autoInit == RefCountedAutoInitialize.yes)
346         {
347             _refCounted.ensureInitialized();
348         }
349         else
350         {
351             assert(_refCounted.isInitialized);
352         }
353         move(rhs, _refCounted._store._payload);
354     }
355 
356     //version to have a single properly ddoc'ed function (w/ correct sig)
357     version(StdDdoc)
358     {
359         /**
360         Returns a reference to the payload. If (autoInit ==
361         RefCountedAutoInitialize.yes), calls $(D
362         refCountedStore.ensureInitialized). Otherwise, just issues $(D
363         assert(refCountedStore.isInitialized)). Used with $(D alias
364         refCountedPayload this;), so callers can just use the $(D RefCountedNoGC)
365         object as a $(D T).
366 
367         $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
368         So if $(D autoInit == RefCountedAutoInitialize.no)
369         or called for a constant or immutable object, then
370         $(D refCountedPayload) will also be qualified as safe and nothrow
371         (but will still assert if not initialized).
372          */
373         @property
374         ref T refCountedPayload();
375 
376         /// ditto
377         @property nothrow @safe
378         ref inout(T) refCountedPayload() inout;
379     }
380     else
381     {
382         static if (autoInit == RefCountedAutoInitialize.yes)
383         {
384             //Can't use inout here because of potential mutation
385             @property
386             ref T refCountedPayload()
387             {
388                 _refCounted.ensureInitialized();
389                 return _refCounted._store._payload;
390             }
391         }
392 
393         @property nothrow @safe
394         ref inout(T) refCountedPayload() inout
395         {
396             assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
397             return _refCounted._store._payload;
398         }
399     }
400 
401 /**
402 Returns a reference to the payload. If (autoInit ==
403 RefCountedAutoInitialize.yes), calls $(D
404 refCountedStore.ensureInitialized). Otherwise, just issues $(D
405 assert(refCountedStore.isInitialized)).
406  */
407     alias refCountedPayload this;
408 }
409 
410 
411 auto toRefCounted(T)(T obj)
412 {
413     return RefCountedNoGC!T(obj);
414 }
415 
416 
417 @nogc unittest
418 {
419     auto r = only(1, 2, 3, 4, 5).map!"a+2".toRefCounted;
420 
421     static void popN(R)(R r, size_t n)
422     {
423         foreach(i; 0 .. n) r.popFront();
424     }
425 
426     assert(equal(r.save, only(3, 4, 5, 6, 7)));
427     popN(r, 2);
428     assert(equal(r.save, only(5, 6, 7)));
429 }
430 
431 
432 __EOF__
433 
434 
435 struct UniqueArray(E, bool bMini = false)
436 {
437     private static
438     size_t allocateSize(size_t n) pure nothrow @safe @nogc
439     {
440       static if(bMini)
441         return n;
442       else
443         return 1 << (core.bitop.bsr(n) + 1);
444     }
445 
446 
447     /**
448     */
449     this(size_t n) nothrow @trusted
450     {
451         immutable elemN = allocateSize(n);
452 
453         auto arr = uninitializedCHeapArray!(Unqual!(E))(elemN);
454         foreach(ref e; arr)
455             .emplace(&e);
456 
457         _array = cast(E[])arr;
458         _s = 0;
459         _e = n;
460     }
461 
462 
463   static if(is(typeof((Unqual!E v){ E x = v; })))
464   {
465     this(bool b)(UniqueArray!(Unqual!E, b) unique) @trusted
466     {
467         _array = cast(E[])unique._array;
468         _s = unique._s;
469         _e = unique._e;
470 
471         unique._array = null;
472     }
473 
474 
475     void opAssign(bool b)(UniqueArray!(const(E), b) unique) @trusted
476     {
477         //.destroy(this);
478         callAllDtor(this);
479 
480         _array = cast(E[])unique._array;
481         _s = unique._s;
482         _e = unique._e;
483 
484         unique._array = null;
485     }
486   }
487 
488 
489   static if(is(typeof((const E v){ E x = v; })))
490   {
491     this(bool b)(UniqueArray!(const(E), b) unique) @trusted
492     {
493         _array = cast(E[])unique._array;
494         _s = unique._s;
495         _e = unique._e;
496 
497         unique._array = null;
498     }
499 
500 
501     void opAssign(bool b)(UniqueArray!(const(E), b) unique) @trusted
502     {
503         //.destroy(this);
504         callAllDtor(this);
505 
506         _array = cast(E[])unique._array;
507         _s = unique._s;
508         _e = unique._e;
509 
510         unique._array = null;
511     }
512   }
513 
514 
515   static if(is(typeof((immutable E v){ E x = v; })))
516   {
517     this(bool b)(UniqueArray!(immutable(E), b) unique) @trusted
518     {
519         _array = cast(E[])unique._array;
520         _s = unique._s;
521         _e = unique._e;
522 
523         unique._array = null;
524     }
525 
526 
527     void opAssign(bool b)(UniqueArray!(immutable(E), b) unique) @trusted
528     {
529         //.destroy(this);
530         callAllDtor(this);
531 
532         _array = cast(E[])unique._array;
533         _s = unique._s;
534         _e = unique._e;
535 
536         unique._array = null;
537     }
538   }
539 
540 
541     ~this()
542     {
543         if(_array !is null){
544           static if(hasElaborateDestructor!E)
545             foreach(ref e; _array)
546                 callAllDtor(e);
547                 //.destroy(e);
548 
549           static if(hasIndirections!E)
550             GC.removeRange(_array.ptr);
551 
552             core.stdc.stdlib.free(cast(void*)_array.ptr);
553             _array = null;
554         }
555     }
556 
557     // can copy
558   static if(is(typeof((E v){ E x = v; })))
559   {
560     this(this)
561     {
562         immutable elemN = (_s == 0 && _e == _array.length) ? _array.length : allocateSize(this.length);
563 
564         auto newarr = uninitializedCHeapArray!(Unqual!E)(elemN);
565         assumeTrusted!((p){
566             foreach(i, ref e; this.view)
567                 emplace(p + i, e);
568         })(newarr.ptr);
569 
570         _array = cast(E[])newarr;
571         _e -= _s;
572         _s = 0;
573     }
574 
575 
576     void opAssign(typeof(this) unique)
577     {
578         swap(this, unique);
579     }
580   }
581   else{
582     @disable this(this);
583     @disable void opAssign(typeof(this) unique);
584   }
585 
586 
587     size_t length() const pure nothrow @safe @nogc @property
588     {
589         return _e - _s;
590     }
591 
592 
593     size_t capacity() const pure nothrow @safe @nogc @property
594     {
595         return _array.length - _e;
596     }
597 
598 
599     size_t reserve(size_t n) @nogc
600     {
601         if(_array is null){
602             auto newArr = typeof(this)(n);
603             this._array = newArr._array;
604             this._s = newArr._s;
605             this._e = newArr._e;
606             newArr._array = null;
607 
608             return this.capacity;
609         }
610         else if(n <= _array.length - _s)
611             return this.capacity;
612         else{
613             immutable newElemN = allocateSize(n);
614             immutable newAllocN = newElemN * E.sizeof;
615 
616             auto p = cast(Unqual!E*)core.stdc.stdlib.malloc(newAllocN);
617             if(!p)
618                 onOutOfMemoryError();
619 
620             core.stdc..string.memcpy(p, _array.ptr + _s, this.length * E.sizeof);
621 
622           static if(hasIndirections!E)
623           {
624             core.stdc..string.memset(p + this.length, 0, (newElemN - this.length) * E.sizeof);
625             GC.addRange(p, newAllocN);
626             GC.removeRange(_array.ptr);
627           }
628 
629             core.stdc.stdlib.free(cast(Unqual!E*)_array.ptr);
630             _array = (cast(E*)p)[0 .. newElemN];
631             _e -= _s;
632             _s = 0;
633 
634             return this.capacity;
635         }
636     }
637 
638 
639     E[] view() pure nothrow @safe @nogc
640     {
641         return _array;
642     }
643 
644 
645   private:
646     E[] _array ;
647     size_t _s, _e;
648 }
649 
650 
651 unittest{
652     UniqueArray!int arr;
653 
654     auto rc = RefCountedNoGC!(UniqueArray!int)(3);
655 }
656 
657 
658 struct RefCountedArrayImpl(E)
659 {
660     this(size_t n) nothrow @trusted @nogc
661     {
662         _refCnt = uninitializedCHeapArray!size_t(1).ptr;
663         *_refCnt = 1;
664         _array = newCHeapArray!E(n);
665     }
666 
667 
668     bool isInitialized() const pure nothrow @safe @nogc @property
669     {
670         return _refCnt !is null;
671     }
672 
673 
674     size_t refCount() const pure nothrow @safe @nogc @property
675     {
676         return isInitialized ? *_refCnt : 0;
677     }
678 
679 
680     this(this) pure nothrow @safe @nogc
681     {
682         if(isInitialized)
683             ++*_refCnt;
684     }
685 
686 
687   static if(is(typeof(() @safe { E e; })))
688   {
689     ~this() @trusted
690     { dtorImpl(); }
691   }
692   else
693   {
694     ~this()
695     { dtorImpl(); }
696   }
697 
698 
699     void dtorImpl()
700     {
701         if(isInitialized){
702             --*_refCnt;
703             if(refCount == 0){
704                 size_t[] dummy = _refCnt[0 .. 1];
705 
706                 dummy.destroyCHeapArray();   // nothrow
707                 _refCnt = null;
708 
709                 _array.destroyCHeapArray();  // maybe throw
710             }
711         }
712     }
713 
714 
715     void reallocate(size_t n)
716     {
717         _array.reallocCHeapArray(n);
718     }
719 
720 
721   private:
722     size_t* _refCnt;
723     E[] _array;
724 }
725 
726 
727 /**
728 Cヒープ上に配列を作成し、その配列を参照カウント方式で管理します。
729 配列への追加は、スライスと同様にCopy On Write方式で管理されます。
730 つまり、複数のオブジェクトが一つの配列を参照している場合に配列への要素の追加を行うと、必ず配列は新たに確保されます。
731 */
732 struct RefCountedArray(E)
733 {
734     alias Impl = RefCountedArrayImpl;
735 
736 
737     /**
738     大きさを指定して配列を作成します。
739     */
740     this(size_t n)
741     {
742         _impl = Impl!E(allocateSize!E(n));
743         _s = 0;
744         _e = n;
745     }
746 
747 
748     /**
749     保持している参照を解除します。
750     よって、参照カウントは一つ減ります。
751     */
752     void release()
753     {
754         _impl = Impl!E.init;
755         _s = 0;
756         _e = 0;
757     }
758 
759 
760     /**
761     */
762     void clear()
763     {
764         if(_impl.refCount == 1){
765             _s = 0;
766             _e = 0;
767         }else
768             release();
769     }
770 
771 
772     /**
773     */
774     size_t capacity() const pure nothrow @safe @nogc @property
775     {
776         if(_impl.refCount == 1)
777             return _impl._array.length - _s;
778         else
779             return 0;
780     }
781 
782 
783     /**
784     */
785     size_t reserve(size_t n)
786     {
787         if(n <= this.length)
788             goto Lreturn;
789 
790         if(!_impl.isInitialized)
791             this = typeof(this)(n);
792         else if(_impl.refCount == 1 && _impl._array.length < n + _s){
793             immutable bool doesMoveToFront = (_s * 2 >= allocateSize!E(n) - _impl._array.length);
794 
795             if(!doesMoveToFront || _impl._array.length < n)
796                 _impl.reallocate(allocateSize!E(n));
797 
798             if(doesMoveToFront){
799                 foreach(i; 0 .. this.length){
800                   static if(is(E == struct) && !__traits(isPOD, E))
801                     _impl._array[i] = std.algorithm.move(_impl._array[_s + i]);
802                   else
803                     _impl._array[i] = _impl._array[_s + i];
804                 }
805 
806                 _e -= _s;
807                 _s = 0;
808             }
809         }
810         else if(_impl.refCount != 1){
811             auto newarr = typeof(this)(n);
812             newarr._impl._array[0 .. this.length] = this._impl._array[_s .. _e];
813             this = newarr;
814         }
815 
816       Lreturn:
817         return this.capacity;
818     }
819 
820 
821     /**
822     */
823     bool isNull() const pure nothrow @safe @nogc @property
824     {
825         return !_impl.isInitialized;
826     }
827 
828 
829     /**
830     代入演算子です。
831     このオブジェクトに&(D null)を代入すると、$(D release)を呼び出したことと等価になります。
832     */
833     void opAssign(typeof(null))
834     {
835         release();
836     }
837 
838 
839     /// array, range primitives
840     ref inout(E) front() inout pure nothrow @safe @nogc @property
841     {
842         return _impl._array[_s];
843     }
844 
845 
846     /// ditto
847     ref inout(E) back() inout pure nothrow @safe @nogc @property
848     {
849         return _impl._array[_e-1];
850     }
851 
852 
853     /// ditto
854     bool empty() const pure nothrow @safe @nogc @property
855     {
856         return !_impl.isInitialized || _s == _e;
857     }
858 
859 
860     /// ditto
861     void popFront()
862     {
863         ++_s;
864 
865         if(this.empty)
866             this.clear();
867     }
868 
869 
870     /// ditto
871     void popBack()
872     {
873         --_e;
874 
875         if(this.empty)
876             this.clear();
877     }
878 
879 
880     /// ditto
881     auto save() @property
882     {
883         return this;
884     }
885 
886 
887     /// ditto
888     ref inout(E) opIndex(size_t i) inout pure nothrow @safe @nogc
889     in{
890         assert(i < this.length);
891     }
892     body{
893         return _impl._array[_s + i];
894     }
895 
896 
897     /// ditto
898     auto opSlice()
899     {
900         return this;
901     }
902 
903 
904     /// ditto
905     size_t length() const pure nothrow @safe @nogc @property
906     {
907         return _e - _s;
908     }
909 
910 
911     /// ditto
912     alias opDollar = length;
913 
914 
915     /// ditto
916     void length(size_t n) @property
917     {
918         reserve(n);
919         _e = _s + n;
920     }
921 
922 
923     /// ditto
924     RefCountedArray!E dup() @property
925     {
926         auto dst = typeof(return)(this.length);
927         dst._impl._array[0 .. this.length] = this._impl._array[_s .. _e];
928         return dst;
929     }
930 
931 
932   static if(is(const(E) : E))
933   {
934     /// ditto
935     RefCountedArray!E dup() const @property
936     {
937         auto dst = typeof(return)(this.length);
938         dst._impl._array[0 .. this.length] = this._impl._array[_s .. _e];
939         return dst;
940     }
941   }
942 
943 
944     /// ditto
945     inout(E)[] view() inout pure nothrow @safe @nogc @property
946     {
947         return _impl._array[_s .. _e];
948     }
949 
950 
951     /// ditto
952     auto opSlice(size_t i, size_t j)
953     in{
954         immutable len = this.length;
955         assert(i <= len);
956         assert(j <= len);
957         assert(i <= j);
958     }
959     body{
960         auto dst = this;
961         dst._s += i;
962         dst._e = dst._s + (j - i);
963         return dst;
964     }
965 
966 
967     /// ditto
968     void opOpAssign(string op : "~")(E v)
969     {
970         this.length = this.length + 1;
971         this.back = v;
972     }
973 
974 
975     /// ditto
976     typeof(this) opBinary(string op : "~")(E v)
977     {
978         if(_impl.refCount == 1 && this.capacity != this.length){
979             auto dst = this;
980             dst._e += 1;
981             dst.back = v;
982             return dst;
983         }
984         else{
985             auto dst = this;
986             dst ~= v;
987             return dst;
988         }
989     }
990 
991 
992     /// ditto
993     typeof(this) opBinaryRight(string op : "~")(E v)
994     {
995         if(_impl.refCount == 1 && _s >= 1){
996             auto dst = this;
997             dst._s -= 1;
998             dst.front = v;
999             return dst;
1000         }
1001         else{
1002             typeof(this) dst;
1003             dst.reserve(1 + this.length);
1004             dst ~= v;
1005             dst ~= this.view;
1006             return dst;
1007         }
1008     }
1009 
1010 
1011     /// ditto
1012     void opOpAssign(string op : "~")(E[] arr)
1013     {
1014         immutable oldLen = this.length;
1015         this.length = oldLen + arr.length;
1016         this._impl._array[oldLen .. this.length] = arr[0 .. $];
1017     }
1018 
1019 
1020     /// ditto
1021     typeof(this) opBinary(string op : "~")(E[] arr)
1022     {
1023         immutable len = arr.length;
1024         if(_impl.refCount <= 1 && this.capacity >= this.length + len){
1025             auto dst = this;
1026             dst._e += len;
1027             dst._impl._array[this._e .. dst._e] = arr[0 .. $];
1028             return dst;
1029         }
1030         else{
1031             auto dst = this;
1032             dst ~= arr;
1033             return dst;
1034         }
1035     }
1036 
1037 
1038     /// ditto
1039     typeof(this) opBinaryRight(string op : "~")(E[] arr)
1040     {
1041         immutable len = arr.length;
1042         if(_impl.refCount == 1 && _s >= len){
1043             auto dst = this;
1044             dst._s -= len;
1045             dst._impl._array[dst._s .. this._s] = arr[0 .. $];
1046             return dst;
1047         }
1048         else{
1049             typeof(this) dst;
1050             dst.reserve(len + this.length);
1051             dst ~= arr;
1052             dst ~= this.view;
1053             return dst;
1054         }
1055     }
1056 
1057 
1058     /// ditto
1059     void opOpAssign(string op : "~")(typeof(this) src)
1060     {
1061         this ~= src.view;
1062     }
1063 
1064 
1065     /// ditto
1066     typeof(this) opBinary(string op : "~")(typeof(this) src)
1067     {
1068         return this ~ src.view;
1069     }
1070 
1071 
1072     /// ditto
1073     void opOpAssign(string op : "~", R)(R range)
1074     if(isInputRange!R && is(ElementType!R : E) && !isInfinite!R)
1075     {
1076       static if(hasLength!R)
1077       {
1078         immutable oldLen = this.length,
1079                   rangeLen = range.length;
1080         this.length = oldLen + rangeLen;
1081 
1082         foreach(i; 0 .. rangeLen){
1083             assert(!range.empty);
1084             _impl._array[_s + oldLen + i] = range.front;
1085             range.popFront();
1086         }
1087       }
1088       else
1089       {
1090         if(_impl.isInitialized)
1091             this = this.dup;
1092         else
1093             this = typeof(this)(0);
1094 
1095         assert(this._impl.refCount == 1);
1096         assert(this._s == 0);
1097 
1098         while(!range.empty){
1099             immutable remN = this._impl._array.length - _e;
1100 
1101             size_t cnt;
1102             foreach(i; 0 .. remN){
1103                 if(range.empty)
1104                     break;
1105 
1106                 this._impl._array[_e + i] = range.front;
1107                 ++cnt;
1108                 range.popFront();
1109             }
1110             _e += cnt;
1111 
1112             if(cnt == remN && !range.empty)
1113                 reserve(_e + 1);
1114         }
1115       }
1116     }
1117 
1118 
1119     /// ditto
1120     typeof(this) opBinary(string op : "~", R)(R range)
1121     if(isInputRange!R && is(ElementType!R : E) && !isInfinite!R)
1122     {
1123       static if(hasLength!R)
1124       {
1125         immutable len = range.length;
1126         if(_impl.refCount <= 1 && this.capacity >= this.length + len){
1127             auto dst = this;
1128             dst._e += len;
1129             foreach(i; 0 .. len){
1130                 dst._impl._array[this._e + i] = range.front;
1131                 range.popFront();
1132             }
1133             return dst;
1134         }
1135       }
1136       
1137         auto dst = this;
1138         dst ~= range;
1139         return this ~ dst;
1140     }
1141 
1142 
1143     /// ditto
1144     typeof(this) opBinaryRight(string op : "~", R)(R range)
1145     if(isInputRange!R && is(ElementType!R : E) && !isInfinite!R && !is(typeof(range.opBinary!"~"(this))))
1146     {
1147       static if(hasLength!R)
1148       {
1149         immutable len = range.length;
1150         if(_impl.refCount <= 1 && _s >= len){
1151             auto dst = this;
1152             dst._s -= len;
1153             foreach(i; 0 .. len){
1154                 dst._impl._array[dst._s + i] = range.front;
1155                 range.popFront();
1156             }
1157             return dst;
1158         }
1159 
1160         typeof(this) dst;
1161         dst.reserve(this.length + len);
1162         dst ~= range;
1163         dst ~= this.view;
1164         return dst;
1165       }
1166       else
1167       {
1168         typeof(this) dst;
1169         dst ~= range;
1170         return this ~ dst;
1171       }
1172     }
1173 
1174 
1175     /// ditto
1176     int opCmp(R)(auto ref R r)
1177     if(isForwardRange!R && is(typeof(r.front < this.front)))
1178     {
1179         return std.algorithm.cmp(this.view, r.save);
1180     }
1181 
1182 
1183     /// ditto
1184     bool opEquals(R)(auto ref R r)
1185     if(isForwardRange!R && is(typeof(r.front == this.front)))
1186     {
1187         return std.algorithm.equal(this.view, r.save);
1188     }
1189 
1190 
1191   private:
1192     Impl!E _impl;
1193     size_t _s, _e;
1194 }
1195 
1196 
1197 /*nothrow @safe @nogc*/ unittest{
1198     auto arr1 = RefCountedArray!int(0);
1199     static assert(isInputRange!(typeof(arr1)));
1200     static assert(isForwardRange!(typeof(arr1)));
1201     static assert(isRandomAccessRange!(typeof(arr1)));
1202     static assert(hasLength!(typeof(arr1)));
1203     static assert(hasSlicing!(typeof(arr1)));
1204 
1205     assert(arr1.length == 0);
1206     assert(equal(arr1, cast(int[])[]));
1207     assert(!arr1.isNull);
1208 
1209     arr1 ~= 1;
1210     assert(arr1.length == 1);
1211     assert(equal(arr1, only(1)));
1212     assert(!arr1.isNull);
1213 
1214     arr1 ~= only(2, 3);
1215     assert(arr1.length == 3);
1216     assert(equal(arr1, only(1, 2, 3)));
1217     assert(!arr1.isNull);
1218 
1219     arr1 ~= arr1;
1220     assert(arr1.length == 6);
1221     assert(equal(arr1, only(1, 2, 3, 1, 2, 3)));
1222     assert(!arr1.isNull);
1223 
1224     arr1 = arr1[2 .. $-1];
1225     assert(arr1.length == 3);
1226     assert(equal(arr1, only(3, 1, 2)));
1227     assert(!arr1.isNull);
1228 
1229     arr1 = arr1.dup;
1230     assert(arr1.length == 3);
1231     assert(equal(arr1, only(3, 1, 2)));
1232     assert(!arr1.isNull);
1233 
1234     arr1 = null;
1235     assert(arr1.isNull);
1236 
1237     arr1 ~= only(1, 2, 3, 4);
1238     assert(arr1.length == 4);
1239     assert(equal(arr1, only(1, 2, 3, 4)));
1240     assert(!arr1.isNull);
1241 
1242     assert(equal(arr1, arr1.retro.retro));
1243 
1244     {
1245         auto arr2 = arr1.retro;
1246         foreach_reverse(e; arr1){
1247             assert(e == arr2.front);
1248             arr2.popFront();
1249         }
1250     }
1251 
1252 
1253     static assert(isForwardRange!(typeof(only(1, 2, 3))));
1254 
1255 
1256     arr1.release();
1257     arr1 ~= only(1, 2, 3);
1258     assert(arr1 < only(2));
1259     assert(arr1 < only(1, 2, 3, 4));
1260     assert(arr1 < only(1, 2, 4));
1261 
1262     assert(arr1 <= arr1);
1263 
1264     assert(arr1 >= arr1);
1265     assert(arr1 == arr1);
1266 
1267     assert(arr1 > only(1));
1268     assert(arr1 > only(1, 2));
1269     assert(arr1 > only(1, 2, 2));
1270     assert(arr1 > only(1, 2, 2, 4));
1271 
1272     assert(arr1 == only(1, 2, 3));
1273     assert(arr1 != only(1, 2, 3, 4));
1274 
1275 
1276     // length, capacity, reserve test
1277     assert(arr1.length == 3);
1278     assert(arr1._impl.refCount == 1);
1279     assert(arr1.capacity == 4);
1280     foreach(i; 0 .. arr1.capacity - arr1.length)
1281         arr1 ~= i;
1282 
1283     assert(arr1.length == 4);
1284     assert(arr1.capacity - arr1.length == 0);
1285 
1286     foreach(i; 0 .. 3)
1287         arr1.popFront();
1288 
1289     assert(arr1.length == 1);
1290     assert(arr1.capacity - arr1.length == 0);
1291 
1292     arr1.reserve(arr1.length + 1);  //  all elements moved to front.
1293     assert(arr1._s == 0);
1294     assert(arr1._e == arr1.length);
1295     assert(arr1.capacity - arr1.length == 3);
1296 }
1297 
1298 
1299 unittest{
1300     import std.typecons;
1301 
1302     auto arr = RefCountedArray!(RefCountedNoGC!int)(0);
1303     assert(arr.length == 0);
1304 
1305     arr ~= RefCountedNoGC!int(1);
1306     assert(arr.length == 1);
1307     assert(arr.front == 1);
1308     assert(arr.front.refCountedStore.refCount == 1);
1309 
1310     auto e = arr.front;
1311     assert(arr.front.refCountedStore.refCount == 2);
1312     assert(e.refCountedStore.refCount == 2);
1313     arr.popFront();
1314     arr.release();
1315     assert(e.refCountedStore.refCount == 1);
1316 
1317     arr ~= RefCountedNoGC!int(1);
1318     e = arr.front;
1319     assert(arr.front.refCountedStore.refCount == 2);
1320     assert(e.refCountedStore.refCount == 2);
1321 
1322     arr[0] = RefCountedNoGC!int(2);
1323     assert(arr.front.refCountedStore.refCount == 1);
1324     assert(e.refCountedStore.refCount == 1);
1325 
1326     auto arr2 = arr.dup;
1327     assert(arr.front.refCountedStore.refCount == 2);
1328     assert(e.refCountedStore.refCount == 1);
1329 }
1330 
1331 
1332 /+
1333 unittest{
1334     static void func(T)()
1335     {
1336         T a;
1337 
1338         a ~= 1;
1339         foreach(i; 0 .. 15)
1340             a ~= a;
1341 
1342         T b;
1343         foreach(e; a[0 .. 1024 * 32])
1344             b ~= e;
1345     }
1346 
1347     static void funcAppender()
1348     {
1349         import std.array;
1350         auto b = appender!(int[])();
1351         foreach(e; recurrence!"a[n-1]+a[n-2]"(1, 1).take(32 * 1024))
1352             b ~= e;
1353     }
1354 
1355 
1356     import std.datetime;
1357     import std.container;
1358     auto ts = benchmark!(func!(int[]),
1359                          func!(RefCountedArray!int),
1360                          func!(Array!int),
1361                          funcAppender)(100);
1362 
1363     writeln(ts);
1364 
1365 
1366     RefCountedArray!int b;
1367     foreach(e; recurrence!"a[n-1]+a[n-2]"(1, 1).take(1024))
1368             b ~= e;
1369 }+/
1370 
1371 
1372 /**
1373 Cヒープ上に配列を作成します。
1374 この配列は、必ずオブジェクト一つに対してユニークな配列を割り当てます。
1375 つまり、ほとんどの場面で配列の確保とコピーが生じます。
1376 この方式は、C++のSTL std::vectorと同じです。
1377 */
1378 struct UniqueArray(E)
1379 {
1380     /**
1381     */
1382     this(size_t n) nothrow @safe @nogc
1383     {
1384         immutable allocLen = allocateSize(n);
1385 
1386         _array = newCHeapArray!E(allocLen);
1387         _s = 0;
1388         _e = n;
1389     }
1390 
1391 
1392     this(this)
1393     {
1394         if(_array.ptr !is null){
1395             immutable n = this.length;
1396 
1397             auto newarr = newCHeapArray!E(allocateSize(n));
1398             newarr[0 .. n] = _array[_s .. _e];
1399             _array = newarr;
1400             _s = 0;
1401             _e = n;
1402         }
1403     }
1404 
1405 
1406     ~this()
1407     {
1408         if(_array.ptr !is null){
1409             _array.destroyCHeapArray();
1410             _s = 0;
1411             _e = 0;
1412         }
1413     }
1414 
1415 
1416     /**
1417     */
1418     void release()
1419     {
1420         _array.destroyCHeapArray();
1421         _s = 0;
1422         _e = 0;
1423     }
1424 
1425 
1426     /**
1427     */
1428     void clear()
1429     {
1430       static if(is(E == struct) && !__traits(isPOD, E))
1431         foreach(ref e; _array[_s .. _e])
1432             e = E.init;
1433 
1434         _s = 0;
1435         _e = 0;
1436     }
1437 
1438 
1439     /**
1440     */
1441     size_t capacity() const pure nothrow @safe @nogc @property
1442     {
1443         return _array.length - _e;
1444     }
1445 
1446 
1447     /**
1448     */
1449     size_t reserve(size_t n)
1450     {
1451         if(n > this.length && _array.length < n + _s){
1452             if(_array.length < n)
1453                 _array.reallocCHeapArray(allocateSize!E(n));
1454 
1455             if(_s != 0){
1456                 foreach(i; 0 .. this.length)
1457                     _array[i] = _array[_s + i];
1458 
1459                 _e -= _s;
1460                 _s = 0;
1461             }
1462         }
1463     }
1464 
1465 
1466     bool isNull() const pure nothrow @safe @nogc @property
1467     {
1468         return _array is null;
1469     }
1470 
1471 
1472     void opAssign(typeof(null))
1473     {
1474         this.release();
1475     }
1476 
1477 
1478     /// array, range primitives
1479     ref inout(E) front() inout pure nothrow @safe @property @nogc
1480     {
1481         return _array[_s];
1482     }
1483 
1484 
1485     /// ditto
1486     ref inout(E) back() inout pure nothrow @safe @property @nogc
1487     {
1488         return _array[_e-1];
1489     }
1490 
1491 
1492     /// ditto
1493     ref inout(E) opIndex(size_t i) inout pure nothrow @safe @nogc
1494     {
1495         return _array[_s + i];
1496     }
1497 
1498 
1499     /// ditto
1500     bool empty() const pure nothrow @safe @nogc
1501     {
1502         return _array.ptr is null || _s == _e;
1503     }
1504 
1505 
1506     /// ditto
1507     void popFront()
1508     {
1509         _array[_s] = E.init;
1510         ++_s;
1511     }
1512 
1513 
1514     /// ditto
1515     void popBack()
1516     {
1517         _array[_e-1] = E.init;
1518         --_e;
1519     }
1520 
1521 
1522     /// ditto
1523     typeof(this) save() @property
1524     {
1525         return this;
1526     }
1527 
1528 
1529     /// ditto
1530     auto dup() const @property
1531     {
1532         return this;
1533     }
1534 
1535 
1536     /// ditto
1537     size_t length() const pure nothrow @safe @nogc @property
1538     {
1539         return _e - _s;
1540     }
1541 
1542 
1543     /// ditto
1544     alias opDollar = length;
1545 
1546 
1547     /// ditto
1548     void length(size_t n) @property
1549     {
1550         if(n < this.length){
1551             static if(is(E == struct) && !__traits(isPOD, E))
1552                 foreach(ref e; _array[_s + n .. _e])
1553                     e = E.init;
1554         }else
1555             reserve(n);
1556 
1557         _e = _s + n;
1558     }
1559 
1560 
1561     /// ditto
1562     inout(E)[] view() inout pure nothrow @safe @nogc @property
1563     {
1564         return _array[_s .. _e];
1565     }
1566 
1567 
1568     /// ditto
1569     void opOpAssign(string op : "~")(E v)
1570     {
1571         this.length = this.length + 1;
1572         this.back = v;
1573     }
1574 
1575 
1576     /// ditto
1577     void opOpAssign(string op : "~")(E[] arr)
1578     {
1579         immutable oldLen = this.length;
1580         this.length = oldLen + arr.length;
1581         this._array[oldLen .. this.length] = arr[0 .. $];
1582     }
1583 
1584 
1585     /// ditto
1586     void opOpAssign(string op : "~")(typeof(this) src)
1587     {
1588         opOpAssign!"~"(src._array[src._s .. src._e]);
1589     }
1590 
1591 
1592     /// ditto
1593     void opOpAssign(string op : "~", R)(R range)
1594     if(isInputRange!R && is(ElementType!R : E) && !is(R : U[], U) && !isInfinite!R)
1595     {
1596       static if(hasLength!R)
1597       {
1598         immutable oldLen = this.length,
1599                   rangeLen = range.length;
1600         this.length = oldLen + rangeLen;
1601 
1602         foreach(i; 0 .. rangeLen){
1603             assert(!range.empty);
1604             _array[_s + oldLen + i] = range.front;
1605             range.popFront();
1606         }
1607       }
1608       else
1609       {
1610         this = this.dup;
1611 
1612         while(!range.empty){
1613             immutable remN = this._impl._array.length - _e;
1614 
1615             size_t cnt;
1616             foreach(i; 0 .. remN){
1617                 if(range.empty)
1618                     break;
1619 
1620                 this._impl._array[_e + i] = range.front;
1621                 ++cnt;
1622                 range.popFront();
1623             }
1624             _e += cnt;
1625 
1626             if(cnt == remN && !range.empty)
1627                 reserve(_e + 1);
1628         }
1629       }
1630     }
1631 
1632 
1633     /// ditto
1634     int opCmp(R)(auto ref R r)
1635     if(isForwardRange!R && is(typeof(r.front < this.front)))
1636     {
1637         return std.algorithm.cmp(this.view, r.save);
1638     }
1639 
1640 
1641     /// ditto
1642     bool opEquals(R)(auto ref R r)
1643     if(isForwardRange!R && is(typeof(r.front == this.front)))
1644     {
1645         return std.algorithm.equal(this.view, r.save);
1646     }
1647 
1648 
1649   private:
1650     E[] _array;
1651     size_t _s, _e;
1652 }