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 Deque: 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 fastDeque: Object = undefined; 27let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 28if (arkPritvate !== undefined) { 29 fastDeque = arkPritvate.Load(arkPritvate.Deque); 30} else { 31 flag = true; 32} 33declare function requireNapi(s: string): errorUtil; 34if (flag || fastDeque === undefined) { 35 const errorUtil = requireNapi('util.struct'); 36 class HandlerDeque<T> { 37 private isOutBounds(prop: string): void { 38 let index: number = Number.parseInt(prop); 39 if (Number.isInteger(index)) { 40 errorUtil.checkRangeError('index', index, 0); 41 } 42 } 43 get(obj: Deque<T>, prop: string): T { 44 if (typeof prop === 'symbol') { 45 return obj[prop]; 46 } 47 this.isOutBounds(prop); 48 return obj[prop]; 49 } 50 set(obj: Deque<T>, prop: any, value: T): boolean { 51 if (prop === 'front' || prop === 'capacity' || prop === 'rear') { 52 obj[prop] = value; 53 return true; 54 } 55 let index: number = Number(prop); 56 if (Number.isInteger(index)) { 57 errorUtil.checkRangeError('index', index, 0); 58 obj[index] = value; 59 return true; 60 } 61 return false; 62 } 63 has(obj: Deque<T>, prop: T): boolean { 64 return obj.has(prop); 65 } 66 ownKeys(obj: Deque<T>): Array<string> { 67 let keys: Array<string> = []; 68 for (let i: number = 0; i < obj.length; i++) { 69 keys.push(i.toString()); 70 } 71 return keys; 72 } 73 defineProperty(): boolean { 74 return true; 75 } 76 getOwnPropertyDescriptor(obj: Deque<T>, prop: string): Object { 77 this.isOutBounds(prop); 78 let index: number = Number.parseInt(prop); 79 if (index >= 0 && Number.isInteger(index)) { 80 return Object.getOwnPropertyDescriptor(obj, prop); 81 } 82 return Object; 83 } 84 setPrototypeOf(): T { 85 throw new Error(`Can't setPrototype on Deque Object`); 86 } 87 } 88 interface IterableIterator<T> { 89 next: () => { 90 value: T; 91 done: boolean; 92 }; 93 } 94 class Deque<T> { 95 private front: number; 96 private capacity: number; 97 private rear: number; 98 constructor() { 99 errorUtil.checkNewTargetIsNullError('Deque', !new.target); 100 this.front = 0; 101 this.capacity = 8; 102 this.rear = 0; 103 return new Proxy(this, new HandlerDeque()); 104 } 105 get length(): number { 106 let result: number = 0; 107 result = (this.rear - this.front + this.capacity) % this.capacity; 108 return result; 109 } 110 insertFront(element: T): void { 111 errorUtil.checkBindError('insertFront', Deque, this); 112 if (this.isFull()) { 113 this.increaseCapacity(); 114 } 115 this.front = (this.front - 1 + this.capacity) % this.capacity; 116 this[this.front] = element; 117 } 118 insertEnd(element: T): void { 119 errorUtil.checkBindError('insertEnd', Deque, this); 120 if (this.isFull()) { 121 this.increaseCapacity(); 122 } 123 this[this.rear] = element; 124 this.rear = (this.rear + 1) % (this.capacity + 1); 125 } 126 getFirst(): T { 127 errorUtil.checkBindError('getFirst', Deque, this); 128 if (this.isEmpty()) { 129 return undefined; 130 } 131 return this[this.front]; 132 } 133 getLast(): T { 134 errorUtil.checkBindError('getLast', Deque, this); 135 if (this.isEmpty()) { 136 return undefined; 137 } 138 return this[this.rear - 1]; 139 } 140 has(element: T): boolean { 141 errorUtil.checkBindError('has', Deque, this); 142 let result: boolean = false; 143 this.forEach(function (value) { 144 if (value === element) { 145 result = true; 146 } 147 }); 148 return result; 149 } 150 popFirst(): T { 151 errorUtil.checkBindError('popFirst', Deque, this); 152 if (this.isEmpty()) { 153 return undefined; 154 } 155 let result: T = undefined; 156 result = this[this.front]; 157 this.front = (this.front + 1) % (this.capacity + 1); 158 return result; 159 } 160 popLast(): T { 161 errorUtil.checkBindError('popLast', Deque, this); 162 if (this.isEmpty()) { 163 return undefined; 164 } 165 let result: T = undefined; 166 result = this[this.rear - 1]; 167 this.rear = (this.rear + this.capacity) % (this.capacity + 1); 168 return result; 169 } 170 forEach(callbackfn: (value: T, index?: number, deque?: Deque<T>) => void, 171 thisArg?: Object): void { 172 errorUtil.checkBindError('forEach', Deque, this); 173 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 174 let k: number = 0; 175 let i: number = this.front; 176 while (true) { 177 callbackfn.call(thisArg, this[i], k, this); 178 i = (i + 1) % this.capacity; 179 k++; 180 if (i === this.rear) { 181 break; 182 } 183 } 184 } 185 private increaseCapacity(): void { 186 let count: number = 0; 187 let arr: Array<T> = []; 188 let length: number = this.length; 189 while (true) { 190 arr[count++] = this[this.front]; 191 this.front = (this.front + 1) % this.capacity; 192 if (this.front === this.rear) { 193 break; 194 } 195 } 196 for (let i: number = 0; i < length; i++) { 197 this[i] = arr[i]; 198 } 199 this.capacity = 2 * this.capacity; // 2 : means number 200 this.front = 0; 201 this.rear = length; 202 } 203 private isFull(): boolean { 204 return (this.rear + 1) % this.capacity === this.front; 205 } 206 private isEmpty(): boolean { 207 return this.length === 0; 208 } 209 [Symbol.iterator](): IterableIterator<T> { 210 errorUtil.checkBindError('Symbol.iterator', Deque, this); 211 let count: number = this.front; 212 return { 213 next: function (): { done: boolean, value: T } { 214 let done: boolean = false; 215 let value: T = undefined; 216 done = count === this.rear; 217 value = done ? undefined : this[count]; 218 count = (count + 1) % this.capacity; 219 return { 220 done: done, 221 value: value, 222 }; 223 }, 224 }; 225 } 226 } 227 Object.freeze(Deque); 228 fastDeque = Deque; 229} 230export default fastDeque; 231