deque.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /**
  2. * Copyright (c) 2013 Petka Antonov
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:</p>
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. "use strict";
  23. function Deque(capacity) {
  24. this._capacity = getCapacity(capacity);
  25. this._length = 0;
  26. this._front = 0;
  27. this._makeCapacity();
  28. if (isArray(capacity)) {
  29. var len = capacity.length;
  30. for (var i = 0; i < len; ++i) {
  31. this[i] = capacity[i];
  32. }
  33. this._length = len;
  34. }
  35. }
  36. Deque.prototype.toArray = function Deque$toArray() {
  37. var len = this._length;
  38. var ret = new Array(len);
  39. var front = this._front;
  40. var capacity = this._capacity;
  41. for (var j = 0; j < len; ++j) {
  42. ret[j] = this[(front + j) & (capacity - 1)];
  43. }
  44. return ret;
  45. };
  46. Deque.prototype.push = function Deque$push(item) {
  47. var argsLength = arguments.length;
  48. var length = this._length;
  49. if (argsLength > 1) {
  50. var capacity = this._capacity;
  51. if (length + argsLength > capacity) {
  52. for (var i = 0; i < argsLength; ++i) {
  53. this._checkCapacity(length + 1);
  54. var j = (this._front + length) & (this._capacity - 1);
  55. this[j] = arguments[i];
  56. length++;
  57. this._length = length;
  58. }
  59. return length;
  60. }
  61. else {
  62. var j = this._front;
  63. for (var i = 0; i < argsLength; ++i) {
  64. this[(j + length) & (capacity - 1)] = arguments[i];
  65. j++;
  66. }
  67. this._length = length + argsLength;
  68. return length + argsLength;
  69. }
  70. }
  71. if (argsLength === 0) return length;
  72. this._checkCapacity(length + 1);
  73. var i = (this._front + length) & (this._capacity - 1);
  74. this[i] = item;
  75. this._length = length + 1;
  76. return length + 1;
  77. };
  78. Deque.prototype.pop = function Deque$pop() {
  79. var length = this._length;
  80. if (length === 0) {
  81. return void 0;
  82. }
  83. var i = (this._front + length - 1) & (this._capacity - 1);
  84. var ret = this[i];
  85. this[i] = void 0;
  86. this._length = length - 1;
  87. return ret;
  88. };
  89. Deque.prototype.shift = function Deque$shift() {
  90. var length = this._length;
  91. if (length === 0) {
  92. return void 0;
  93. }
  94. var front = this._front;
  95. var ret = this[front];
  96. this[front] = void 0;
  97. this._front = (front + 1) & (this._capacity - 1);
  98. this._length = length - 1;
  99. return ret;
  100. };
  101. Deque.prototype.unshift = function Deque$unshift(item) {
  102. var length = this._length;
  103. var argsLength = arguments.length;
  104. if (argsLength > 1) {
  105. var capacity = this._capacity;
  106. if (length + argsLength > capacity) {
  107. for (var i = argsLength - 1; i >= 0; i--) {
  108. this._checkCapacity(length + 1);
  109. var capacity = this._capacity;
  110. var j = (((( this._front - 1 ) &
  111. ( capacity - 1) ) ^ capacity ) - capacity );
  112. this[j] = arguments[i];
  113. length++;
  114. this._length = length;
  115. this._front = j;
  116. }
  117. return length;
  118. }
  119. else {
  120. var front = this._front;
  121. for (var i = argsLength - 1; i >= 0; i--) {
  122. var j = (((( front - 1 ) &
  123. ( capacity - 1) ) ^ capacity ) - capacity );
  124. this[j] = arguments[i];
  125. front = j;
  126. }
  127. this._front = front;
  128. this._length = length + argsLength;
  129. return length + argsLength;
  130. }
  131. }
  132. if (argsLength === 0) return length;
  133. this._checkCapacity(length + 1);
  134. var capacity = this._capacity;
  135. var i = (((( this._front - 1 ) &
  136. ( capacity - 1) ) ^ capacity ) - capacity );
  137. this[i] = item;
  138. this._length = length + 1;
  139. this._front = i;
  140. return length + 1;
  141. };
  142. Deque.prototype.peekBack = function Deque$peekBack() {
  143. var length = this._length;
  144. if (length === 0) {
  145. return void 0;
  146. }
  147. var index = (this._front + length - 1) & (this._capacity - 1);
  148. return this[index];
  149. };
  150. Deque.prototype.peekFront = function Deque$peekFront() {
  151. if (this._length === 0) {
  152. return void 0;
  153. }
  154. return this[this._front];
  155. };
  156. Deque.prototype.get = function Deque$get(index) {
  157. var i = index;
  158. if ((i !== (i | 0))) {
  159. return void 0;
  160. }
  161. var len = this._length;
  162. if (i < 0) {
  163. i = i + len;
  164. }
  165. if (i < 0 || i >= len) {
  166. return void 0;
  167. }
  168. return this[(this._front + i) & (this._capacity - 1)];
  169. };
  170. Deque.prototype.isEmpty = function Deque$isEmpty() {
  171. return this._length === 0;
  172. };
  173. Deque.prototype.clear = function Deque$clear() {
  174. this._length = 0;
  175. this._front = 0;
  176. this._makeCapacity();
  177. };
  178. Deque.prototype.toString = function Deque$toString() {
  179. return this.toArray().toString();
  180. };
  181. Deque.prototype.valueOf = Deque.prototype.toString;
  182. Deque.prototype.removeFront = Deque.prototype.shift;
  183. Deque.prototype.removeBack = Deque.prototype.pop;
  184. Deque.prototype.insertFront = Deque.prototype.unshift;
  185. Deque.prototype.insertBack = Deque.prototype.push;
  186. Deque.prototype.enqueue = Deque.prototype.push;
  187. Deque.prototype.dequeue = Deque.prototype.shift;
  188. Deque.prototype.toJSON = Deque.prototype.toArray;
  189. Object.defineProperty(Deque.prototype, "length", {
  190. get: function() {
  191. return this._length;
  192. },
  193. set: function() {
  194. throw new RangeError("");
  195. }
  196. });
  197. Deque.prototype._makeCapacity = function Deque$_makeCapacity() {
  198. var len = this._capacity;
  199. for (var i = 0; i < len; ++i) {
  200. this[i] = void 0;
  201. }
  202. };
  203. Deque.prototype._checkCapacity = function Deque$_checkCapacity(size) {
  204. if (this._capacity < size) {
  205. this._resizeTo(getCapacity(this._capacity * 1.5 + 16));
  206. }
  207. };
  208. Deque.prototype._resizeTo = function Deque$_resizeTo(capacity) {
  209. var oldFront = this._front;
  210. var oldCapacity = this._capacity;
  211. var oldDeque = new Array(oldCapacity);
  212. var length = this._length;
  213. arrayCopy(this, 0, oldDeque, 0, oldCapacity);
  214. this._capacity = capacity;
  215. this._makeCapacity();
  216. this._front = 0;
  217. if (oldFront + length <= oldCapacity) {
  218. arrayCopy(oldDeque, oldFront, this, 0, length);
  219. } else { var lengthBeforeWrapping =
  220. length - ((oldFront + length) & (oldCapacity - 1));
  221. arrayCopy(oldDeque, oldFront, this, 0, lengthBeforeWrapping);
  222. arrayCopy(oldDeque, 0, this, lengthBeforeWrapping,
  223. length - lengthBeforeWrapping);
  224. }
  225. };
  226. var isArray = Array.isArray;
  227. function arrayCopy(src, srcIndex, dst, dstIndex, len) {
  228. for (var j = 0; j < len; ++j) {
  229. dst[j + dstIndex] = src[j + srcIndex];
  230. }
  231. }
  232. function pow2AtLeast(n) {
  233. n = n >>> 0;
  234. n = n - 1;
  235. n = n | (n >> 1);
  236. n = n | (n >> 2);
  237. n = n | (n >> 4);
  238. n = n | (n >> 8);
  239. n = n | (n >> 16);
  240. return n + 1;
  241. }
  242. function getCapacity(capacity) {
  243. if (typeof capacity !== "number") {
  244. if (isArray(capacity)) {
  245. capacity = capacity.length;
  246. }
  247. else {
  248. return 16;
  249. }
  250. }
  251. return pow2AtLeast(
  252. Math.min(
  253. Math.max(16, capacity), 1073741824)
  254. );
  255. }
  256. module.exports = Deque;