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 Stack: 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 fastStack: Object = undefined; 27let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 28if (arkPritvate !== undefined) { 29 fastStack = arkPritvate.Load(arkPritvate.Stack); 30} else { 31 flag = true; 32} 33declare function requireNapi(s: string): errorUtil; 34if (flag || fastStack === undefined) { 35 const errorUtil = requireNapi('util.struct'); 36 class HandlerStack<T> { 37 private isOutBounds(obj: Stack<T>, prop: string): void { 38 let index: number = Number.parseInt(prop); 39 if (Number.isInteger(index)) { 40 errorUtil.checkRangeError('index', index, 0, obj.length - 1); 41 } 42 } 43 get(obj: Stack<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: Stack<T>, prop: any, value: T): boolean { 51 if (prop === 'elementNum' || prop === 'capacity') { 52 obj[prop] = value; 53 return true; 54 } 55 this.isOutBounds(obj, prop); 56 let index: number = Number.parseInt(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: Stack<T>): Array<string> { 64 let keys: string[] = []; 65 let length: number = obj.length; 66 for (let i: number = 0; i < length; i++) { 67 keys.push(i.toString()); 68 } 69 return keys; 70 } 71 defineProperty(): boolean { 72 return true; 73 } 74 getOwnPropertyDescriptor(obj: Stack<T>, prop: string): Object { 75 this.isOutBounds(obj, prop); 76 let index: number = Number.parseInt(prop); 77 if (index >= 0 && index < obj.length && Number.isInteger(index)) { 78 return Object.getOwnPropertyDescriptor(obj, prop); 79 } 80 return Object; 81 } 82 setPrototypeOf(): T { 83 throw new Error(`Can't setPrototype on Stack Object`); 84 } 85 } 86 interface IterableIterator<T> { 87 next: () => { 88 value: T; 89 done: boolean; 90 }; 91 } 92 class Stack<T> { 93 private elementNum: number = 0; 94 private capacity: number = 10; // 10 : means number 95 constructor() { 96 errorUtil.checkNewTargetIsNullError('Stack', !new.target); 97 return new Proxy(this, new HandlerStack()); 98 } 99 get length(): number { 100 return this.elementNum; 101 } 102 push(item: T): T { 103 errorUtil.checkBindError('push', Stack, this); 104 if (this.isFull()) { 105 this.increaseCapacity(); 106 } 107 this[this.elementNum++] = item; 108 return item; 109 } 110 pop(): T { 111 errorUtil.checkBindError('pop', Stack, this); 112 if (this.isEmpty()) { 113 return undefined; 114 } 115 let result: T = undefined; 116 result = this[this.length - 1]; 117 this.elementNum--; 118 return result; 119 } 120 peek(): T { 121 errorUtil.checkBindError('peek', Stack, this); 122 if (this.isEmpty()) { 123 return undefined; 124 } 125 return this[this.length - 1]; 126 } 127 locate(element: T): number { 128 errorUtil.checkBindError('locate', Stack, this); 129 for (let i: number = 0; i < this.length; i++) { 130 if (this[i] === element) { 131 return i; 132 } 133 } 134 return -1; 135 } 136 isEmpty(): boolean { 137 errorUtil.checkBindError('isEmpty', Stack, this); 138 return this.elementNum === 0; 139 } 140 forEach(callbackfn: (value: T, index?: number, stack?: Stack<T>) => void, 141 thisArg?: Object): void { 142 errorUtil.checkBindError('forEach', Stack, this); 143 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 144 for (let i: number = 0; i < this.length; i++) { 145 callbackfn.call(thisArg, this[i], i, this); 146 } 147 } 148 private isFull(): boolean { 149 return this.elementNum === this.capacity; 150 } 151 private increaseCapacity(): void { 152 this.capacity = 1.5 * this.capacity; // 1.5 : means number 153 } 154 [Symbol.iterator](): IterableIterator<T> { 155 errorUtil.checkBindError('Symbol.iterator', Stack, this); 156 let count: number = 0; 157 return { 158 next: function (): { done: boolean, value: T } { 159 let done: boolean = false; 160 let value: T = undefined; 161 done = count >= this.elementNum; 162 value = done ? undefined : this[count++]; 163 return { 164 done: done, 165 value: value, 166 }; 167 }, 168 }; 169 } 170 } 171 Object.freeze(Stack); 172 fastStack = Stack; 173} 174export default fastStack; 175