14d6c458bSopenharmony_ci/*
24d6c458bSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
34d6c458bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44d6c458bSopenharmony_ci * you may not use this file except in compliance with the License.
54d6c458bSopenharmony_ci * You may obtain a copy of the License at
64d6c458bSopenharmony_ci *
74d6c458bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84d6c458bSopenharmony_ci *
94d6c458bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104d6c458bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114d6c458bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124d6c458bSopenharmony_ci * See the License for the specific language governing permissions and
134d6c458bSopenharmony_ci * limitations under the License.
144d6c458bSopenharmony_ci */
154d6c458bSopenharmony_ciinterface ArkPrivate {
164d6c458bSopenharmony_ci  Deque: number;
174d6c458bSopenharmony_ci  Load(key: number): Object;
184d6c458bSopenharmony_ci}
194d6c458bSopenharmony_ciinterface errorUtil{
204d6c458bSopenharmony_ci  checkRangeError(paramName: string, receivedValue: unknown, min?: number, max?: number, options?: string): void;
214d6c458bSopenharmony_ci  checkNewTargetIsNullError(className: string, isNull: boolean): void;
224d6c458bSopenharmony_ci  checkBindError(methodName: string, className: Function, self: unknown): void;
234d6c458bSopenharmony_ci  checkTypeError(paramName: string, type: string, receivedValue: unknown): void;
244d6c458bSopenharmony_ci}
254d6c458bSopenharmony_cilet flag: boolean = false;
264d6c458bSopenharmony_cilet fastDeque: Object = undefined;
274d6c458bSopenharmony_cilet arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined;
284d6c458bSopenharmony_ciif (arkPritvate !== undefined) {
294d6c458bSopenharmony_ci  fastDeque = arkPritvate.Load(arkPritvate.Deque);
304d6c458bSopenharmony_ci} else {
314d6c458bSopenharmony_ci  flag = true;
324d6c458bSopenharmony_ci}
334d6c458bSopenharmony_cideclare function requireNapi(s: string): errorUtil;
344d6c458bSopenharmony_ciif (flag || fastDeque === undefined) {
354d6c458bSopenharmony_ci  const errorUtil = requireNapi('util.struct');
364d6c458bSopenharmony_ci  class HandlerDeque<T> {
374d6c458bSopenharmony_ci    private isOutBounds(prop: string): void {
384d6c458bSopenharmony_ci      let index: number = Number.parseInt(prop);
394d6c458bSopenharmony_ci      if (Number.isInteger(index)) {
404d6c458bSopenharmony_ci        errorUtil.checkRangeError('index', index, 0);
414d6c458bSopenharmony_ci      }
424d6c458bSopenharmony_ci    }
434d6c458bSopenharmony_ci    get(obj: Deque<T>, prop: string): T {
444d6c458bSopenharmony_ci      if (typeof prop === 'symbol') {
454d6c458bSopenharmony_ci        return obj[prop];
464d6c458bSopenharmony_ci      }
474d6c458bSopenharmony_ci      this.isOutBounds(prop);
484d6c458bSopenharmony_ci      return obj[prop];
494d6c458bSopenharmony_ci    }
504d6c458bSopenharmony_ci    set(obj: Deque<T>, prop: any, value: T): boolean {
514d6c458bSopenharmony_ci      if (prop === 'front' || prop === 'capacity' || prop === 'rear') {
524d6c458bSopenharmony_ci        obj[prop] = value;
534d6c458bSopenharmony_ci        return true;
544d6c458bSopenharmony_ci      }
554d6c458bSopenharmony_ci      let index: number = Number(prop);
564d6c458bSopenharmony_ci      if (Number.isInteger(index)) {
574d6c458bSopenharmony_ci        errorUtil.checkRangeError('index', index, 0);
584d6c458bSopenharmony_ci        obj[index] = value;
594d6c458bSopenharmony_ci        return true;
604d6c458bSopenharmony_ci      }
614d6c458bSopenharmony_ci      return false;
624d6c458bSopenharmony_ci    }
634d6c458bSopenharmony_ci    has(obj: Deque<T>, prop: T): boolean {
644d6c458bSopenharmony_ci      return obj.has(prop);
654d6c458bSopenharmony_ci    }
664d6c458bSopenharmony_ci    ownKeys(obj: Deque<T>): Array<string> {
674d6c458bSopenharmony_ci      let keys: Array<string> = [];
684d6c458bSopenharmony_ci      for (let i: number = 0; i < obj.length; i++) {
694d6c458bSopenharmony_ci        keys.push(i.toString());
704d6c458bSopenharmony_ci      }
714d6c458bSopenharmony_ci      return keys;
724d6c458bSopenharmony_ci    }
734d6c458bSopenharmony_ci    defineProperty(): boolean {
744d6c458bSopenharmony_ci      return true;
754d6c458bSopenharmony_ci    }
764d6c458bSopenharmony_ci    getOwnPropertyDescriptor(obj: Deque<T>, prop: string): Object {
774d6c458bSopenharmony_ci      this.isOutBounds(prop);
784d6c458bSopenharmony_ci      let index: number = Number.parseInt(prop);
794d6c458bSopenharmony_ci      if (index >= 0 && Number.isInteger(index)) {
804d6c458bSopenharmony_ci        return Object.getOwnPropertyDescriptor(obj, prop);
814d6c458bSopenharmony_ci      }
824d6c458bSopenharmony_ci      return Object;
834d6c458bSopenharmony_ci    }
844d6c458bSopenharmony_ci    setPrototypeOf(): T {
854d6c458bSopenharmony_ci      throw new Error(`Can't setPrototype on Deque Object`);
864d6c458bSopenharmony_ci    }
874d6c458bSopenharmony_ci  }
884d6c458bSopenharmony_ci  interface IterableIterator<T> {
894d6c458bSopenharmony_ci    next: () => {
904d6c458bSopenharmony_ci      value: T;
914d6c458bSopenharmony_ci      done: boolean;
924d6c458bSopenharmony_ci    };
934d6c458bSopenharmony_ci  }
944d6c458bSopenharmony_ci  class Deque<T> {
954d6c458bSopenharmony_ci    private front: number;
964d6c458bSopenharmony_ci    private capacity: number;
974d6c458bSopenharmony_ci    private rear: number;
984d6c458bSopenharmony_ci    constructor() {
994d6c458bSopenharmony_ci      errorUtil.checkNewTargetIsNullError('Deque', !new.target);
1004d6c458bSopenharmony_ci      this.front = 0;
1014d6c458bSopenharmony_ci      this.capacity = 8;
1024d6c458bSopenharmony_ci      this.rear = 0;
1034d6c458bSopenharmony_ci      return new Proxy(this, new HandlerDeque());
1044d6c458bSopenharmony_ci    }
1054d6c458bSopenharmony_ci    get length(): number {
1064d6c458bSopenharmony_ci      let result: number = 0;
1074d6c458bSopenharmony_ci      result = (this.rear - this.front + this.capacity) % this.capacity;
1084d6c458bSopenharmony_ci      return result;
1094d6c458bSopenharmony_ci    }
1104d6c458bSopenharmony_ci    insertFront(element: T): void {
1114d6c458bSopenharmony_ci      errorUtil.checkBindError('insertFront', Deque, this);
1124d6c458bSopenharmony_ci      if (this.isFull()) {
1134d6c458bSopenharmony_ci        this.increaseCapacity();
1144d6c458bSopenharmony_ci      }
1154d6c458bSopenharmony_ci      this.front = (this.front - 1 + this.capacity) % this.capacity;
1164d6c458bSopenharmony_ci      this[this.front] = element;
1174d6c458bSopenharmony_ci    }
1184d6c458bSopenharmony_ci    insertEnd(element: T): void {
1194d6c458bSopenharmony_ci      errorUtil.checkBindError('insertEnd', Deque, this);
1204d6c458bSopenharmony_ci      if (this.isFull()) {
1214d6c458bSopenharmony_ci        this.increaseCapacity();
1224d6c458bSopenharmony_ci      }
1234d6c458bSopenharmony_ci      this[this.rear] = element;
1244d6c458bSopenharmony_ci      this.rear = (this.rear + 1) % (this.capacity + 1);
1254d6c458bSopenharmony_ci    }
1264d6c458bSopenharmony_ci    getFirst(): T {
1274d6c458bSopenharmony_ci      errorUtil.checkBindError('getFirst', Deque, this);
1284d6c458bSopenharmony_ci      if (this.isEmpty()) {
1294d6c458bSopenharmony_ci        return undefined;
1304d6c458bSopenharmony_ci      }
1314d6c458bSopenharmony_ci      return this[this.front];
1324d6c458bSopenharmony_ci    }
1334d6c458bSopenharmony_ci    getLast(): T {
1344d6c458bSopenharmony_ci      errorUtil.checkBindError('getLast', Deque, this);
1354d6c458bSopenharmony_ci      if (this.isEmpty()) {
1364d6c458bSopenharmony_ci        return undefined;
1374d6c458bSopenharmony_ci      }
1384d6c458bSopenharmony_ci      return this[this.rear - 1];
1394d6c458bSopenharmony_ci    }
1404d6c458bSopenharmony_ci    has(element: T): boolean {
1414d6c458bSopenharmony_ci      errorUtil.checkBindError('has', Deque, this);
1424d6c458bSopenharmony_ci      let result: boolean = false;
1434d6c458bSopenharmony_ci      this.forEach(function (value) {
1444d6c458bSopenharmony_ci        if (value === element) {
1454d6c458bSopenharmony_ci          result = true;
1464d6c458bSopenharmony_ci        }
1474d6c458bSopenharmony_ci      });
1484d6c458bSopenharmony_ci      return result;
1494d6c458bSopenharmony_ci    }
1504d6c458bSopenharmony_ci    popFirst(): T {
1514d6c458bSopenharmony_ci      errorUtil.checkBindError('popFirst', Deque, this);
1524d6c458bSopenharmony_ci      if (this.isEmpty()) {
1534d6c458bSopenharmony_ci        return undefined;
1544d6c458bSopenharmony_ci      }
1554d6c458bSopenharmony_ci      let result: T = undefined;
1564d6c458bSopenharmony_ci      result = this[this.front];
1574d6c458bSopenharmony_ci      this.front = (this.front + 1) % (this.capacity + 1);
1584d6c458bSopenharmony_ci      return result;
1594d6c458bSopenharmony_ci    }
1604d6c458bSopenharmony_ci    popLast(): T {
1614d6c458bSopenharmony_ci      errorUtil.checkBindError('popLast', Deque, this);
1624d6c458bSopenharmony_ci      if (this.isEmpty()) {
1634d6c458bSopenharmony_ci        return undefined;
1644d6c458bSopenharmony_ci      }
1654d6c458bSopenharmony_ci      let result: T = undefined;
1664d6c458bSopenharmony_ci      result = this[this.rear - 1];
1674d6c458bSopenharmony_ci      this.rear = (this.rear + this.capacity) % (this.capacity + 1);
1684d6c458bSopenharmony_ci      return result;
1694d6c458bSopenharmony_ci    }
1704d6c458bSopenharmony_ci    forEach(callbackfn: (value: T, index?: number, deque?: Deque<T>) => void,
1714d6c458bSopenharmony_ci      thisArg?: Object): void {
1724d6c458bSopenharmony_ci      errorUtil.checkBindError('forEach', Deque, this);
1734d6c458bSopenharmony_ci      errorUtil.checkTypeError('callbackfn', 'callable', callbackfn);
1744d6c458bSopenharmony_ci      let k: number = 0;
1754d6c458bSopenharmony_ci      let i: number = this.front;
1764d6c458bSopenharmony_ci      while (true) {
1774d6c458bSopenharmony_ci        callbackfn.call(thisArg, this[i], k, this);
1784d6c458bSopenharmony_ci        i = (i + 1) % this.capacity;
1794d6c458bSopenharmony_ci        k++;
1804d6c458bSopenharmony_ci        if (i === this.rear) {
1814d6c458bSopenharmony_ci          break;
1824d6c458bSopenharmony_ci        }
1834d6c458bSopenharmony_ci      }
1844d6c458bSopenharmony_ci    }
1854d6c458bSopenharmony_ci    private increaseCapacity(): void {
1864d6c458bSopenharmony_ci      let count: number = 0;
1874d6c458bSopenharmony_ci      let arr: Array<T> = [];
1884d6c458bSopenharmony_ci      let length: number = this.length;
1894d6c458bSopenharmony_ci      while (true) {
1904d6c458bSopenharmony_ci        arr[count++] = this[this.front];
1914d6c458bSopenharmony_ci        this.front = (this.front + 1) % this.capacity;
1924d6c458bSopenharmony_ci        if (this.front === this.rear) {
1934d6c458bSopenharmony_ci          break;
1944d6c458bSopenharmony_ci        }
1954d6c458bSopenharmony_ci      }
1964d6c458bSopenharmony_ci      for (let i: number = 0; i < length; i++) {
1974d6c458bSopenharmony_ci        this[i] = arr[i];
1984d6c458bSopenharmony_ci      }
1994d6c458bSopenharmony_ci      this.capacity = 2 * this.capacity; // 2 : means number
2004d6c458bSopenharmony_ci      this.front = 0;
2014d6c458bSopenharmony_ci      this.rear = length;
2024d6c458bSopenharmony_ci    }
2034d6c458bSopenharmony_ci    private isFull(): boolean {
2044d6c458bSopenharmony_ci      return (this.rear + 1) % this.capacity === this.front;
2054d6c458bSopenharmony_ci    }
2064d6c458bSopenharmony_ci    private isEmpty(): boolean {
2074d6c458bSopenharmony_ci      return this.length === 0;
2084d6c458bSopenharmony_ci    }
2094d6c458bSopenharmony_ci    [Symbol.iterator](): IterableIterator<T> {
2104d6c458bSopenharmony_ci      errorUtil.checkBindError('Symbol.iterator', Deque, this);
2114d6c458bSopenharmony_ci      let count: number = this.front;
2124d6c458bSopenharmony_ci      return {
2134d6c458bSopenharmony_ci        next: function (): { done: boolean, value: T } {
2144d6c458bSopenharmony_ci          let done: boolean = false;
2154d6c458bSopenharmony_ci          let value: T = undefined;
2164d6c458bSopenharmony_ci          done = count === this.rear;
2174d6c458bSopenharmony_ci          value = done ? undefined : this[count];
2184d6c458bSopenharmony_ci          count = (count + 1) % this.capacity;
2194d6c458bSopenharmony_ci          return {
2204d6c458bSopenharmony_ci            done: done,
2214d6c458bSopenharmony_ci            value: value,
2224d6c458bSopenharmony_ci          };
2234d6c458bSopenharmony_ci        },
2244d6c458bSopenharmony_ci      };
2254d6c458bSopenharmony_ci    }
2264d6c458bSopenharmony_ci  }
2274d6c458bSopenharmony_ci  Object.freeze(Deque);
2284d6c458bSopenharmony_ci  fastDeque = Deque;
2294d6c458bSopenharmony_ci}
2304d6c458bSopenharmony_ciexport default fastDeque;
231