1/* 2 * Copyright (c) 2021 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 ArrayList: 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 fastArrayList: Object = undefined; 27let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 28if (arkPritvate !== undefined) { 29 fastArrayList = arkPritvate.Load(arkPritvate.ArrayList); 30} else { 31 flag = true; 32} 33declare function requireNapi(s: string): errorUtil; 34if (flag || fastArrayList === undefined) { 35 const errorUtil = requireNapi('util.struct'); 36 class HandlerArrayList<T> { 37 private isOutBounds(obj: ArrayList<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: ArrayList<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: ArrayList<T>, prop: any, value: T): boolean { 51 if (prop === 'elementNum' || prop === 'capacity') { 52 obj[prop] = value; 53 return true; 54 } 55 let index: number = Number.parseInt(prop); 56 if (Number.isInteger(index)) { 57 errorUtil.checkRangeError('index', index, 0, obj.length); 58 obj[index] = value; 59 return true; 60 } 61 return false; 62 } 63 deleteProperty(obj: ArrayList<T>, prop: string): boolean { 64 this.isOutBounds(obj, prop); 65 let index: number = Number.parseInt(prop); 66 if (index >= 0 && index < obj.length && Number.isInteger(index)) { 67 obj.removeByIndex(index); 68 return true; 69 } 70 return false; 71 } 72 has(obj: ArrayList<T>, prop: T): boolean { 73 return obj.has(prop); 74 } 75 ownKeys(obj: ArrayList<T>): Array<string> { 76 let keys: Array<string> = []; 77 for (let i: number = 0; i < obj.length; i++) { 78 keys.push(i.toString()); 79 } 80 return keys; 81 } 82 defineProperty(): boolean { 83 return true; 84 } 85 getOwnPropertyDescriptor(obj: ArrayList<T>, prop: string): Object { 86 this.isOutBounds(obj, prop); 87 let index: number = Number.parseInt(prop); 88 if (index >= 0 && index < obj.length && Number.isInteger(index)) { 89 return Object.getOwnPropertyDescriptor(obj, prop); 90 } 91 return Object; 92 } 93 setPrototypeOf(): T { 94 throw new Error(`Can't setPrototype on ArrayList Object`); 95 } 96 } 97 interface IterableIterator<T> { 98 next: () => { 99 value: T; 100 done: boolean; 101 }; 102 } 103 class ArrayList<T> { 104 private elementNum: number = 0; 105 private capacity: number = 10; // 10 : means number 106 constructor() { 107 errorUtil.checkNewTargetIsNullError('ArrayList', !new.target); 108 return new Proxy(this, new HandlerArrayList()); 109 } 110 get length(): number { 111 return this.elementNum; 112 } 113 add(element: T): boolean { 114 errorUtil.checkBindError('add', ArrayList, this); 115 if (this.isFull()) { 116 this.resize(); 117 } 118 this[this.elementNum++] = element; 119 return true; 120 } 121 insert(element: T, index: number): void { 122 errorUtil.checkBindError('insert', ArrayList, this); 123 errorUtil.checkTypeError('index', 'Integer', index); 124 errorUtil.checkRangeError('index', index, 0, this.elementNum); 125 if (this.isFull()) { 126 this.resize(); 127 } 128 for (let i: number = this.elementNum; i > index; i--) { 129 this[i] = this[i - 1]; 130 } 131 this[index] = element; 132 this.elementNum++; 133 } 134 has(element: T): boolean { 135 errorUtil.checkBindError('has', ArrayList, this); 136 for (let i: number = 0; i < this.elementNum; i++) { 137 if (this[i] === element) { 138 return true; 139 } 140 } 141 return false; 142 } 143 getIndexOf(element: T): number { 144 errorUtil.checkBindError('getIndexOf', ArrayList, this); 145 for (let i: number = 0; i < this.elementNum; i++) { 146 if (element === this[i]) { 147 return i; 148 } 149 } 150 return -1; 151 } 152 removeByIndex(index: number): T { 153 errorUtil.checkBindError('removeByIndex', ArrayList, this); 154 errorUtil.checkTypeError('index', 'Integer', index); 155 errorUtil.checkRangeError('index', index, 0, this.elementNum - 1); 156 let result: T = this[index]; 157 for (let i: number = index; i < this.elementNum - 1; i++) { 158 this[i] = this[i + 1]; 159 } 160 this.elementNum--; 161 return result; 162 } 163 remove(element: T): boolean { 164 errorUtil.checkBindError('remove', ArrayList, this); 165 if (this.has(element)) { 166 let index: number = this.getIndexOf(element); 167 for (let i: number = index; i < this.elementNum - 1; i++) { 168 this[i] = this[i + 1]; 169 } 170 this.elementNum--; 171 return true; 172 } 173 return false; 174 } 175 getLastIndexOf(element: T): number { 176 errorUtil.checkBindError('getLastIndexOf', ArrayList, this); 177 for (let i: number = this.elementNum - 1; i >= 0; i--) { 178 if (element === this[i]) { 179 return i; 180 } 181 } 182 return -1; 183 } 184 removeByRange(fromIndex: number, toIndex: number): void { 185 errorUtil.checkBindError('removeByRange', ArrayList, this); 186 errorUtil.checkTypeError('fromIndex', 'Integer', fromIndex); 187 errorUtil.checkTypeError('toIndex', 'Integer', toIndex); 188 errorUtil.checkRangeError('fromIndex', fromIndex, 0, 189 (toIndex > this.elementNum) ? this.elementNum - 1 : toIndex - 1); 190 errorUtil.checkRangeError('toIndex', toIndex, 0, this.elementNum); 191 let i: number = fromIndex; 192 for (let j: number = toIndex; j < this.elementNum; j++) { 193 this[i] = this[j]; 194 i++; 195 } 196 this.elementNum -= toIndex - fromIndex; 197 } 198 replaceAllElements(callbackfn: (value: T, index?: number, arrList?: ArrayList<T>) => T, 199 thisArg?: Object): void { 200 errorUtil.checkBindError('replaceAllElements', ArrayList, this); 201 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 202 for (let i: number = 0; i < this.elementNum; i++) { 203 this[i] = callbackfn.call(thisArg, this[i], i, this); 204 } 205 } 206 forEach(callbackfn: (value: T, index?: number, arrList?: ArrayList<T>) => void, 207 thisArg?: Object): void { 208 errorUtil.checkBindError('forEach', ArrayList, this); 209 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 210 for (let i: number = 0; i < this.elementNum; i++) { 211 callbackfn.call(thisArg, this[i], i, this); 212 } 213 } 214 sort(comparator?: (firstValue: T, secondValue: T) => number): void { 215 errorUtil.checkBindError('sort', ArrayList, this); 216 let isSort: boolean = true; 217 if (comparator) { 218 errorUtil.checkTypeError('comparator', 'callable', comparator); 219 for (let i: number = 0; i < this.elementNum; i++) { 220 for (let j: number = 0; j < this.elementNum - 1 - i; j++) { 221 if (comparator(this[j], this[j + 1]) > 0) { 222 isSort = false; 223 let temp: T = this[j]; 224 this[j] = this[j + 1]; 225 this[j + 1] = temp; 226 } 227 } 228 } 229 } else { 230 for (let i: number = 0; i < this.length - 1; i++) { 231 for (let j: number = 0; j < this.elementNum - 1 - i; j++) { 232 if (this.asciSort(this[j], this[j + 1])) { 233 isSort = false; 234 let temp: T = this[j]; 235 this[j] = this[j + 1]; 236 this[j + 1] = temp; 237 } 238 } 239 if (isSort) { 240 break; 241 } 242 } 243 } 244 } 245 private asciSort(curElement: string, nextElement: string): boolean { 246 if ((Object.prototype.toString.call(curElement) === '[object String]' || 247 Object.prototype.toString.call(curElement) === '[object Number]') && 248 (Object.prototype.toString.call(nextElement) === '[object String]' || 249 Object.prototype.toString.call(nextElement) === '[object Number]')) { 250 curElement = curElement.toString(); 251 nextElement = nextElement.toString(); 252 if (curElement > nextElement) { 253 return true; 254 } 255 return false; 256 } 257 return false; 258 } 259 subArrayList(fromIndex: number, toIndex: number): ArrayList<T> { 260 errorUtil.checkBindError('subArrayList', ArrayList, this); 261 errorUtil.checkTypeError('fromIndex', 'Integer', fromIndex); 262 errorUtil.checkTypeError('toIndex', 'Integer', toIndex); 263 errorUtil.checkRangeError('fromIndex', fromIndex, 0, 264 (toIndex > this.elementNum) ? this.elementNum - 1 : toIndex - 1); 265 errorUtil.checkRangeError('toIndex', toIndex, 0, this.elementNum); 266 let arraylist: ArrayList<T> = new ArrayList<T>(); 267 for (let i: number = fromIndex; i < toIndex; i++) { 268 arraylist.add(this[i]); 269 } 270 return arraylist; 271 } 272 clear(): void { 273 errorUtil.checkBindError('clear', ArrayList, this); 274 this.elementNum = 0; 275 } 276 clone(): ArrayList<T> { 277 errorUtil.checkBindError('clone', ArrayList, this); 278 let clone: ArrayList<T> = new ArrayList<T>(); 279 for (let i: number = 0; i < this.elementNum; i++) { 280 clone.add(this[i]); 281 } 282 return clone; 283 } 284 getCapacity(): number { 285 errorUtil.checkBindError('getCapacity', ArrayList, this); 286 return this.capacity; 287 } 288 convertToArray(): Array<T> { 289 errorUtil.checkBindError('convertToArray', ArrayList, this); 290 let arr: Array<T> = []; 291 for (let i: number = 0; i < this.elementNum; i++) { 292 arr[i] = this[i]; 293 } 294 return arr; 295 } 296 private isFull(): boolean { 297 return this.elementNum === this.capacity; 298 } 299 private resize(): void { 300 this.capacity = 1.5 * this.capacity; // 1.5 : means number 301 } 302 isEmpty(): boolean { 303 errorUtil.checkBindError('isEmpty', ArrayList, this); 304 return this.elementNum === 0; 305 } 306 increaseCapacityTo(newCapacity: number): void { 307 errorUtil.checkBindError('increaseCapacityTo', ArrayList, this); 308 errorUtil.checkTypeError('newCapacity', 'Integer', newCapacity); 309 if (newCapacity >= this.elementNum) { 310 this.capacity = newCapacity; 311 } 312 } 313 trimToCurrentLength(): void { 314 errorUtil.checkBindError('trimToCurrentLength', ArrayList, this); 315 this.capacity = this.elementNum; 316 } 317 [Symbol.iterator](): IterableIterator<T> { 318 errorUtil.checkBindError('Symbol.iterator', ArrayList, this); 319 let count: number = 0; 320 return { 321 next: function (): { done: boolean, value: T } { 322 let done: boolean = false; 323 let value: T = undefined; 324 done = count >= this.elementNum; 325 value = done ? undefined : this[count++]; 326 return { 327 done: done, 328 value: value, 329 }; 330 }, 331 }; 332 } 333 } 334 Object.freeze(ArrayList); 335 fastArrayList = ArrayList; 336} 337export default fastArrayList; 338