Denque

Extremely fast and lightweight double-ended queue implementation with zero dependencies.

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/428422/943850/Denque.js

  1. /**
  2. * Copyright (c) 2018 Mike Diarmid (Salakar) <mike.diarmid@gmail.com>
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this library except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. 'use strict';
  18.  
  19. /**
  20. * Custom implementation of a double ended queue.
  21. */
  22. function Denque(array, options) {
  23. var options = options || {};
  24.  
  25. this._head = 0;
  26. this._tail = 0;
  27. this._capacity = options.capacity;
  28. this._capacityMask = 0x3;
  29. this._list = new Array(4);
  30. if (Array.isArray(array)) {
  31. this._fromArray(array);
  32. }
  33. }
  34.  
  35. /**
  36. * -------------
  37. * PUBLIC API
  38. * -------------
  39. */
  40.  
  41. /**
  42. * Returns the item at the specified index from the list.
  43. * 0 is the first element, 1 is the second, and so on...
  44. * Elements at negative values are that many from the end: -1 is one before the end
  45. * (the last element), -2 is two before the end (one before last), etc.
  46. * @param index
  47. * @returns {*}
  48. */
  49. Denque.prototype.peekAt = function peekAt(index) {
  50. var i = index;
  51. // expect a number or return undefined
  52. if ((i !== (i | 0))) {
  53. return void 0;
  54. }
  55. var len = this.size();
  56. if (i >= len || i < -len) return undefined;
  57. if (i < 0) i += len;
  58. i = (this._head + i) & this._capacityMask;
  59. return this._list[i];
  60. };
  61.  
  62. /**
  63. * Alias for peekAt()
  64. * @param i
  65. * @returns {*}
  66. */
  67. Denque.prototype.get = function get(i) {
  68. return this.peekAt(i);
  69. };
  70.  
  71. /**
  72. * Returns the first item in the list without removing it.
  73. * @returns {*}
  74. */
  75. Denque.prototype.peek = function peek() {
  76. if (this._head === this._tail) return undefined;
  77. return this._list[this._head];
  78. };
  79.  
  80. /**
  81. * Alias for peek()
  82. * @returns {*}
  83. */
  84. Denque.prototype.peekFront = function peekFront() {
  85. return this.peek();
  86. };
  87.  
  88. /**
  89. * Returns the item that is at the back of the queue without removing it.
  90. * Uses peekAt(-1)
  91. */
  92. Denque.prototype.peekBack = function peekBack() {
  93. return this.peekAt(-1);
  94. };
  95.  
  96. /**
  97. * Returns the current length of the queue
  98. * @return {Number}
  99. */
  100. Object.defineProperty(Denque.prototype, 'length', {
  101. get: function length() {
  102. return this.size();
  103. }
  104. });
  105.  
  106. /**
  107. * Return the number of items on the list, or 0 if empty.
  108. * @returns {number}
  109. */
  110. Denque.prototype.size = function size() {
  111. if (this._head === this._tail) return 0;
  112. if (this._head < this._tail) return this._tail - this._head;
  113. else return this._capacityMask + 1 - (this._head - this._tail);
  114. };
  115.  
  116. /**
  117. * Add an item at the beginning of the list.
  118. * @param item
  119. */
  120. Denque.prototype.unshift = function unshift(item) {
  121. if (item === undefined) return this.size();
  122. var len = this._list.length;
  123. this._head = (this._head - 1 + len) & this._capacityMask;
  124. this._list[this._head] = item;
  125. if (this._tail === this._head) this._growArray();
  126. if (this._capacity && this.size() > this._capacity) this.pop();
  127. if (this._head < this._tail) return this._tail - this._head;
  128. else return this._capacityMask + 1 - (this._head - this._tail);
  129. };
  130.  
  131. /**
  132. * Remove and return the first item on the list,
  133. * Returns undefined if the list is empty.
  134. * @returns {*}
  135. */
  136. Denque.prototype.shift = function shift() {
  137. var head = this._head;
  138. if (head === this._tail) return undefined;
  139. var item = this._list[head];
  140. this._list[head] = undefined;
  141. this._head = (head + 1) & this._capacityMask;
  142. if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray();
  143. return item;
  144. };
  145.  
  146. /**
  147. * Add an item to the bottom of the list.
  148. * @param item
  149. */
  150. Denque.prototype.push = function push(item) {
  151. if (item === undefined) return this.size();
  152. var tail = this._tail;
  153. this._list[tail] = item;
  154. this._tail = (tail + 1) & this._capacityMask;
  155. if (this._tail === this._head) {
  156. this._growArray();
  157. }
  158. if (this._capacity && this.size() > this._capacity) {
  159. this.shift();
  160. }
  161. if (this._head < this._tail) return this._tail - this._head;
  162. else return this._capacityMask + 1 - (this._head - this._tail);
  163. };
  164.  
  165. /**
  166. * Remove and return the last item on the list.
  167. * Returns undefined if the list is empty.
  168. * @returns {*}
  169. */
  170. Denque.prototype.pop = function pop() {
  171. var tail = this._tail;
  172. if (tail === this._head) return undefined;
  173. var len = this._list.length;
  174. this._tail = (tail - 1 + len) & this._capacityMask;
  175. var item = this._list[this._tail];
  176. this._list[this._tail] = undefined;
  177. if (this._head < 2 && tail > 10000 && tail <= len >>> 2) this._shrinkArray();
  178. return item;
  179. };
  180.  
  181. /**
  182. * Remove and return the item at the specified index from the list.
  183. * Returns undefined if the list is empty.
  184. * @param index
  185. * @returns {*}
  186. */
  187. Denque.prototype.removeOne = function removeOne(index) {
  188. var i = index;
  189. // expect a number or return undefined
  190. if ((i !== (i | 0))) {
  191. return void 0;
  192. }
  193. if (this._head === this._tail) return void 0;
  194. var size = this.size();
  195. var len = this._list.length;
  196. if (i >= size || i < -size) return void 0;
  197. if (i < 0) i += size;
  198. i = (this._head + i) & this._capacityMask;
  199. var item = this._list[i];
  200. var k;
  201. if (index < size / 2) {
  202. for (k = index; k > 0; k--) {
  203. this._list[i] = this._list[i = (i - 1 + len) & this._capacityMask];
  204. }
  205. this._list[i] = void 0;
  206. this._head = (this._head + 1 + len) & this._capacityMask;
  207. } else {
  208. for (k = size - 1 - index; k > 0; k--) {
  209. this._list[i] = this._list[i = ( i + 1 + len) & this._capacityMask];
  210. }
  211. this._list[i] = void 0;
  212. this._tail = (this._tail - 1 + len) & this._capacityMask;
  213. }
  214. return item;
  215. };
  216.  
  217. /**
  218. * Remove number of items from the specified index from the list.
  219. * Returns array of removed items.
  220. * Returns undefined if the list is empty.
  221. * @param index
  222. * @param count
  223. * @returns {array}
  224. */
  225. Denque.prototype.remove = function remove(index, count) {
  226. var i = index;
  227. var removed;
  228. var del_count = count;
  229. // expect a number or return undefined
  230. if ((i !== (i | 0))) {
  231. return void 0;
  232. }
  233. if (this._head === this._tail) return void 0;
  234. var size = this.size();
  235. var len = this._list.length;
  236. if (i >= size || i < -size || count < 1) return void 0;
  237. if (i < 0) i += size;
  238. if (count === 1 || !count) {
  239. removed = new Array(1);
  240. removed[0] = this.removeOne(i);
  241. return removed;
  242. }
  243. if (i === 0 && i + count >= size) {
  244. removed = this.toArray();
  245. this.clear();
  246. return removed;
  247. }
  248. if (i + count > size) count = size - i;
  249. var k;
  250. removed = new Array(count);
  251. for (k = 0; k < count; k++) {
  252. removed[k] = this._list[(this._head + i + k) & this._capacityMask];
  253. }
  254. i = (this._head + i) & this._capacityMask;
  255. if (index + count === size) {
  256. this._tail = (this._tail - count + len) & this._capacityMask;
  257. for (k = count; k > 0; k--) {
  258. this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
  259. }
  260. return removed;
  261. }
  262. if (index === 0) {
  263. this._head = (this._head + count + len) & this._capacityMask;
  264. for (k = count - 1; k > 0; k--) {
  265. this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
  266. }
  267. return removed;
  268. }
  269. if (i < size / 2) {
  270. this._head = (this._head + index + count + len) & this._capacityMask;
  271. for (k = index; k > 0; k--) {
  272. this.unshift(this._list[i = (i - 1 + len) & this._capacityMask]);
  273. }
  274. i = (this._head - 1 + len) & this._capacityMask;
  275. while (del_count > 0) {
  276. this._list[i = (i - 1 + len) & this._capacityMask] = void 0;
  277. del_count--;
  278. }
  279. if (index < 0) this._tail = i;
  280. } else {
  281. this._tail = i;
  282. i = (i + count + len) & this._capacityMask;
  283. for (k = size - (count + index); k > 0; k--) {
  284. this.push(this._list[i++]);
  285. }
  286. i = this._tail;
  287. while (del_count > 0) {
  288. this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
  289. del_count--;
  290. }
  291. }
  292. if (this._head < 2 && this._tail > 10000 && this._tail <= len >>> 2) this._shrinkArray();
  293. return removed;
  294. };
  295.  
  296. /**
  297. * Native splice implementation.
  298. * Remove number of items from the specified index from the list and/or add new elements.
  299. * Returns array of removed items or empty array if count == 0.
  300. * Returns undefined if the list is empty.
  301. *
  302. * @param index
  303. * @param count
  304. * @param {...*} [elements]
  305. * @returns {array}
  306. */
  307. Denque.prototype.splice = function splice(index, count) {
  308. var i = index;
  309. // expect a number or return undefined
  310. if ((i !== (i | 0))) {
  311. return void 0;
  312. }
  313. var size = this.size();
  314. if (i < 0) i += size;
  315. if (i > size) return void 0;
  316. if (arguments.length > 2) {
  317. var k;
  318. var temp;
  319. var removed;
  320. var arg_len = arguments.length;
  321. var len = this._list.length;
  322. var arguments_index = 2;
  323. if (!size || i < size / 2) {
  324. temp = new Array(i);
  325. for (k = 0; k < i; k++) {
  326. temp[k] = this._list[(this._head + k) & this._capacityMask];
  327. }
  328. if (count === 0) {
  329. removed = [];
  330. if (i > 0) {
  331. this._head = (this._head + i + len) & this._capacityMask;
  332. }
  333. } else {
  334. removed = this.remove(i, count);
  335. this._head = (this._head + i + len) & this._capacityMask;
  336. }
  337. while (arg_len > arguments_index) {
  338. this.unshift(arguments[--arg_len]);
  339. }
  340. for (k = i; k > 0; k--) {
  341. this.unshift(temp[k - 1]);
  342. }
  343. } else {
  344. temp = new Array(size - (i + count));
  345. var leng = temp.length;
  346. for (k = 0; k < leng; k++) {
  347. temp[k] = this._list[(this._head + i + count + k) & this._capacityMask];
  348. }
  349. if (count === 0) {
  350. removed = [];
  351. if (i != size) {
  352. this._tail = (this._head + i + len) & this._capacityMask;
  353. }
  354. } else {
  355. removed = this.remove(i, count);
  356. this._tail = (this._tail - leng + len) & this._capacityMask;
  357. }
  358. while (arguments_index < arg_len) {
  359. this.push(arguments[arguments_index++]);
  360. }
  361. for (k = 0; k < leng; k++) {
  362. this.push(temp[k]);
  363. }
  364. }
  365. return removed;
  366. } else {
  367. return this.remove(i, count);
  368. }
  369. };
  370.  
  371. /**
  372. * Soft clear - does not reset capacity.
  373. */
  374. Denque.prototype.clear = function clear() {
  375. this._head = 0;
  376. this._tail = 0;
  377. };
  378.  
  379. /**
  380. * Returns true or false whether the list is empty.
  381. * @returns {boolean}
  382. */
  383. Denque.prototype.isEmpty = function isEmpty() {
  384. return this._head === this._tail;
  385. };
  386.  
  387. /**
  388. * Returns an array of all queue items.
  389. * @returns {Array}
  390. */
  391. Denque.prototype.toArray = function toArray() {
  392. return this._copyArray(false);
  393. };
  394.  
  395. /**
  396. * -------------
  397. * INTERNALS
  398. * -------------
  399. */
  400.  
  401. /**
  402. * Fills the queue with items from an array
  403. * For use in the constructor
  404. * @param array
  405. * @private
  406. */
  407. Denque.prototype._fromArray = function _fromArray(array) {
  408. for (var i = 0; i < array.length; i++) this.push(array[i]);
  409. };
  410.  
  411. /**
  412. *
  413. * @param fullCopy
  414. * @returns {Array}
  415. * @private
  416. */
  417. Denque.prototype._copyArray = function _copyArray(fullCopy) {
  418. var newArray = [];
  419. var list = this._list;
  420. var len = list.length;
  421. var i;
  422. if (fullCopy || this._head > this._tail) {
  423. for (i = this._head; i < len; i++) newArray.push(list[i]);
  424. for (i = 0; i < this._tail; i++) newArray.push(list[i]);
  425. } else {
  426. for (i = this._head; i < this._tail; i++) newArray.push(list[i]);
  427. }
  428. return newArray;
  429. };
  430.  
  431. /**
  432. * Grows the internal list array.
  433. * @private
  434. */
  435. Denque.prototype._growArray = function _growArray() {
  436. if (this._head) {
  437. // copy existing data, head to end, then beginning to tail.
  438. this._list = this._copyArray(true);
  439. this._head = 0;
  440. }
  441.  
  442. // head is at 0 and array is now full, safe to extend
  443. this._tail = this._list.length;
  444.  
  445. this._list.length *= 2;
  446. this._capacityMask = (this._capacityMask << 1) | 1;
  447. };
  448.  
  449. /**
  450. * Shrinks the internal list array.
  451. * @private
  452. */
  453. Denque.prototype._shrinkArray = function _shrinkArray() {
  454. this._list.length >>>= 1;
  455. this._capacityMask >>>= 1;
  456. };
  457.  
  458. window.Denque = Denque;

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址