1 module cybuf; 2 3 import std.algorithm; 4 import std.range; 5 import std.stdio; 6 7 struct Cybuf(T){ 8 alias Handler = void delegate(T value); 9 private T[] buf; 10 private size_t place; 11 private size_t size; 12 private Handler handler; 13 14 @disable 15 public this(); 16 17 public this(size_t length, Handler handler = null){ 18 this.buf.length = length; 19 place = 0; 20 size = 0; 21 this.handler = handler; 22 } 23 24 public this(T[] buf, size_t place, size_t size){ 25 this.buf = buf; 26 this.place = place; 27 this.size = size; 28 } 29 30 @property 31 public T back(){ 32 return this[$-1]; 33 } 34 35 @property 36 public bool empty(){ 37 return (size == 0); 38 } 39 40 @property 41 public T front(){ 42 return this[0]; 43 } 44 45 @property 46 public size_t length(){ 47 return size; 48 } 49 50 public T opIndex(size_t index) 51 in{ 52 assert(index < size); 53 } 54 body{ 55 if(place+index >= buf.length){ 56 return buf[index - (buf.length - place)]; 57 } 58 else{ 59 return buf[place + index]; 60 } 61 } 62 63 public size_t opDollar(){ 64 return size; 65 } 66 67 public void popBack(){ 68 size--; 69 } 70 71 public void popFront(){ 72 place = (place+1 == buf.length) ? 0 : place+1; 73 size--; 74 } 75 76 public void put(T elem){ 77 if(size == buf.length && (handler !is null)){ 78 handler(this[0]); 79 } 80 81 if(place+size < buf.length){ 82 buf[place+size] = elem; 83 } 84 else{ 85 buf[size - (buf.length - place)] = elem; 86 } 87 88 if(size == buf.length){ 89 place = (place+1 == buf.length) ? 0 : place+1; 90 } 91 else{ 92 size++; 93 } 94 } 95 96 public void put(T[] elems){ 97 foreach(e; elems){ 98 this.put(e); 99 } 100 } 101 102 public T[] rawBuf(){ 103 return this.buf; 104 } 105 106 public void setHandler(Handler h){ 107 this.handler = h; 108 } 109 110 @property 111 public Cybuf!T save() const 112 { 113 return Cybuf!T(buf.dup, place, size); 114 } 115 } 116 117 //Static checks about the status of the range. 118 unittest { 119 static assert(isInputRange!(Cybuf!int)); 120 static assert(isOutputRange!(Cybuf!int, int)); 121 static assert(isForwardRange!(Cybuf!int)); 122 static assert(isBidirectionalRange!(Cybuf!int)); 123 static assert(isRandomAccessRange!(Cybuf!int)); 124 } 125 126 //Testing Input/Output 127 unittest { 128 auto cb = Cybuf!int(4); 129 130 cb.put([1,2,3]); 131 132 assert(equal(cb.rawBuf(),[1,2,3,0][])); 133 134 cb.put([4,5]); 135 136 assert(equal(cb.rawBuf(),[5,2,3,4][])); 137 } 138 139 //Testing save 140 unittest { 141 auto cb = Cybuf!string(4); 142 143 cb.put(["faa", "fbb", "fcc", "fdd"]); 144 145 auto cb_save = cb.save; 146 147 cb.put(["fee"]); 148 149 assert(!equal(cb.rawBuf(),cb_save.rawBuf())); 150 } 151 152 //Testing backward iterating 153 unittest { 154 auto cb = Cybuf!int(6); 155 156 cb.put([1,2,3,4,5,6,7,8]); 157 158 auto daplop = retro(cb); 159 160 int[] test; 161 162 foreach(i; daplop){ 163 test ~= i; 164 } 165 166 assert(equal(test, [8,7,6,5,4,3])); 167 } 168 169 //Testing index access 170 unittest { 171 auto cb = Cybuf!int(4); 172 173 cb.put([1,2,3,4,5,6]); 174 175 assert(cb[0] == 3); 176 assert(cb[$-1] == 6); 177 } 178 179 //Example of how to use a handler 180 //Disabled because it is not a real unittest 181 /* 182 unittest { 183 184 void printValue(int value){ 185 writefln("I received the value %d", value); 186 } 187 188 auto cb = Cybuf!int(4, &printValue); 189 190 cb.put([1,2,3,4]); 191 192 cb.put([5, 6]); 193 194 cb = Cybuf!int(4); 195 196 cb.setHandler(&printValue); 197 198 cb.put([3,4,5,6,7,8]); 199 } 200 */