• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 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 */
15
16const helpUtil = requireInternal('arkts.utils');
17let locks = helpUtil.locks;
18let ASON = helpUtil.ASON;
19let ConditionVariable = helpUtil.ConditionVariable;
20let isSendable = helpUtil.isSendable;
21
22export const typeErrorCode = 401;
23export class BusinessError extends Error {
24  code: number;
25  constructor(errorcode: number, msg: string) {
26    super(msg);
27    this.name = 'BusinessError';
28    this.code = errorcode;
29  }
30}
31
32class SendableLruCache {
33  // the following cache is a sendable instance of sendable map
34  private cache: SendableMap<Object, Object>;
35  // Default current size
36  private maxSize: number = 64;
37  // Default maximum size
38  private maxNumber: number = 2147483647;
39  private putCount: number = 0;
40  private createCount: number = 0;
41  private evictionCount: number = 0;
42  private hitCount: number = 0;
43  private missCount: number = 0;
44  public length: number = 0;
45
46  public constructor(capacity?: number) {
47    'use sendable';
48    if (capacity !== undefined && capacity !== null) {
49      if (capacity <= 0 || capacity % 1 !== 0 || capacity > this.maxNumber) {
50        let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${capacity} must be small integer`);
51        throw error;
52      }
53      this.maxSize = capacity;
54    }
55    this.cache = new SendableMap();
56  }
57
58  private changeCapacity(newCapacity: number): void {
59    while (this.cache.size > newCapacity) {
60      this.cache.delete(this.cache.keys().next().value);
61      this.evictionCount++;
62      this.afterRemoval(true, this.cache.keys(), this.cache.values(), null);
63    }
64  }
65
66  protected afterRemoval(isEvict: boolean, key: Object | undefined | null, value: Object | undefined | null,
67    newValue: Object | undefined | null): void {
68  }
69
70  protected createDefault(key: Object): Object | undefined {
71    if (typeof (key as Object) === 'undefined') {
72      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${key} must be Object`);
73      throw error;
74    }
75    return undefined;
76  }
77
78  public updateCapacity(newCapacity: number): void {
79    if (typeof newCapacity !== 'number') {
80      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${newCapacity} must be number`);
81      throw error;
82    }
83    if (newCapacity <= 0 || newCapacity % 1 !== 0 || newCapacity > this.maxNumber) {
84      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${newCapacity} must be small integer`);
85      throw error;
86    }
87    if (this.cache.size > newCapacity) {
88      this.changeCapacity(newCapacity);
89    }
90    this.length = this.cache.size;
91    this.maxSize = newCapacity;
92  }
93
94  public get(key: Object): Object | undefined {
95    if (typeof (key as Object) === 'undefined' || key === null) {
96      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${key} must be Object`);
97      throw error;
98    }
99    let value: Object;
100    if (this.cache.has(key)) {
101      value = this.cache.get(key);
102      this.hitCount++;
103      this.cache.delete(key);
104      this.cache.set(key, value);
105      return value;
106    }
107    this.missCount++;
108    let createValue: Object | undefined = this.createDefault(key);
109    if (createValue === undefined) {
110      return undefined;
111    } else {
112      value = this.put(key, createValue);
113      this.createCount++;
114      if (value !== undefined) {
115        this.put(key, value);
116        this.afterRemoval(false, key, createValue, value);
117        return value;
118      }
119      return createValue;
120    }
121  }
122
123  public put(key: Object, value: Object): Object | undefined {
124    if (typeof (key as Object) === 'undefined') {
125      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${key} must be Object`);
126      throw error;
127    }
128    if (typeof (value as Object) === 'undefined') {
129      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${value} must be Object`);
130      throw error;
131    }
132    if (key === null || value === null) {
133      let error = new BusinessError(typeErrorCode, `Parameter error. The type of key and value must be Object`);
134      throw error;
135    }
136    let former: Object | undefined = undefined;
137    this.putCount++;
138    if (this.cache.has(key)) {
139      former = this.cache.get(key);
140      this.cache.delete(key);
141      this.afterRemoval(false, key, former, value);
142    } else if (this.cache.size >= this.maxSize) {
143      this.afterRemoval(true, this.cache.keys().next().value, this.cache.values().next().value, null);
144      this.cache.delete(this.cache.keys().next().value);
145      this.evictionCount++;
146    }
147    this.cache.set(key, value);
148    this.length = this.cache.size;
149    former = this.cache.get(key);
150    return former;
151  }
152
153  public remove(key: Object): Object | undefined {
154    if (typeof (key as Object) === 'undefined' || key === null) {
155      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${key} must be Object`);
156      throw error;
157    }
158    let former: Object = undefined;
159    if (this.cache.has(key)) {
160      former = this.cache.get(key);
161      this.cache.delete(key);
162      if (former !== null) {
163        this.afterRemoval(false, key, former, null);
164        this.length = this.cache.size;
165      }
166    } else {
167      this.length = this.cache.size;
168    }
169    return former;
170  }
171
172  public contains(key: Object): boolean {
173    if (typeof (key as Object) === 'undefined') {
174      let error = new BusinessError(typeErrorCode, `Parameter error. The type of ${key} must be Object`);
175      throw error;
176    }
177    let flag: boolean = false;
178    if (this.cache.has(key)) {
179      flag = true;
180      this.hitCount++;
181      let value: Object = this.cache.get(key);
182      this.cache.delete(key);
183      this.cache.set(key, value);
184      this.length = this.cache.size;
185    } else {
186      this.missCount++;
187    }
188    return flag;
189  }
190
191  public getCreateCount(): number {
192    return this.createCount;
193  }
194
195  public getMissCount(): number {
196    return this.missCount;
197  }
198
199  public getRemoveCount(): number {
200    return this.evictionCount;
201  }
202
203  public getMatchCount(): number {
204    return this.hitCount;
205  }
206
207  public getPutCount(): number {
208    return this.putCount;
209  }
210
211  public getCapacity(): number {
212    return this.maxSize;
213  }
214
215  public clear(): void {
216    this.afterRemoval(false, this.cache.keys(), this.cache.values(), null);
217    this.cache.clear();
218    this.length = this.cache.size;
219  }
220
221  public isEmpty(): boolean {
222    return this.cache.size === 0;
223  }
224
225  public toString(): string {
226    let peek: number = 0;
227    let hitRate: number = 0;
228    let str: string = '';
229    peek = this.hitCount + this.missCount;
230    if (peek !== 0) {
231      // The value is 100 times larger
232      hitRate = 100 * this.hitCount / peek;
233    }
234    str = 'SendableLruCache[ maxSize = ' + this.maxSize + ', hits = ' + this.hitCount +
235      ', misses = ' + this.missCount + ', hitRate = ' + hitRate + '% ]';
236    return str;
237  }
238
239  public values(): Object[] {
240    let arr: Array<Object> = [];
241    for (let value of this.cache.values()) {
242      arr.push(value);
243    }
244    return arr;
245  }
246
247  public keys(): Object[] {
248    let arr: Array<Object> = [];
249    for (let key of this.cache.keys()) {
250      arr.push(key);
251    }
252    return arr;
253  }
254
255  public entries(): IterableIterator<[Object, Object]> {
256    return this.cache.entries();
257  }
258
259  public [Symbol.iterator](): IterableIterator<[Object, Object]> {
260    return this.cache.entries();
261  }
262}
263
264export default {
265  SendableLruCache: SendableLruCache,
266  locks: locks,
267  ASON: ASON,
268  ConditionVariable: ConditionVariable,
269  isSendable: isSendable,
270};
271