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