1 /* 2 * Kiss - A refined core library for D programming language. 3 * 4 * Copyright (C) 2015-2018 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: HuntLabs.cn 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module kiss.container.ByteBuffer; 13 14 import core.stdc.string; 15 import std.bitmanip; 16 import kiss.util.traits; 17 18 19 interface WriteBuffer 20 { 21 size_t write(in ubyte[] data); 22 23 size_t set(size_t pos, in ubyte[] data); 24 25 @property size_t length() const; 26 } 27 28 interface ReadBuffer 29 { 30 @property bool eof() const; 31 32 size_t read(size_t size, scope void delegate(in ubyte[]) cback); 33 34 void rest(size_t size = 0); 35 36 size_t readPos(); 37 38 @property size_t length() const; 39 } 40 41 interface Buffer : WriteBuffer, ReadBuffer 42 { 43 size_t readLine(scope void delegate(in ubyte[]) cback); 44 45 size_t readAll(scope void delegate(in ubyte[]) cback); 46 47 size_t readUtil(in ubyte[] data, scope void delegate(in ubyte[]) cback); 48 } 49 50 51 /** 52 */ 53 final class ByteBuffer(Alloc) : Buffer 54 { 55 import kiss.container.ByteBuffer; 56 import kiss.container.Vector; 57 import std.experimental.allocator.common; 58 59 alias BufferStore = Vector!(ubyte, Alloc); 60 61 static if (stateSize!(Alloc) != 0) 62 { 63 this(Alloc alloc) 64 { 65 _store = BufferStore(1024, alloc); 66 } 67 68 @property allocator() 69 { 70 return _store.allocator; 71 } 72 73 } 74 else 75 { 76 this() 77 { 78 _store = BufferStore(1024); 79 } 80 } 81 82 ~this() 83 { 84 destroy(_store); 85 } 86 87 pragma(inline, true) void reserve(size_t elements) 88 { 89 _store.reserve(elements); 90 } 91 92 pragma(inline, true) void clear() 93 { 94 _rsize = 0; 95 _store.clear(); 96 } 97 98 override @property bool eof() const 99 { 100 return (_rsize >= _store.length); 101 } 102 103 override size_t read(size_t size, scope void delegate(in ubyte[]) cback) 104 { 105 size_t len = _store.length - _rsize; 106 len = size < len ? size : len; 107 auto _data = _store.data(); 108 size = _rsize; 109 _rsize += len; 110 if (len > 0) 111 cback(_data[size .. _rsize]); 112 113 return len; 114 } 115 116 override size_t write(in ubyte[] dt) 117 { 118 size_t len = _store.length; 119 _store.insertBack(cast(ubyte[]) dt); 120 return _store.length - len; 121 } 122 123 override size_t set(size_t pos, in ubyte[] data) 124 { 125 import core.stdc.string : memcpy; 126 127 if (pos >= _store.length || data.length == 0) 128 return 0; 129 size_t len = _store.length - pos; 130 len = len > data.length ? data.length : len; 131 ubyte* ptr = cast(ubyte*)(_store.ptr + pos); 132 memcpy(ptr, data.ptr, len); 133 return len; 134 } 135 136 override void rest(size_t size = 0) 137 { 138 _rsize = size; 139 } 140 141 override size_t readPos() 142 { 143 return _rsize; 144 } 145 146 BufferStore allData() 147 { 148 return _store; 149 } 150 151 override @property size_t length() const 152 { 153 return _store.length; 154 } 155 156 override size_t readLine(scope void delegate(in ubyte[]) cback) 157 { 158 if (eof()) 159 return 0; 160 auto _data = _store.data(); 161 auto tdata = _data[_rsize .. $]; 162 size_t size = _rsize; 163 ptrdiff_t index = findCharByte(tdata, cast(ubyte) '\n'); 164 if (index < 0) 165 { 166 _rsize += tdata.length; 167 cback(tdata); 168 } 169 else 170 { 171 _rsize += (index + 1); 172 size += 1; 173 if (index > 0) 174 { 175 size_t ts = index - 1; 176 if (tdata[ts] == cast(ubyte) '\r') 177 { 178 index = ts; 179 } 180 } 181 cback(tdata[0 .. index]); 182 } 183 184 return _rsize - size; 185 } 186 187 override size_t readAll(scope void delegate(in ubyte[]) cback) 188 { 189 if (eof()) 190 return 0; 191 auto _data = _store.data(); 192 auto tdata = _data[_rsize .. $]; 193 _rsize = _store.length; 194 cback(tdata); 195 return tdata.length; 196 } 197 198 override size_t readUtil(in ubyte[] chs, scope void delegate(in ubyte[]) cback) 199 { 200 if (eof()) 201 return 0; 202 auto _data = _store.data(); 203 auto tdata = _data[_rsize .. $]; 204 size_t size = _rsize; 205 ptrdiff_t index = findCharBytes(tdata, chs); 206 if (index < 0) 207 { 208 _rsize += tdata.length; 209 cback(tdata); 210 } 211 else 212 { 213 _rsize += (index + chs.length); 214 size += chs.length; 215 cback(tdata[0 .. index]); 216 } 217 return _rsize - size; 218 } 219 220 private: 221 BufferStore _store; 222 size_t _rsize = 0; 223 } 224 225 226 227 ptrdiff_t findCharByte(T)(in T[] data, in T ch) if (isCharByte!(T)) { 228 if (data.length == 0) 229 return -1; 230 ptrdiff_t index = -1; 231 auto ptr = memchr(data.ptr, ch, data.length); 232 if (ptr !is null) { 233 index = cast(ptrdiff_t)((cast(T*) ptr) - data.ptr); 234 } 235 236 return index; 237 } 238 239 ptrdiff_t findCharBytes(T)(in T[] data, in T[] chs) if (isCharByte!(T)) { 240 if (data.length < chs.length || data.length == 0 || chs.length == 0) 241 return -1; 242 ptrdiff_t index = -1; 243 size_t rsize = 0; 244 while (rsize < data.length) { 245 auto tdata = data[rsize .. $]; 246 auto ptr = memchr(tdata.ptr, chs[0], tdata.length); 247 if (ptr is null) 248 break; 249 250 size_t fistindex = (cast(T*) ptr) - tdata.ptr; 251 if (tdata.length - fistindex < chs.length) 252 break; 253 254 size_t i = 1; 255 size_t j = fistindex + 1; 256 while (i < chs.length && j < tdata.length) { 257 if (chs[i] != tdata[j]) { 258 rsize += fistindex + 1; 259 goto next; 260 } 261 ++i; 262 ++j; 263 } 264 index = cast(ptrdiff_t)(rsize + fistindex); 265 break; 266 next: 267 continue; 268 } 269 return index; 270 } 271 272 template endianToNative(bool litte, T) { 273 static if (litte) 274 alias endianToNative = littleEndianToNative!(T, T.sizeof); 275 else 276 alias endianToNative = bigEndianToNative!(T, T.sizeof); 277 } 278 279 template nativeToEndian(bool litte, T) { 280 static if (litte) 281 alias nativeToEndian = nativeToLittleEndian!(T); 282 else 283 alias nativeToEndian = nativeToBigEndian!(T); 284 285 } 286 287 unittest { 288 string hello = "hell worlf\r\nnext"; 289 assert(findCharByte(hello, 'l') == 2); 290 assert(findCharBytes(hello, "worlf") == 5); 291 }