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