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