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: any): 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: any, value: any): 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: any): 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: any): 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: any): 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; 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 } 270 remove(element: T): boolean { 271 ErrorUtil.checkBindError("remove", LinkedList, this); 272 if (this.isEmpty()) { 273 return false; 274 } 275 if (this.has(element)) { 276 let index: number = 0; 277 index = this.getIndexOf(element); 278 this.removeByIndex(index); 279 return true; 280 } 281 return false; 282 } 283 removeFirstFound(element: T): boolean { 284 ErrorUtil.checkBindError("removeFirstFound", LinkedList, this); 285 ErrorUtil.checkIsEmptyError(!this.head); 286 if (this.has(element)) { 287 let index: number = 0; 288 index = this.getIndexOf(element); 289 this.removeByIndex(index); 290 return true; 291 } 292 return false; 293 } 294 removeLastFound(element: T): boolean { 295 ErrorUtil.checkBindError("removeLastFound", LinkedList, this); 296 ErrorUtil.checkIsEmptyError(!this.tail); 297 if (this.has(element)) { 298 let index: number = 0; 299 index = this.getLastIndexOf(element); 300 this.removeByIndex(index); 301 return true; 302 } 303 return false; 304 } 305 getFirst(): T { 306 ErrorUtil.checkBindError("getFirst", LinkedList, this); 307 if (this.head !== undefined) { 308 return this.head.element; 309 } 310 return undefined; 311 } 312 getLast(): T { 313 ErrorUtil.checkBindError("getLast", LinkedList, this); 314 if (this.tail !== undefined) { 315 return this.tail.element; 316 } 317 return undefined; 318 } 319 insert(index: number, element: T): void { 320 ErrorUtil.checkBindError("insert", LinkedList, this); 321 ErrorUtil.checkTypeError("index", "Integer", index); 322 ErrorUtil.checkRangeError("index", index, 0, this.length); 323 if (index >= 0 && index <= this.elementNum) { 324 let newNode: NodeObj<T> = new NodeObj(element); 325 let current: NodeObj<T> = this.head; 326 if (index === 0) { 327 if (this.head === undefined) { 328 this.head = this.tail = newNode; 329 } else { 330 newNode.next = this.head; 331 this.head.prev = newNode; 332 this.head = newNode; 333 } 334 } else if (index === this.elementNum && this.elementNum !== 0) { 335 let prevNode: NodeObj<T> = this.getNode(this.elementNum - 1); 336 prevNode.next = this.tail = newNode; 337 } else { 338 let prevNode: NodeObj<T> = this.getNode(index - 1); 339 current = prevNode.next; 340 newNode.next = current; 341 prevNode.next = newNode; 342 current.prev = newNode; 343 newNode.prev = prevNode; 344 } 345 } else { 346 throw new RangeError('the index is out-of-bounds'); 347 } 348 this.elementNum++; 349 } 350 set(index: number, element: T): T { 351 ErrorUtil.checkBindError("set", LinkedList, this); 352 ErrorUtil.checkTypeError("index", "Integer", index); 353 ErrorUtil.checkRangeError("index", index, 0, this.length - 1); 354 let current: NodeObj<T> = undefined; 355 current = this.getNode(index); 356 current.element = element; 357 return current.element; 358 } 359 convertToArray(): Array<T> { 360 ErrorUtil.checkBindError("convertToArray", LinkedList, this); 361 let arr: Array<T> = []; 362 let index: number = 0; 363 if (this.elementNum <= 0) { 364 return arr; 365 } 366 if (this.head !== undefined) { 367 let current: NodeObj<T> = this.head; 368 arr[index] = this.head.element; 369 while (current.next !== undefined) { 370 current = current.next; 371 arr[++index] = current.element; 372 } 373 } 374 return arr; 375 } 376 clone(): LinkedList<T> { 377 ErrorUtil.checkBindError("clone", LinkedList, this); 378 let clone: LinkedList<T> = new LinkedList<T>(); 379 let arr: Array<T> = this.convertToArray(); 380 for (let i: number = 0; i < arr.length; i++) { 381 let item: T = arr[i]; 382 clone.add(item); 383 } 384 return clone; 385 } 386 private isEmpty(): boolean { 387 return this.elementNum === 0; 388 } 389 forEach(callbackfn: (value: T, index?: number, linkedList?: LinkedList<T>) => void, 390 thisArg?: Object): void { 391 ErrorUtil.checkBindError("forEach", LinkedList, this); 392 ErrorUtil.checkTypeError("callbackfn", "callable", callbackfn); 393 let index: number = 0; 394 if (this.head !== undefined) { 395 let current: NodeObj<T> = this.head; 396 if (this.elementNum > 0) { 397 callbackfn.call(thisArg, this.head.element, index, this); 398 } 399 while (current.next !== undefined) { 400 current = current.next; 401 callbackfn.call(thisArg, current.element, ++index, this); 402 } 403 } 404 } 405 [Symbol.iterator](): IterableIterator<T> { 406 ErrorUtil.checkBindError("Symbol.iterator", LinkedList, this); 407 let count: number = 0; 408 let linkedlist: LinkedList<T> = this; 409 return { 410 next: function () { 411 let done: boolean = false; 412 let value: T = undefined; 413 done = count >= linkedlist.elementNum; 414 value = done ? undefined : linkedlist.getNode(count++).element; 415 return { 416 done: done, 417 value: value, 418 }; 419 }, 420 }; 421 } 422 } 423 Object.freeze(LinkedList); 424 fastLinkedList = LinkedList; 425} 426export default fastLinkedList; 427