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 ae.sys.data; 17 18 /// Join an array of Data to a single Data. 19 Data joinData(Data[] data) 20 { 21 if (data.length == 0) 22 return Data(); 23 else 24 if (data.length == 1) 25 return data[0]; 26 27 size_t size = 0; 28 foreach (ref d; data) 29 size += d.length; 30 Data result = Data(size); 31 size_t pos = 0; 32 foreach (ref d; data) 33 { 34 result.mcontents[pos..pos+d.length] = d.contents[]; 35 pos += d.length; 36 } 37 return result; 38 } 39 40 /// Join an array of Data to a memory block on the managed heap. 41 @property 42 void[] joinToHeap(Data[] data) 43 { 44 size_t size = 0; 45 foreach (ref d; data) 46 size += d.length; 47 auto result = new void[size]; 48 size_t pos = 0; 49 foreach (ref d; data) 50 { 51 result[pos..pos+d.length] = d.contents[]; 52 pos += d.length; 53 } 54 return result; 55 } 56 57 /// Remove and return the specified number of bytes from the given `Data[]`. 58 Data[] popFront(ref Data[] data, size_t amount) 59 { 60 auto result = data.bytes[0..amount]; 61 data = data.bytes[amount..data.bytes.length]; 62 return result; 63 } 64 65 /// Return a type that's indexable to access individual bytes, 66 /// and sliceable to get an array of `Data` over the specified 67 /// byte range. No actual `Data` concatenation is done. 68 @property 69 DataSetBytes bytes(Data[] data) 70 { 71 return DataSetBytes(data); 72 } 73 74 /// ditto 75 struct DataSetBytes 76 { 77 Data[] data; /// Underlying `Data[]`. 78 79 ubyte opIndex(size_t offset) 80 { 81 size_t index = 0; 82 while (index < data.length && data[index].length <= offset) 83 { 84 offset -= data[index].length; 85 index++; 86 } 87 return (cast(ubyte[])data[index].contents)[offset]; 88 } /// 89 90 Data[] opSlice() 91 { 92 return data; 93 } /// 94 95 Data[] opSlice(size_t start, size_t end) 96 { 97 Data[] range = data; 98 while (range.length && range[0].length <= start) 99 { 100 start -= range[0].length; 101 end -= range[0].length; 102 range = range[1..$]; 103 } 104 if (range.length==0) 105 { 106 assert(start==0, "Range error"); 107 return null; 108 } 109 110 size_t endIndex = 0; 111 while (endIndex < range.length && range[endIndex].length < end) 112 { 113 end -= range[endIndex].length; 114 endIndex++; 115 } 116 range = range[0..endIndex+1]; 117 range = range.dup; 118 range[$-1] = range[$-1][0..end]; 119 range[0 ] = range[0 ][start..range[0].length]; 120 return range; 121 } /// 122 123 @property 124 size_t length() 125 { 126 size_t result = 0; 127 foreach (ref d; data) 128 result += d.length; 129 return result; 130 } /// 131 132 size_t opDollar(size_t pos)() 133 { 134 static assert(pos == 0); 135 return length; 136 } /// 137 } 138 139 unittest 140 { 141 Data[] ds; 142 string s; 143 144 ds = [ 145 Data("aaaaa"), 146 ]; 147 s = cast(string)(ds.joinToHeap); 148 assert(s == "aaaaa"); 149 s = cast(string)(ds.bytes[].joinToHeap); 150 assert(s == "aaaaa"); 151 s = cast(string)(ds.bytes[1..4].joinToHeap); 152 assert(s == "aaa"); 153 154 ds = [ 155 Data("aaaaa"), 156 Data("bbbbb"), 157 Data("ccccc"), 158 ]; 159 assert(ds.bytes[ 4]=='a'); 160 assert(ds.bytes[ 5]=='b'); 161 assert(ds.bytes[ 9]=='b'); 162 assert(ds.bytes[10]=='c'); 163 s = cast(string)(ds.bytes[ 3..12].joinToHeap); 164 assert(s == "aabbbbbcc"); 165 s = cast(string)(ds.joinToHeap); 166 assert(s == "aaaaabbbbbccccc"); 167 s = cast(string)(ds.bytes[ 0.. 6].joinToHeap); 168 assert(s == "aaaaab"); 169 s = cast(string)(ds.bytes[ 9..15].joinToHeap); 170 assert(s == "bccccc"); 171 s = cast(string)(ds.bytes[ 0.. 0].joinToHeap); 172 assert(s == ""); 173 s = cast(string)(ds.bytes[15..15].joinToHeap); 174 assert(s == ""); 175 }