• 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: 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