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  LightWeightMap: number;
18  Load(key: number): Object;
19}
20let flag: boolean = false;
21let fastLightWeightMap: Object = undefined;
22let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined;
23if (arkPritvate !== undefined) {
24  fastLightWeightMap = arkPritvate.Load(arkPritvate.LightWeightMap);
25} else {
26  flag = true;
27}
28if (flag || fastLightWeightMap === 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 HandlerLightWeightMap<K, V> {
38    set(target: LightWeightMap<K, V>, 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 LightWeightMap Object`);
47    }
48    deleteProperty(): boolean {
49      throw new Error(`Can't delete Property on LightWeightMap Object`);
50    }
51    setPrototypeOf(): boolean {
52      throw new Error(`Can't set Prototype on LightWeightMap Object`);
53    }
54  }
55  class LightWeightMap<K, V> extends lightWeightAbility.LightWeightClass<K, V> {
56    constructor() {
57      errorUtil.checkNewTargetIsNullError('LightWeightMap', !new.target);
58      super();
59      return new Proxy(this, new HandlerLightWeightMap());
60    }
61    get length(): number {
62      return this.memberNumber;
63    }
64    hasAll(map: LightWeightMap<K, V>): boolean {
65      errorUtil.checkBindError('hasAll', LightWeightMap, this);
66      errorUtil.checkTypeError('map', 'LightWeightMap', map);
67      if (!(map instanceof LightWeightMap)) {
68        throw new TypeError('map is not JSAPILightWeightMap');
69      }
70      if (map.memberNumber > this.memberNumber) {
71        return false;
72      }
73      if (lightWeightAbility.isIncludeToArray(this.keyValueStringArray(), map.keyValueStringArray())) {
74        return true;
75      }
76      return false;
77    }
78    hasKey(key: K): boolean {
79      errorUtil.checkBindError('hasKey', LightWeightMap, this);
80      return this.members.keys.indexOf(key) > -1;
81    }
82    hasValue(value: V): boolean {
83      errorUtil.checkBindError('hasValue', LightWeightMap, this);
84      return this.members.values.indexOf(value) > -1;
85    }
86    increaseCapacityTo(minimumCapacity: number): void {
87      errorUtil.checkBindError('increaseCapacityTo', LightWeightMap, this);
88      errorUtil.checkTypeError('minimumCapacity', 'Integer', minimumCapacity);
89      super.ensureCapacity(minimumCapacity);
90    }
91    entries(): IterableIterator<[K, V]> {
92      errorUtil.checkBindError('entries', LightWeightMap, this);
93      let count: number = 0;
94      return {
95        next: function (): { done: boolean, value: [K, V] } {
96          let done: boolean = false;
97          let value: [K, V] = undefined;
98          done = count >= this.memberNumber;
99          value = done ? undefined : [this.members.keys[count], this.members.values[count]] as [K, V];
100          count++;
101          return {
102            done: done,
103            value: value,
104          };
105        },
106      };
107    }
108    get(key: K): V {
109      errorUtil.checkBindError('get', LightWeightMap, this);
110      let index: number = 0;
111      index = this.getIndexByKey(key);
112      return this.members.values[index];
113    }
114    getIndexOfKey(key: K): number {
115      errorUtil.checkBindError('getIndexOfKey', LightWeightMap, this);
116      return this.getIndexByKey(key);
117    }
118    getIndexOfValue(value: V): number {
119      errorUtil.checkBindError('getIndexOfValue', LightWeightMap, this);
120      return this.members.values.indexOf(value);
121    }
122    isEmpty(): boolean {
123      errorUtil.checkBindError('isEmpty', LightWeightMap, this);
124      return this.memberNumber === 0;
125    }
126    getKeyAt(index: number): K {
127      errorUtil.checkBindError('getKeyAt', LightWeightMap, this);
128      errorUtil.checkTypeError('index', 'Integer', index);
129      errorUtil.checkRangeError('index', index, 0, this.length - 1);
130      return this.members.keys[index];
131    }
132    keys(): IterableIterator<K> {
133      errorUtil.checkBindError('keys', LightWeightMap, this);
134      let count: number = 0;
135      return {
136        next: function (): { done: boolean, value: K } {
137          let done: boolean = false;
138          let value: K = undefined;
139          done = count >= this.memberNumber;
140          value = done ? undefined : this.members.keys[count];
141          count++;
142          return {
143            done: done,
144            value: value,
145          };
146        },
147      };
148    }
149    setAll(map: LightWeightMap<K, V>): void {
150      errorUtil.checkBindError('setAll', LightWeightMap, this);
151      errorUtil.checkTypeError('map', 'LightWeightMap', map);
152      if (this.memberNumber === 0) {
153        this.members.hashs = map.members.hashs.slice();
154        this.members.keys = map.members.keys.slice();
155        this.members.values = map.members.values.slice();
156        this.memberNumber = map.memberNumber;
157      } else {
158        for (let i: number = 0; i < map.memberNumber; i++) {
159          this.addmember(map.members.keys[i], map.members.values[i]);
160        }
161      }
162    }
163    set(key: K, value: V): Object {
164      errorUtil.checkBindError('set', LightWeightMap, this);
165      this.addmember(key, value);
166      return this;
167    }
168    remove(key: K): V {
169      errorUtil.checkBindError('remove', LightWeightMap, this);
170      return this.deletemember(key);
171    }
172    removeAt(index: number): boolean {
173      errorUtil.checkBindError('removeAt', LightWeightMap, this);
174      errorUtil.checkTypeError('index', 'Integer', index);
175      if (index > this.memberNumber--) {
176        return false;
177      }
178      this.members.hashs.splice(index, 1);
179      this.members.values.splice(index, 1);
180      this.members.keys.splice(index, 1);
181      this.memberNumber--;
182      return true;
183    }
184    clear(): void {
185      errorUtil.checkBindError('clear', LightWeightMap, this);
186      if (this.memberNumber !== 0 || this.capacity > 8) { // 8 : means number
187        this.members.hashs = [];
188        this.members.keys = [];
189        this.members.values = [];
190        this.memberNumber = 0;
191        this.capacity = 8;
192      }
193    }
194    setValueAt(index: number, newValue: V): boolean {
195      errorUtil.checkBindError('setValueAt', LightWeightMap, this);
196      errorUtil.checkTypeError('index', 'Integer', index);
197      errorUtil.checkRangeError('index', index, 0, this.length - 1);
198      if (index > this.memberNumber || this.members.values[index] === undefined) {
199        return false;
200      }
201      this.members.values[index] = newValue;
202      return true;
203    }
204    forEach(callbackfn: (value?: V, key?: K, map?: LightWeightMap<K, V>) => void,
205      thisArg?: Object): void {
206      errorUtil.checkBindError('forEach', LightWeightMap, this);
207      errorUtil.checkTypeError('callbackfn', 'callable', callbackfn);
208      for (let i: number = 0; i < this.memberNumber; i++) {
209        callbackfn.call(thisArg, this.members.values[i], this.members.keys[i], this);
210      }
211    }
212    [Symbol.iterator](): IterableIterator<[K, V]> {
213      errorUtil.checkBindError('Symbol.iterator', LightWeightMap, this);
214      return this.entries();
215    }
216    toString(): string {
217      errorUtil.checkBindError('toString', LightWeightMap, this);
218      let result: string[] = [];
219      for (let i: number = 0; i < this.memberNumber; i++) {
220        result.push(this.members.keys[i] + ':' + this.members.values[i]);
221      }
222      return result.join(',');
223    }
224    getValueAt(index: number): V {
225      errorUtil.checkBindError('getValueAt', LightWeightMap, this);
226      errorUtil.checkTypeError('index', 'Integer', index);
227      errorUtil.checkRangeError('index', index, 0, this.length - 1);
228      return this.members.values[index];
229    }
230    values(): IterableIterator<V> {
231      errorUtil.checkBindError('values', LightWeightMap, this);
232      let count: number = 0;
233      return {
234        next: function (): { done: boolean, value: V } {
235          let done: boolean = false;
236          let value: V = undefined;
237          done = count >= this.memberNumber;
238          value = done ? undefined : this.members.values[count];
239          count++;
240          return {
241            done: done,
242            value: value,
243          };
244        },
245      };
246    }
247  }
248  Object.freeze(LightWeightMap);
249  fastLightWeightMap = LightWeightMap;
250}
251export default fastLightWeightMap;
252