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 */
15declare function requireNapi(s: string): any;
16interface ArkPrivate {
17  LightWeightSet: number;
18  Load(key: number): Object;
19}
20let flag: boolean = false;
21let fastLightWeightSet: Object = undefined;
22let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined;
23if (arkPritvate !== undefined) {
24  fastLightWeightSet = arkPritvate.Load(arkPritvate.LightWeightSet);
25} else {
26  flag = true;
27}
28if (flag || fastLightWeightSet === undefined) {
29  const lightWeightAbility = requireNapi('util.struct');
30  const errorUtil = lightWeightAbility.errorUtil;
31  interface IterableIterator<T> {
32    next: () => {
33      value: T | undefined;
34      done: boolean;
35    };
36  }
37  class HandlerLightWeightSet<T> {
38    set(target: LightWeightSet<T>, p: string, value: string): boolean {
39      if (p in target) {
40        target[p] = value;
41        return true;
42      }
43      return false;
44    }
45    defineProperty(): boolean {
46      throw new Error(`Can't define Property on LightWeightSet Object`);
47    }
48    deleteProperty(): boolean {
49      throw new Error(`Can't delete Property on LightWeightSet Object`);
50    }
51    setPrototypeOf(): boolean {
52      throw new Error(`Can't set Prototype on LightWeightSet Object`);
53    }
54  }
55  class LightWeightSet<T> extends lightWeightAbility.LightWeightClass<T, T> {
56    constructor() {
57      errorUtil.checkNewTargetIsNullError('LightWeightSet', !new.target);
58      super();
59      return new Proxy(this, new HandlerLightWeightSet());
60    }
61    get length(): number {
62      return this.memberNumber;
63    }
64    add(obj: T): boolean {
65      errorUtil.checkBindError('add', LightWeightSet, this);
66      if (this.members.keys.indexOf(obj) > 0) {
67        return false;
68      }
69      this.addmember(obj);
70      return true;
71    }
72    addAll(set: LightWeightSet<T>): boolean {
73      errorUtil.checkBindError('addAll', LightWeightSet, this);
74      errorUtil.checkTypeError('set', 'LightWeightSet', set);
75      if (!(set instanceof LightWeightSet)) {
76        throw new TypeError('Incoming object is not JSAPILightWeightSet');
77      }
78      let change: boolean = false;
79      if (set.memberNumber === 0) {
80        change = false;
81      } else {
82        for (let i: number = 0; i < set.memberNumber; i++) {
83          change = this.add(set.members.keys[i]) || change;
84        }
85      }
86      return change;
87    }
88    hasAll(set: LightWeightSet<T>): boolean {
89      errorUtil.checkBindError('hasAll', LightWeightSet, this);
90      errorUtil.checkTypeError('set', 'LightWeightSet', set);
91      if (set.memberNumber > this.memberNumber) {
92        return false;
93      }
94      if (lightWeightAbility.isIncludeToArray(this.members.keys, set.members.keys)) {
95        return true;
96      }
97      return false;
98    }
99    has(key: T): boolean {
100      errorUtil.checkBindError('has', LightWeightSet, this);
101      return this.members.keys.indexOf(key) > -1;
102    }
103    equal(obj: Object): boolean {
104      errorUtil.checkBindError('equal', LightWeightSet, this);
105      if (this.memberNumber === 0) {
106        return false;
107      }
108      if (obj instanceof LightWeightSet) {
109        return JSON.stringify(obj.members.keys) === JSON.stringify(this.members.keys);
110      }
111      if (JSON.stringify(obj) === JSON.stringify(this.members.keys)) {
112        return true;
113      }
114      return false;
115    }
116    increaseCapacityTo(minimumCapacity: number): void {
117      errorUtil.checkBindError('increaseCapacityTo', LightWeightSet, this);
118      errorUtil.checkTypeError('minimumCapacity', 'Integer', minimumCapacity);
119      errorUtil.checkRangeError('minimumCapacity', minimumCapacity, this.capacity,
120        undefined, '!=min');
121      super.ensureCapacity(minimumCapacity);
122    }
123    getIndexOf(key: T): number {
124      errorUtil.checkBindError('getIndexOf', LightWeightSet, this);
125      return super.getIndexByKey(key);
126    }
127    isEmpty(): boolean {
128      errorUtil.checkBindError('isEmpty', LightWeightSet, this);
129      return this.memberNumber === 0;
130    }
131    remove(key: T): T {
132      errorUtil.checkBindError('remove', LightWeightSet, this);
133      return super.deletemember(key);
134    }
135    removeAt(index: number): boolean {
136      errorUtil.checkBindError('removeAt', LightWeightSet, this);
137      errorUtil.checkTypeError('index', 'Integer', index);
138      if (index > this.memberNumber--) {
139        return false;
140      }
141      this.members.hashs.splice(index, 1);
142      this.members.values.splice(index, 1);
143      this.members.keys.splice(index, 1);
144      this.memberNumber--;
145      return true;
146    }
147    clear(): void {
148      errorUtil.checkBindError('clear', LightWeightSet, this);
149      if (this.memberNumber !== 0 || this.capacity > 8) { // 8 : means number
150        this.members.hashs = [];
151        this.members.keys = [];
152        this.members.values = [];
153        this.memberNumber = 0;
154        this.capacity = 8; // 8 : means number
155      }
156    }
157    forEach(callbackfn: (value?: T, key?: T, set?: LightWeightSet<T>) => void,
158      thisArg?: Object): void {
159      errorUtil.checkBindError('forEach', LightWeightSet, this);
160      errorUtil.checkTypeError('callbackfn', 'callable', callbackfn);
161      for (let i: number = 0; i < this.memberNumber; i++) {
162        callbackfn.call(thisArg, this.members.keys[i], this.members.keys[i], this);
163      }
164    }
165    [Symbol.iterator](): IterableIterator<T> {
166      errorUtil.checkBindError('Symbol.iterator', LightWeightSet, this);
167      let count: number = 0;
168      return {
169        next: function (): { done: boolean, value: T } {
170          let done: boolean = false;
171          let value: T = undefined;
172          done = count >= this.memberNumber;
173          value = done ? undefined : this.members.keys[count];
174          count++;
175          return {
176            done: done,
177            value: value,
178          };
179        },
180      };
181    }
182    toString(): string {
183      errorUtil.checkBindError('toString', LightWeightSet, this);
184      return this.members.keys.join(',');
185    }
186    toArray(): Array<T> {
187      errorUtil.checkBindError('toArray', LightWeightSet, this);
188      return this.members.keys.slice();
189    }
190    getValueAt(index: number): T {
191      errorUtil.checkBindError('getValueAt', LightWeightSet, this);
192      errorUtil.checkTypeError('index', 'Integer', index);
193      return this.members.keys[index];
194    }
195    values(): IterableIterator<T> {
196      errorUtil.checkBindError('values', LightWeightSet, this);
197      return this.members.keys.values() as IterableIterator<T>;
198    }
199    entries(): IterableIterator<[T, T]> {
200      errorUtil.checkBindError('entries', LightWeightSet, this);
201      let count: number = 0;
202      return {
203        next: function (): { done: boolean, value: [T, T] } {
204          let done: boolean = false;
205          let value: [T, T] = undefined;
206          let tempValue: T = undefined;
207          done = count >= this.memberNumber;
208          tempValue = this.members.keys[count];
209          value = done ? undefined : ([tempValue, tempValue] as [T, T]);
210          count++;
211          return {
212            done: done,
213            value: value,
214          };
215        },
216      };
217    }
218  }
219  Object.freeze(LightWeightSet);
220  fastLightWeightSet = LightWeightSet;
221}
222export default fastLightWeightSet;
223