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