1 /** 2 * ae.sys.dataset 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <ae@cy.md> 12 */ 13 14 module ae.sys.dataset; 15 16 import std.algorithm.mutation : move; 17 import std.range.primitives : ElementType; 18 19 import ae.sys.data; 20 import ae.utils.vec; 21 22 /// Copy a `Data` array's contents to a specified buffer. 23 void[] copyTo(R)(auto ref R data, void[] buffer) 24 if (is(ElementType!R == Data)) 25 { 26 size_t pos = 0; 27 foreach (ref d; data) 28 { 29 buffer[pos .. pos + d.length] = d.contents[]; 30 pos += d.length; 31 } 32 assert(pos == buffer.length); 33 return buffer; 34 } 35 36 /// Join an array of Data to a single Data. 37 Data joinData(R)(auto ref R data) 38 if (is(ElementType!R == Data)) 39 { 40 if (data.length == 0) 41 return Data(); 42 else 43 if (data.length == 1) 44 return data[0]; 45 46 size_t size = 0; 47 foreach (ref d; data) 48 size += d.length; 49 Data result = Data(size); 50 data.copyTo(result.mcontents); 51 return result; 52 } 53 54 unittest 55 { 56 assert(cast(int[])([Data([1]), Data([2])].joinData().contents) == [1, 2]); 57 } 58 59 /// Join an array of Data to a memory block on the managed heap. 60 @property 61 void[] joinToHeap(R)(auto ref R data) 62 if (is(ElementType!R == Data)) 63 { 64 size_t size = 0; 65 foreach (ref d; data) 66 size += d.length; 67 auto result = new void[size]; 68 data.copyTo(result); 69 return result; 70 } 71 72 unittest 73 { 74 assert(cast(int[])([Data([1]), Data([2])].joinToHeap()) == [1, 2]); 75 } 76 77 78 /// A vector of `Data` with deterministic lifetime. 79 alias DataVec = Vec!Data; 80 81 /// Remove and return the specified number of bytes from the given `Data` array. 82 DataVec shift(ref DataVec data, size_t amount) 83 { 84 auto bytes = data.bytes; 85 auto result = bytes[0..amount]; 86 data = bytes[amount..bytes.length]; 87 return result; 88 } 89 90 /// Return a type that's indexable to access individual bytes, 91 /// and sliceable to get an array of `Data` over the specified 92 /// byte range. No actual `Data` concatenation is done. 93 @property DataSetBytes bytes(Data[] data) { return DataSetBytes(data); } 94 @property DataSetBytes bytes(ref DataVec data) { return DataSetBytes(data[]); } /// ditto 95 96 /// ditto 97 struct DataSetBytes 98 { 99 Data[] data; /// Underlying `Data[]`. 100 101 ubyte opIndex(size_t offset) 102 { 103 size_t index = 0; 104 while (index < data.length && data[index].length <= offset) 105 { 106 offset -= data[index].length; 107 index++; 108 } 109 return (cast(ubyte[])data[index].contents)[offset]; 110 } /// 111 112 DataVec opSlice() 113 { 114 return DataVec(data); 115 } /// 116 117 DataVec opSlice(size_t start, size_t end) 118 { 119 auto range = DataVec(data); 120 while (range.length && range[0].length <= start) 121 { 122 start -= range[0].length; 123 end -= range[0].length; 124 range.popFront(); 125 } 126 if (range.length==0) 127 { 128 assert(start==0, "Range error"); 129 return range; 130 } 131 132 size_t endIndex = 0; 133 while (endIndex < range.length && range[endIndex].length < end) 134 { 135 end -= range[endIndex].length; 136 endIndex++; 137 } 138 range.length = endIndex + 1; 139 range[$-1] = range[$-1][0..end]; 140 range[0 ] = range[0 ][start..range[0].length]; 141 return range; 142 } /// 143 144 @property 145 size_t length() 146 { 147 size_t result = 0; 148 foreach (ref d; data) 149 result += d.length; 150 return result; 151 } /// 152 153 size_t opDollar(size_t pos)() 154 { 155 static assert(pos == 0); 156 return length; 157 } /// 158 } 159 160 unittest 161 { 162 DataVec ds; 163 string s; 164 165 ds = DataVec( 166 Data("aaaaa"), 167 ); 168 s = cast(string)(ds.joinToHeap); 169 assert(s == "aaaaa"); 170 s = cast(string)(ds.bytes[].joinToHeap); 171 assert(s == "aaaaa"); 172 s = cast(string)(ds.bytes[1..4].joinToHeap); 173 assert(s == "aaa"); 174 175 ds = DataVec( 176 Data("aaaaa"), 177 Data("bbbbb"), 178 Data("ccccc"), 179 ); 180 auto dsb = ds.bytes; 181 assert(dsb.length == 15); 182 assert(dsb.length == 15); 183 assert(dsb[ 4]=='a'); 184 assert(dsb[ 5]=='b'); 185 assert(dsb[ 9]=='b'); 186 assert(dsb[10]=='c'); 187 s = cast(string)(dsb[ 3..12].joinToHeap); 188 assert(s == "aabbbbbcc"); 189 s = cast(string)(ds.joinToHeap); 190 assert(s == "aaaaabbbbbccccc", s); 191 s = cast(string)(dsb[ 0.. 6].joinToHeap); 192 assert(s == "aaaaab"); 193 s = cast(string)(dsb[ 9..15].joinToHeap); 194 assert(s == "bccccc"); 195 s = cast(string)(dsb[ 0.. 0].joinToHeap); 196 assert(s == ""); 197 s = cast(string)(dsb[15..15].joinToHeap); 198 assert(s == ""); 199 }