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 }