1 module async.container.bytebuffer; 2 3 import std.container.dlist; 4 import std.conv; 5 6 struct ByteBuffer 7 { 8 @property bool empty() 9 { 10 return (_size == 0); 11 } 12 13 @property size_t length() 14 { 15 return _size; 16 } 17 18 ref typeof(this) opBinary(string op, Stuff)(auto ref Stuff rhs) 19 if ((is(Stuff: const ubyte[])) && op == "~") 20 { 21 if (rhs is null) 22 { 23 return this; 24 } 25 26 _queue.insertBack(cast(ubyte[])rhs); 27 _size += rhs.length; 28 29 return this; 30 } 31 32 void opOpAssign(string op, Stuff)(auto ref Stuff rhs) 33 if ((is(Stuff: const ubyte[])) && op == "~") 34 { 35 if (rhs is null) 36 { 37 return; 38 } 39 40 _queue.insertBack(cast(ubyte[])rhs); 41 _size += rhs.length; 42 } 43 44 ubyte[] opSlice(in size_t low, in size_t high) @trusted 45 in 46 { 47 assert ((low <= high) && (high <= _size), "ByteBuffer.opSlice: Invalid arguments low, high"); 48 } 49 body 50 { 51 ubyte[] ret; 52 53 if (low == high) 54 { 55 return ret; 56 } 57 58 size_t count = 0, lack = high - low; 59 foreach (a; _queue) 60 { 61 count += a.length; 62 63 if (count < low) 64 { 65 continue; 66 } 67 68 size_t start = low + ret.length - (count - a.length); 69 ret ~= a[start .. ($ - start) >= lack ? start + lack : $]; 70 lack = high - low - ret.length; 71 72 if (lack == 0) 73 { 74 break; 75 } 76 } 77 78 return ret; 79 } 80 81 size_t opDollar() nothrow const 82 { 83 return _size; 84 } 85 86 @property ref inout(ubyte[]) front() inout 87 { 88 assert (!_queue.empty, "ByteBuffer.front: Queue is empty"); 89 90 return _queue.front; 91 } 92 93 void popFront() 94 { 95 assert (!_queue.empty, "ByteBuffer.popFront: Queue is empty"); 96 97 _size -= _queue.front.length; 98 _queue.removeFront(); 99 } 100 101 void popFront(size_t size) 102 { 103 assert (size >= 0 && size <= _size, "ByteBuffer.popFront: Invalid arguments size"); 104 105 if (size == 0) 106 { 107 return; 108 } 109 110 if (size == _size) 111 { 112 _queue.clear(); 113 _size = 0; 114 115 return; 116 } 117 118 size_t removed = 0, lack = size; 119 120 size_t line = 0, count = 0, currline_len = 0; 121 foreach (a; _queue) 122 { 123 line++; 124 currline_len = a.length; 125 count += currline_len; 126 127 if (count > size) 128 { 129 break; 130 } 131 } 132 133 if (line > 1) 134 { 135 removed = count - currline_len; 136 lack = size - removed; 137 _queue.removeFront(line - 1); 138 } 139 140 if (lack > 0) 141 { 142 _queue.front = _queue.front[lack .. $]; 143 } 144 145 _size -= size; 146 } 147 148 void clear() 149 { 150 _queue.clear(); 151 _size = 0; 152 } 153 154 string toString() 155 { 156 return this[0 .. $].to!string(); 157 } 158 159 auto opCast(T)() 160 { 161 static if (isSomeString!T) 162 { 163 return toString(); 164 } 165 else static if (is(T: const ubyte[])) 166 { 167 return this[0 .. $]; 168 } 169 else 170 { 171 static assert(0, "ByteBuffer.opCast: Not support type."); 172 } 173 } 174 175 private: 176 177 DList!(ubyte[]) _queue; 178 size_t _size; 179 }