1 module yu.container.cirularqueue; 2 3 import core.memory; 4 import std.experimental.allocator.common; 5 import std.experimental.allocator.gc_allocator; 6 import std.traits; 7 import yu.container.common; 8 9 /** 10 * 循环队列 11 Queue Struct Template. 12 Params: 13 T = the element type; 14 autoExten = if the Queue is full, will or not auto expand; 15 addToGC = if use other Allocator, will or not add to GC scan. 16 Allocator = which type Allocator will used 17 */ 18 19 @trusted struct CirularQueue(T, Allocator = GCAllocator, bool autoExten = false, bool addInGC = true) if(is(T == Unqual!T)) { 20 enum TSize = T.sizeof; 21 enum addToGC = addInGC && hasIndirections!T && !is(Unqual!Allocator == GCAllocator); 22 static if (hasIndirections!T) 23 alias InsertT = T; 24 else 25 alias InsertT = const T; 26 27 /** 28 Params: 29 size = the queue init size. 30 */ 31 this(uint size) { 32 assert(size > 3); 33 _size = size; 34 _data = cast(T[]) _alloc.allocate(TSize * size); 35 static if (addToGC) 36 GC.addRange(_data.ptr, len); 37 } 38 39 static if (!StaticAlloc!Allocator) { 40 this(uint size, Allocator alloc) { 41 this._alloc = alloc; 42 this(size); 43 } 44 } 45 ~this() { 46 if (_data.ptr) { 47 static if (addToGC) 48 GC.removeRange(_data.ptr); 49 _alloc.deallocate(_data); 50 } 51 } 52 53 pragma(inline, true) void clear() { 54 55 _data[] = T.init; 56 _front = _rear = 0; 57 } 58 59 pragma(inline, true) @property bool empty() const nothrow { 60 return (_rear == _front); 61 } 62 63 pragma(inline) @property bool full() const { 64 if ((_rear + 1) % _size == _front) 65 return true; //队满 66 else 67 return false; 68 } 69 70 pragma(inline, true) @property T front() { 71 assert(!empty()); 72 return _data[_front]; 73 } 74 75 pragma(inline, true) @property uint length() { 76 return (_rear - _front + _size) % _size; 77 } 78 79 pragma(inline, true) @property uint maxLength() nothrow { 80 static if (autoExten) { 81 return uint.max; 82 } else { 83 return _size - 1; 84 } 85 } 86 87 bool enQueue(InsertT x) { 88 if (full()) { //队满 89 static if (autoExten) 90 exten(); 91 else 92 return false; 93 } 94 _data[_rear] = x; 95 _rear = (_rear + 1) % _size; //队尾指针加 1 取模 96 return true; 97 } 98 99 pragma(inline, true) T deQueue(T v = T.init) nothrow { 100 assert(!empty()); 101 auto x = _data[_front]; 102 _data[_front] = v; 103 _front = (_front + 1) % _size; //队头指针加 1 取模 104 return x; 105 } 106 107 static if (autoExten) { 108 protected: 109 void exten() { 110 auto size = _size > 128 ? _size + ((_size / 3) * 2) : _size * 2; 111 auto len = TSize * size; 112 auto data = cast(T[]) _alloc.allocate(TSize * size); 113 static if (addToGC) 114 GC.addRange(data.ptr, len); 115 uint i = 0; 116 while (!empty) { 117 data[i] = deQueue(); 118 ++i; 119 } 120 _size = size; 121 _front = 0; 122 _rear = i; 123 static if (addToGC) 124 GC.removeRange(_data.ptr); 125 _alloc.deallocate(_data); 126 _data = data; 127 } 128 129 } 130 mixin AllocDefine!Allocator; 131 private: 132 @disable this(); 133 @disable this(this); 134 uint _front = 0; 135 uint _rear = 0; 136 T[] _data = null; 137 uint _size; 138 } 139 140 unittest { 141 import std.stdio; 142 143 auto myq = CirularQueue!(int)(5); 144 writeln("init is empty = ", myq.empty); 145 foreach (i; 0 .. 13) { 146 writeln("enQueue i = ", i, " en value = ", myq.enQueue(i)); 147 } 148 writeln("end is empty = ", myq.empty); 149 writeln("end is full = ", myq.full); 150 writeln("size = ", myq.length); 151 int i = 0; 152 while (!myq.empty) { 153 writeln("\n"); 154 writeln("\tstart while! i = ", i); 155 writeln("\tfront is = ", myq.front()); 156 writeln("\tdeQueue is = ", myq.deQueue()); 157 158 ++i; 159 } 160 writeln("size = ", myq.length); 161 int x = 2; 162 myq.enQueue(x); 163 writeln("front is = ", myq.front()); 164 writeln("size = ", myq.length); 165 x = 3; 166 myq.enQueue(x); 167 writeln("size = ", myq.length); 168 writeln("front is = ", myq.front()); 169 writeln("deQueue is = ", myq.deQueue()); 170 writeln("size = ", myq.length); 171 writeln("front is = ", myq.front()); 172 }