1 /*******************************************************************************
2 
3     Utility for manipulation of reusable mutable array buffers.
4 
5     Notes:
6     * Because of a DMD1 bug, declaring Buffer!(Buffer!(T)) is not possible and
7       will result in a compile-time error complaining about recursive template
8       instantiation.
9     * Buffers of void of any dimension greater than one are disallowed (i.e.
10       Buffer!(void) is allowed; Buffer!(void[]), Buffer!(void[][]), etc are
11       not). For > 1d arrays, you should use buffers of ubyte instead. The reason
12       for this limitation is that any array type can be implicitly cast to
13       void[], leading to internal ambiguities in the code of Buffer. (A fix for
14       this problem may possible, but would add a lot of complexity to the code.)
15 
16     Copyright:
17         Copyright (c) 2016 dunnhumby Germany GmbH.
18         All rights reserved.
19 
20     License:
21         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
22         Alternatively, this file may be distributed under the terms of the Tango
23         3-Clause BSD License (see LICENSE_BSD.txt for details).
24 
25 *******************************************************************************/
26 
27 module ocean.core.Buffer;
28 
29 
30 import ocean.meta.types.Qualifiers;
31 
32 import ocean.meta.traits.Basic;
33 import ocean.meta.types.Arrays;
34 
35 import ocean.core.buffer.Void;
36 import ocean.core.buffer.WithIndirections;
37 import ocean.core.buffer.NoIndirections;
38 
39 Buffer!(Unqual!(T)) createBuffer ( T ) ( T[] initial... )
40 {
41     return Buffer!(Unqual!(T))(initial.dup);
42 }
43 
44 struct Buffer ( T )
45 {
46     static assert (
47         !isBasicArrayType!(T) || !is(StripAllArrays!(T) == void),
48         "Buffer doesn't work as void[][] replacement, try use ubyte[][] instead"
49     );
50 
51     /***************************************************************************
52 
53         Disable postblit constructor in D2 to prevent copying
54 
55     ***************************************************************************/
56 
57     @disable this(this);
58     @disable void opAssign (Buffer!(T) other);
59 
60     /***************************************************************************
61 
62         Mixin appropriate API based on kind of element type requested
63 
64     ***************************************************************************/
65 
66     static if (is(T == void))
67     {
68         alias ubyte ElementType;
69         mixin VoidBufferImpl Impl;
70     }
71     else static if (is(typeof({ T x; const(T) y; x = y; })))
72     {
73         alias T ElementType;
74         mixin NoIndirectionsBufferImpl Impl;
75     }
76     else
77     {
78         alias T ElementType;
79         mixin WithIndirectionsBufferImpl Impl;
80     }
81 
82     /***************************************************************************
83 
84         Add opAssign from currently used implementation to main overload set
85         so that it won't get shadowed by opAssign automatically generated
86         from postblit.
87 
88     ***************************************************************************/
89 
90     alias Impl.opAssign opAssign;
91 
92     /***************************************************************************
93 
94         More readable alias for resetting buffer length to 0 while preserving
95         capacity.
96 
97     ***************************************************************************/
98 
99     void reset ( )
100     {
101         this.length = 0;
102     }
103 
104     /***************************************************************************
105 
106         Returns:
107             stored data length
108 
109     ***************************************************************************/
110 
111     size_t length ( ) const
112     {
113         return this.data.length;
114     }
115 
116     /***************************************************************************
117 
118         Resizes buffer and allows memory stomping
119 
120         Params:
121             new_length = length to resize to
122 
123     ***************************************************************************/
124 
125     void length ( size_t new_length )
126     {
127         assumeSafeAppend(this.data);
128         this.data.length = new_length;
129         assumeSafeAppend(this.data);
130     }
131 
132     /***************************************************************************
133 
134         Ensures buffer has enough capacity to hold specified length but does
135         not modify effective length.
136 
137         Params:
138             new_length = length to extend capacity to
139 
140     ***************************************************************************/
141 
142     void reserve ( size_t new_length )
143     {
144         assumeSafeAppend(this.data);
145         auto old_length = this.data.length;
146         this.data.length = new_length;
147         this.data.length = old_length;
148         assumeSafeAppend(this.data);
149     }
150 
151     /***************************************************************************
152 
153         Exposes owned data as an array slice
154 
155         Params:
156             begin = start index, inclusive
157             end = end index, exclusive
158 
159         Returns:
160             requested slice fo stored data
161 
162     ***************************************************************************/
163 
164     inout(T[]) opSlice ( size_t begin, size_t end ) inout
165     {
166         return this.data[begin .. end];
167     }
168 
169     /***************************************************************************
170 
171         Exposes owned data as an array slice
172 
173         Returns:
174             requested slice fo stored data
175 
176     ***************************************************************************/
177 
178     inout(T[]) opSlice ( ) inout
179     {
180         return this.data[];
181     }
182 }
183 
184 unittest
185 {
186     // test instantiation with various types
187 
188     {
189         Buffer!(void) buffer;
190     }
191 
192     {
193         Buffer!(char) buffer;
194     }
195 
196     {
197         static struct S
198         {
199         }
200 
201         Buffer!(S) buffer;
202     }
203 
204     {
205         Buffer!(istring) buffer1;
206         Buffer!(cstring) buffer2;
207         Buffer!(mstring) buffer3;
208     }
209 
210     {
211         static class C
212         {
213         }
214 
215         Buffer!(C) buffer;
216     }
217 }