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 List: 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 fastList: Object = undefined; 27let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined; 28if (arkPritvate !== undefined) { 29 fastList = arkPritvate.Load(arkPritvate.List); 30} else { 31 flag = true; 32} 33declare function requireNapi(s: string): errorUtil; 34if (flag || fastList === undefined) { 35 const errorUtil = requireNapi('util.struct'); 36 class HandlerList<T> { 37 get(obj: List<T>, prop: string): T { 38 if (typeof prop === 'symbol') { 39 return obj[prop]; 40 } 41 let index: number = Number.parseInt(prop); 42 if (Number.isInteger(index)) { 43 errorUtil.checkRangeError('index', index, 0, obj.length - 1); 44 return obj.get(index); 45 } 46 return obj[prop]; 47 } 48 set(obj: List<T>, prop: string, value: T): boolean { 49 if (prop === 'elementNum' || 50 prop === 'capacity' || 51 prop === 'head' || 52 prop === 'next') { 53 obj[prop] = value; 54 return true; 55 } 56 let index: number = Number.parseInt(prop); 57 if (Number.isInteger(index)) { 58 errorUtil.checkRangeError('index', index, 0, obj.length); 59 obj.set(index, value); 60 return true; 61 } 62 return false; 63 } 64 deleteProperty(obj: List<T>, prop: string): boolean { 65 let index: number = Number.parseInt(prop); 66 if (Number.isInteger(index)) { 67 errorUtil.checkRangeError('index', index, 0, obj.length - 1); 68 obj.removeByIndex(index); 69 return true; 70 } 71 return false; 72 } 73 has(obj: List<T>, prop: T): boolean { 74 return obj.has(prop); 75 } 76 ownKeys(obj: List<T>): Array<string> { 77 let keys: Array<string> = []; 78 for (let i: number = 0; i < obj.length; i++) { 79 keys.push(i.toString()); 80 } 81 return keys; 82 } 83 defineProperty(): boolean { 84 return true; 85 } 86 getOwnPropertyDescriptor(obj: List<T>, prop: string): Object { 87 let index: number = Number.parseInt(prop); 88 if (Number.isInteger(index)) { 89 errorUtil.checkRangeError('index', index, 0, obj.length - 1); 90 return Object.getOwnPropertyDescriptor(obj, prop); 91 } 92 return Object; 93 } 94 setPrototypeOf(): T { 95 throw new Error(`Can't setPrototype on List Object`); 96 } 97 } 98 interface IterableIterator<T> { 99 next: () => { 100 value: T; 101 done: boolean; 102 }; 103 } 104 class NodeObj<T> { 105 element: T; 106 next?: NodeObj<T>; 107 constructor(element: T, next?: NodeObj<T>) { 108 this.element = element; 109 this.next = next; 110 } 111 } 112 class List<T> { 113 private head: NodeObj<T>; 114 private elementNum: number; 115 private capacity: number; 116 constructor() { 117 errorUtil.checkNewTargetIsNullError('List', !new.target); 118 this.head = undefined; 119 this.elementNum = 0; 120 this.capacity = 10; 121 return new Proxy(this, new HandlerList()); 122 } 123 get length(): number { 124 return this.elementNum; 125 } 126 private getNode(index: number): NodeObj<T> | undefined { 127 if (index >= 0 && index < this.elementNum) { 128 let current: NodeObj<T> = this.head; 129 for (let i: number = 0; i < index; i++) { 130 if (current !== undefined) { 131 current = current.next; 132 } 133 } 134 return current; 135 } 136 return undefined; 137 } 138 get(index: number): T { 139 errorUtil.checkBindError('get', List, this); 140 errorUtil.checkTypeError('index', 'Integer', index); 141 if (index >= 0 && index < this.elementNum) { 142 let current: NodeObj<T> = this.head; 143 for (let i: number = 0; i < index && current !== undefined; i++) { 144 current = current.next; 145 } 146 return current.element; 147 } 148 return undefined; 149 } 150 add(element: T): boolean { 151 errorUtil.checkBindError('add', List, this); 152 let node: NodeObj<T> = new NodeObj(element); 153 if (this.head === undefined) { 154 this.head = node; 155 } else { 156 let current: NodeObj<T> = this.head; 157 while (current.next !== undefined) { 158 current = current.next; 159 } 160 current.next = node; 161 } 162 this.elementNum++; 163 return true; 164 } 165 clear(): void { 166 errorUtil.checkBindError('clear', List, this); 167 this.head = undefined; 168 this.elementNum = 0; 169 } 170 has(element: T): boolean { 171 errorUtil.checkBindError('has', List, this); 172 if (this.head !== undefined) { 173 if (this.head.element === element) { 174 return true; 175 } 176 let current: NodeObj<T> = this.head; 177 while (current.next !== undefined) { 178 current = current.next; 179 if (current.element === element) { 180 return true; 181 } 182 } 183 } 184 return false; 185 } 186 equal(obj: Object): boolean { 187 errorUtil.checkBindError('equal', List, this); 188 if (obj === this) { 189 return true; 190 } 191 if (!(obj instanceof List)) { 192 return false; 193 } else { 194 let e1: NodeObj<T> = this.head; 195 let e2: NodeObj<T> = obj.head; 196 if (e1 !== undefined && e2 !== undefined) { 197 while (e1.next !== undefined && e2.next !== undefined) { 198 e1 = e1.next; 199 e2 = e2.next; 200 if (e1.element !== e2.element) { 201 return false; 202 } 203 } 204 return !(e1.next !== undefined || e2.next !== undefined); 205 } else if (e1 !== undefined && e2 === undefined) { 206 return false; 207 } else if (e1 === undefined && e2 !== undefined) { 208 return false; 209 } else { 210 return true; 211 } 212 } 213 } 214 getIndexOf(element: T): number { 215 errorUtil.checkBindError('getIndexOf', List, this); 216 for (let i: number = 0; i < this.elementNum; i++) { 217 let curNode: NodeObj<T> = undefined; 218 curNode = this.getNode(i); 219 if (curNode !== undefined && curNode.element === element) { 220 return i; 221 } 222 } 223 return -1; 224 } 225 getLastIndexOf(element: T): number { 226 errorUtil.checkBindError('getLastIndexOf', List, this); 227 for (let i: number = this.elementNum - 1; i >= 0; i--) { 228 let curNode: NodeObj<T> = undefined; 229 curNode = this.getNode(i); 230 if (curNode !== undefined && curNode.element === element) { 231 return i; 232 } 233 } 234 return -1; 235 } 236 removeByIndex(index: number): T { 237 errorUtil.checkBindError('removeByIndex', List, this); 238 errorUtil.checkTypeError('index', 'Integer', index); 239 errorUtil.checkRangeError('index', index, 0, this.elementNum - 1); 240 let oldNode: NodeObj<T> = this.head; 241 if (index === 0) { 242 oldNode = this.head; 243 this.head = oldNode && oldNode.next; 244 } else { 245 let prevNode: NodeObj<T> = undefined; 246 prevNode = this.getNode(index - 1); 247 oldNode = prevNode.next; 248 prevNode.next = oldNode.next; 249 } 250 this.elementNum--; 251 return oldNode && oldNode.element; 252 } 253 remove(element: T): boolean { 254 errorUtil.checkBindError('remove', List, this); 255 if (this.has(element)) { 256 let index: number = 0; 257 index = this.getIndexOf(element); 258 this.removeByIndex(index); 259 return true; 260 } 261 return false; 262 } 263 replaceAllElements(callbackfn: (value: T, index?: number, list?: List<T>) => T, 264 thisArg?: Object): void { 265 errorUtil.checkBindError('replaceAllElements', List, this); 266 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 267 let index: number = 0; 268 if (this.head !== undefined) { 269 let current: NodeObj<T> = this.head; 270 if (this.elementNum > 0) { 271 this.getNode(index).element = callbackfn.call(thisArg, this.head.element, index, this); 272 } 273 while (current.next !== undefined) { 274 current = current.next; 275 this.getNode(++index).element = callbackfn.call(thisArg, current.element, index, this); 276 } 277 } 278 } 279 getFirst(): T { 280 errorUtil.checkBindError('getFirst', List, this); 281 if (this.isEmpty()) { 282 return undefined; 283 } 284 let element: T = this.head.element; 285 return element; 286 } 287 getLast(): T { 288 errorUtil.checkBindError('getLast', List, this); 289 if (this.isEmpty()) { 290 return undefined; 291 } 292 let newNode: NodeObj<T> = undefined; 293 newNode = this.getNode(this.elementNum - 1); 294 let element: T = newNode.element; 295 return element; 296 } 297 insert(element: T, index: number): void { 298 errorUtil.checkBindError('insert', List, this); 299 errorUtil.checkTypeError('index', 'Integer', index); 300 errorUtil.checkRangeError('index', index, 0, this.elementNum); 301 let newNode: NodeObj<T> = undefined; 302 newNode = new NodeObj(element); 303 if (index === 0) { 304 let current: NodeObj<T> = this.head; 305 newNode.next = current; 306 this.head = newNode; 307 } else { 308 let prevNode: NodeObj<T> = undefined; 309 prevNode = this.getNode(index - 1); 310 newNode.next = prevNode.next; 311 prevNode.next = newNode; 312 } 313 this.elementNum++; 314 } 315 set(index: number, element: T): T { 316 errorUtil.checkBindError('set', List, this); 317 errorUtil.checkTypeError('index', 'Integer', index); 318 errorUtil.checkRangeError('index', index, 0, this.length - 1); 319 let current: NodeObj<T> = undefined; 320 current = this.getNode(index); 321 current.element = element; 322 return current.element; 323 } 324 sort(comparator: (firstValue: T, secondValue: T) => number): void { 325 errorUtil.checkBindError('sort', List, this); 326 errorUtil.checkTypeError('comparator', 'callable', comparator); 327 let isSort: boolean = true; 328 for (let i: number = 0; i < this.elementNum; i++) { 329 for (let j: number = 0; j < this.elementNum - 1 - i; j++) { 330 if ( 331 comparator(this.getNode(j).element, this.getNode(j + 1).element) > 0 332 ) { 333 isSort = false; 334 let temp: T = undefined; 335 temp = this.getNode(j).element; 336 this.getNode(j).element = this.getNode(j + 1).element; 337 this.getNode(j + 1).element = temp; 338 } 339 } 340 if (isSort) { 341 break; 342 } 343 } 344 } 345 getSubList(fromIndex: number, toIndex: number): List<T> { 346 errorUtil.checkBindError('getSubList', List, this); 347 errorUtil.checkTypeError('fromIndex', 'Integer', fromIndex); 348 errorUtil.checkTypeError('toIndex', 'Integer', toIndex); 349 errorUtil.checkRangeError('fromIndex', fromIndex, 0, 350 (toIndex > this.elementNum) ? this.elementNum - 1 : toIndex - 1); 351 errorUtil.checkRangeError('toIndex', toIndex, 0, this.elementNum); 352 let list: List<T> = new List<T>(); 353 for (let i: number = fromIndex; i < toIndex; i++) { 354 let element: T = undefined; 355 element = this.getNode(i).element; 356 list.add(element); 357 if (element === undefined) { 358 break; 359 } 360 } 361 return list; 362 } 363 convertToArray(): Array<T> { 364 errorUtil.checkBindError('convertToArray', List, this); 365 let arr: Array<T> = []; 366 let index: number = 0; 367 if (this.elementNum <= 0) { 368 return arr; 369 } 370 if (this.head !== undefined) { 371 let current: NodeObj<T> = this.head; 372 arr[index] = this.head.element; 373 while (current.next !== undefined) { 374 current = current.next; 375 arr[++index] = current.element; 376 } 377 } 378 return arr; 379 } 380 isEmpty(): boolean { 381 errorUtil.checkBindError('isEmpty', List, this); 382 return this.elementNum === 0; 383 } 384 forEach(callbackfn: (value: T, index?: number, list?: List<T>) => void, 385 thisArg?: Object): void { 386 errorUtil.checkBindError('forEach', List, this); 387 errorUtil.checkTypeError('callbackfn', 'callable', callbackfn); 388 let index: number = 0; 389 if (this.head !== undefined) { 390 let current: NodeObj<T> = this.head; 391 if (this.elementNum > 0) { 392 callbackfn.call(thisArg, this.head.element, index, this); 393 } 394 while (current.next !== undefined) { 395 current = current.next; 396 callbackfn.call(thisArg, current.element, ++index, this); 397 } 398 } 399 } 400 [Symbol.iterator](): IterableIterator<T> { 401 errorUtil.checkBindError('Symbol.iterator', List, this); 402 let count: number = 0; 403 return { 404 next: function (): { done: boolean, value: T } { 405 let done: boolean = false; 406 let value: T = undefined; 407 done = count >= this.elementNum; 408 value = done ? undefined : this.getNode(count++).element; 409 return { 410 done: done, 411 value: value, 412 }; 413 }, 414 }; 415 } 416 } 417 Object.freeze(List); 418 fastList = List; 419} 420export default fastList; 421