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 <vladimir@thecybershadow.net> 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 Data[] popFront(ref Data[] data, size_t amount) 58 { 59 auto result = data.bytes[0..amount]; 60 data = data.bytes[amount..data.bytes.length]; 61 return result; 62 } 63 64 /// Return a type that's indexable to access individual bytes, 65 /// and sliceable to get an array of Data over the specified 66 /// byte range. No actual Data concatenation is done. 67 @property 68 DataSetBytes bytes(Data[] data) 69 { 70 return DataSetBytes(data); 71 } 72 73 struct DataSetBytes 74 { 75 Data[] data; 76 77 ubyte opIndex(size_t offset) 78 { 79 size_t index = 0; 80 while (index < data.length && data[index].length <= offset) 81 { 82 offset -= data[index].length; 83 index++; 84 } 85 return (cast(ubyte[])data[index].contents)[offset]; 86 } 87 88 Data[] opSlice() 89 { 90 return data; 91 } 92 93 Data[] opSlice(size_t start, size_t end) 94 { 95 Data[] range = data; 96 while (range.length && range[0].length <= start) 97 { 98 start -= range[0].length; 99 end -= range[0].length; 100 range = range[1..$]; 101 } 102 if (range.length==0) 103 { 104 assert(start==0, "Range error"); 105 return null; 106 } 107 108 size_t endIndex = 0; 109 while (endIndex < range.length && range[endIndex].length < end) 110 { 111 end -= range[endIndex].length; 112 endIndex++; 113 } 114 range = range[0..endIndex+1]; 115 range = range.dup; 116 range[$-1] = range[$-1][0..end]; 117 range[0 ] = range[0 ][start..range[0].length]; 118 return range; 119 } 120 121 @property 122 size_t length() 123 { 124 size_t result = 0; 125 foreach (ref d; data) 126 result += d.length; 127 return result; 128 } 129 130 size_t opDollar(size_t pos)() 131 { 132 static assert(pos == 0); 133 return length; 134 } 135 } 136 137 unittest 138 { 139 Data[] ds; 140 string s; 141 142 ds = [ 143 Data("aaaaa"), 144 ]; 145 s = cast(string)(ds.joinToHeap); 146 assert(s == "aaaaa"); 147 s = cast(string)(ds.bytes[].joinToHeap); 148 assert(s == "aaaaa"); 149 s = cast(string)(ds.bytes[1..4].joinToHeap); 150 assert(s == "aaa"); 151 152 ds = [ 153 Data("aaaaa"), 154 Data("bbbbb"), 155 Data("ccccc"), 156 ]; 157 assert(ds.bytes[ 4]=='a'); 158 assert(ds.bytes[ 5]=='b'); 159 assert(ds.bytes[ 9]=='b'); 160 assert(ds.bytes[10]=='c'); 161 s = cast(string)(ds.bytes[ 3..12].joinToHeap); 162 assert(s == "aabbbbbcc"); 163 s = cast(string)(ds.joinToHeap); 164 assert(s == "aaaaabbbbbccccc"); 165 s = cast(string)(ds.bytes[ 0.. 6].joinToHeap); 166 assert(s == "aaaaab"); 167 s = cast(string)(ds.bytes[ 9..15].joinToHeap); 168 assert(s == "bccccc"); 169 s = cast(string)(ds.bytes[ 0.. 0].joinToHeap); 170 assert(s == ""); 171 s = cast(string)(ds.bytes[15..15].joinToHeap); 172 assert(s == ""); 173 }