1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15interface ArkPrivate { 16 Queue: number; 17 Load(key: number): Object; 18} 19interface errorUtil{ 20 checkRangeError(paramName: string, receivedValue: unknown, min?: number, max?: number, options?: string): void; 21 checkNewTargetIsNullError(className: string, isNull: boolean): void; 22 checkBindError(methodName: string, className: Function, self: unknown): void; 23 checkTypeError(paramName: string, type: string, receivedValue: unknown): void; 24} 25let flag: boolean = false; 26let fastQueue: Object = undefined; 27let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 28if (arkPritvate !== undefined) { 29 fastQueue = arkPritvate.Load(arkPritvate.Queue); 30} else { 31 flag = true; 32} 33declare function requireNapi(s: string): errorUtil; 34if (flag || fastQueue === undefined) { 35 const errorUtil = requireNapi('util.struct'); 36 class HandlerQueue<T> { 37 private isOutBounds(obj: Queue<T>, prop: string): void { 38 let index: number = Number.parseInt(prop); 39 if (Number.isInteger(index)) { 40 errorUtil.checkRangeError('index', index, 0, obj.length); 41 } 42 } 43 get(obj: Queue<T>, prop: string): T { 44 if (typeof prop === 'symbol') { 45 return obj[prop]; 46 } 47 this.isOutBounds(obj, prop); 48 return obj[prop]; 49 } 50 set(obj: Queue<T>, prop: any, value: T): boolean { 51 if (prop === 'front' || prop === 'capacity' || prop === 'rear') { 52 obj[prop] = value; 53 return true; 54 } 55 this.isOutBounds(obj, prop); 56 let index: number = Number(prop); 57 if (index >= 0 && index <= obj.length && Number.isInteger(index)) { 58 obj[index] = value; 59 return true; 60 } 61 return false; 62 } 63 ownKeys(obj: Queue<T>): Array<string> { 64 let keys: string[] = []; 65 for (let i: number = 0; i < obj.length; i++) { 66 keys.push(i.toString()); 67 } 68 return keys; 69 } 70 defineProperty(): boolean { 71 return true; 72 } 73 getOwnPropertyDescriptor(obj: Queue<T>, prop: string): Object { 74 this.isOutBounds(obj, prop); 75 let index: number = Number.parseInt(prop); 76 if (index >= 0 && index < obj.length && Number.isInteger(index)) { 77 return Object.getOwnPropertyDescriptor(obj, prop); 78 } 79 return Object; 80 } 81 setPrototypeOf(): T { 82 throw new Error(`Can't setPrototype on Queue Object`); 83 } 84 } 85 interface IterableIterator<T> { 86 next: () => { 87 value: T; 88 done: boolean; 89 }; 90 } 91 class Queue<T> { 92 private front: number; 93 private capacity: number; 94 private rear: number; 95 constructor() { 96 errorUtil.checkNewTargetIsNullError('Queue', !new.target); 97 this.front = 0; 98 this.capacity = 8; 99 this.rear = 0; 100 return new Proxy(this, new HandlerQueue()); 101 } 102 get length(): number { 103 return this.rear - this.front; 104 } 105 add(element: T): boolean { 106 errorUtil.checkBindError('add', Queue, this); 107 if (this.isFull()) { 108 this.increaseCapacity(); 109 } 110 this[this.rear] = element; 111 this.rear = (this.rear + 1) % (this.capacity + 1); 112 return true; 113 } 114 getFirst(): T { 115 errorUtil.checkBindError('getFirst', Queue, this); 116 if (this.isEmpty()) { 117 return undefined; 118 } 119 return this[this.front]; 120 } 121 pop(): T { 122 errorUtil.checkBindError('pop', Queue, this); 123 if (this.isEmpty()) { 124 return undefined; 125 } 126 let result: T = undefined; 127 result = this[this.front]; 128 this.front = (this.front + 1) % (this.capacity + 1); 129 return result; 130 } 131 forEach(callbackfn: (value: T, index?: number, queue?: Queue<T>) => void, 132 thisArg?: Object): void { 133 errorUtil.checkBindError('forEach', Queue, this); 134 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 135 let k: number = 0; 136 let i: number = this.front; 137 if (this.isEmpty()) { 138 return; 139 } else { 140 while (true) { 141 callbackfn.call(thisArg, this[i], k, this); 142 i = (i + 1) % this.capacity; 143 k++; 144 if (i === this.rear) { 145 break; 146 } 147 } 148 } 149 } 150 private isFull(): boolean { 151 return this.length === this.capacity; 152 } 153 private isEmpty(): boolean { 154 return this.length === 0; 155 } 156 [Symbol.iterator](): IterableIterator<T> { 157 errorUtil.checkBindError('Symbol.iterator', Queue, this); 158 let count: number = this.front; 159 return { 160 next: function (): { done: boolean, value: T } { 161 let done: boolean = false; 162 let value: T = undefined; 163 done = count === this.rear; 164 value = done ? undefined : this[count]; 165 count = (count + 1) % this.capacity; 166 return { 167 done: done, 168 value: value, 169 }; 170 }, 171 }; 172 } 173 private increaseCapacity(): void { 174 this.capacity = 2 * this.capacity; // 2 : means number 175 } 176 } 177 Object.freeze(Queue); 178 fastQueue = Queue; 179} 180export default fastQueue; 181