• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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