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 */
15type CompFun<T> = (firstValue: T, secondValue: T) => boolean;
16
17function hashCode(element: Object): number {
18  let str: string = '';
19  str = String(element);
20  let hash: number = 0;
21  if (hash === 0 && str.length > 0) {
22    for (let i: number = 0; i < str.length; i++) {
23      let char: number = 0;
24      char = str.charCodeAt(i);
25      hash = ((hash << 5) - hash) + char; // 5 : means number
26      hash = hash & hash;
27    }
28  }
29  return hash;
30}
31function insert<T>(a: Array<T>, index: number, value: T): void {
32  for (let i: number = a.length; i > index; i--) {
33    a[i] = a[i - 1];
34  }
35  a[index] = value;
36}
37enum ComparResult {
38  LESS_THAN = -1,
39  BIGGER_THAN = 1,
40  EQUALS = 0
41}
42function compareToString(string1: String, string2: String): number {
43  let len1: number = string1.length;
44  let len2: number = string2.length;
45  let lim: number = 0;
46  lim = (len1 > len2 ? len2 : len1);
47  let k: number = 0;
48  while (k < lim) {
49    if (string1.charCodeAt(k) === string2.charCodeAt(k)) {
50      k++;
51      if (k === lim) {
52        return len1 > len2 ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN;
53      }
54      continue;
55    }
56    return string1.charCodeAt(k) > string2.charCodeAt(k) ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN;
57  }
58  throw new Error('this compare function run error');
59}
60function currencyCompare(a: string | Object, b: string | Object, compareFn?: CompFun<string | Object>): number {
61  if (a === b) {
62    return ComparResult.EQUALS;
63  }
64  if (a instanceof Pair && b instanceof Pair) {
65    return currencyCompare(a.key, b.key, compareFn);
66  }
67  if (compareFn !== undefined) {
68    return compareFn(a, b) ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN;
69  }
70  if (typeof a === 'number' && typeof b === 'number') {
71    if (a > b) {
72      return ComparResult.BIGGER_THAN;
73    } else {
74      return ComparResult.LESS_THAN;
75    }
76  } else if (typeof a === 'string' && typeof b === 'string') {
77    return compareToString(a, b);
78  } else if (typeof a === 'string' && typeof b === 'number') {
79    return ComparResult.BIGGER_THAN;
80  } else if (typeof a === 'number' && typeof b === 'string') {
81    return ComparResult.LESS_THAN;
82  }
83  throw new Error('This form of comparison is not supported');
84}
85function isIncludeToArray(array1: Array<number>, array2: Array<number>): boolean {
86  let newList: number[] = [];
87  newList = array1.filter((val) => {
88    return array2.indexOf(val) > -1;
89  });
90  if (newList.length === array2.length) {
91    return true;
92  }
93  return false;
94}
95class Pair<K, V> {
96  key: K;
97  value: V;
98  constructor(key: K, value: V = key as unknown as V) {
99    this.key = key;
100    this.value = value;
101  }
102  entry(): [K, V] {
103    return [this.key, this.value];
104  }
105  toString(): string {
106    return `[#${this.key}: ${this.value}]`;
107  }
108}
109class PlainArrayMembers<T> {
110  keys: Array<number>;
111  values: Array<T>;
112  constructor() {
113    this.keys = [];
114    this.values = [];
115  }
116}
117class PlainArrayClass<T> {
118  protected memberNumber: number;
119  protected members: PlainArrayMembers<T>;
120  constructor() {
121    this.memberNumber = 0;
122    this.members = new PlainArrayMembers<T>();
123  }
124  protected addmember(key: number, value: T): void {
125    let index: number = 0;
126    index = this.binarySearchAtPlain(key);
127    if (index >= 0) {
128      this.members.keys[index] = key;
129      this.members.values[index] = value;
130    } else {
131      index = ~index;
132      insert(this.members.keys, index, key);
133      insert(this.members.values, index, value);
134      this.memberNumber++;
135    }
136  }
137  protected deletemember(index: number, safeSize: number = 1): T {
138    this.memberNumber -= safeSize;
139    this.members.keys.splice(index, safeSize);
140    let removeValue = this.members.values.splice(index, safeSize)[0];
141    return removeValue;
142  }
143  protected binarySearchAtPlain(key: number, startIndex: number = 0, endIndex: number = this.memberNumber): number {
144    let low: number = startIndex;
145    let high: number = endIndex - 1;
146    while (low <= high) {
147      let mid: number = (low + high) >>> 1;
148      let midVal: number = this.members.keys[mid];
149      if (midVal < key) {
150        low = mid + 1;
151      } else {
152        if (midVal <= key) {
153          return mid;
154        }
155        high = mid - 1;
156      }
157    }
158    return -(low + 1);
159  }
160}
161class LightWeightMembers<K, V> {
162  hashs: Array<number>;
163  keys: Array<K>;
164  values: Array<V>;
165  constructor() {
166    this.hashs = [];
167    this.keys = [];
168    this.values = [];
169  }
170}
171class LightWeightClass<K, V> {
172  protected memberNumber: number;
173  protected members: LightWeightMembers<K, V>;
174  protected capacity: number = 8; // 8 : means number
175  constructor() {
176    this.memberNumber = 0;
177    this.members = new LightWeightMembers<K, V>();
178  }
179  protected addmember(key: K, value: V = key as unknown as V): void {
180    let hash: number = 0;
181    hash = hashCode(key);
182    let index: number = 0;
183    index = this.binarySearchAtLightWeight(hash);
184    if (index >= 0) {
185      this.members.keys[index] = key;
186      this.members.values[index] = value;
187    } else {
188      index = ~index;
189      insert(this.members.hashs, index, hash);
190      insert(this.members.keys, index, key);
191      insert(this.members.values, index, value);
192      this.memberNumber++;
193    }
194    if (this.capacity < this.memberNumber) {
195      this.ensureCapacity(1);
196    }
197  }
198  protected getIndexByKey(key: K): number {
199    let hash: number = 0;
200    hash = hashCode(key);
201    let index: number = 0;
202    index = this.binarySearchAtLightWeight(hash);
203    // js ( A negative number indicates an inverted number in the array )
204    if (index < 0 || index >= this.memberNumber) {
205      return -1;
206    }
207    return index;
208  }
209  protected deletemember(key: K): V {
210    let result: V = undefined;
211    let index: number = 0;
212    index = this.getIndexByKey(key);
213    if (index < 0) {
214      return result;
215    }
216    this.memberNumber--;
217    this.members.hashs.splice(index, 1);
218    this.members.keys.splice(index, 1);
219    return this.members.values.splice(index, 1)[0];
220  }
221  protected ensureCapacity(addCapacity: number = 1): void {
222    let tempCapacity: number = 0;
223    tempCapacity = this.capacity + addCapacity;
224    while (this.capacity < tempCapacity) {
225      this.capacity = 2 * this.capacity; // 2 : means number
226    }
227  }
228  protected getIndex(key: K): number {
229    let hash: number = 0;
230    hash = hashCode(key);
231    let index: number = 0;
232    index = this.binarySearchAtLightWeight(hash);
233    if (index < 0) {
234      index = ~index;
235    }
236    return index;
237  }
238  protected keyValueStringArray(): Array<string> {
239    let resultArray: Array<string> = [];
240    for (let i: number = 0; i < this.memberNumber; i++) {
241      resultArray.push(JSON.stringify(this.members.keys[i]) + ':' + JSON.stringify(this.members.values[i]));
242    }
243    return resultArray;
244  }
245  protected binarySearchAtLightWeight(hash: number, startIndex: number = 0, endIndex: number = this.memberNumber): number {
246    let low: number = startIndex;
247    let high: number = endIndex - 1;
248    while (low <= high) {
249      let mid: number = 0;
250      mid = (low + high) >>> 1;
251      let midVal: number = 0;
252      midVal = this.members.hashs[mid];
253      if (midVal < hash) {
254        low = mid + 1;
255      } else {
256        if (midVal <= hash) {
257          return mid;
258        }
259        high = mid - 1;
260      }
261    }
262    return -(low + 1);
263  }
264}
265type RBTreeNodeColor = 0 | 1;
266const BLACK = 0;
267const RED = 1;
268class TreeNode<K, V> extends Pair<K, V> {
269  color: RBTreeNodeColor;
270  left: TreeNode<K, V> | undefined;
271  right: TreeNode<K, V> | undefined;
272  parent: TreeNode<K, V> | undefined;
273  constructor(key: K,
274    value?: V,
275    color: RBTreeNodeColor = RED,
276    parent?: TreeNode<K, V>,
277    left?: TreeNode<K, V>,
278    right?: TreeNode<K, V>) {
279    super(key, value);
280    this.color = color;
281    this.left = left;
282    this.right = right;
283    this.parent = parent;
284  }
285}
286class TreeClass<K, V> {
287  private root: TreeNode<K, V> | undefined;
288  public memberNumber: number;
289  private isChange: boolean;
290  private treeNodeArray: Array<TreeNode<K, V>>;
291  private compFun: CompFun<K> | undefined;
292  constructor(comparator?: CompFun<K>, root?: TreeNode<K, V>) {
293    this.root = root;
294    this.compFun = comparator;
295    this.memberNumber = 0;
296    this.isChange = true;
297    this.treeNodeArray = [];
298  }
299  get keyValueArray(): Array<TreeNode<K, V>> {
300    let result: Array<TreeNode<K, V>> = [];
301    result = this.recordByMinToMax();
302    return result;
303  }
304  addNode(key: K, value: V = key as unknown as V): TreeClass<K, V> {
305    if (this.root === undefined) {
306      this.root = new TreeNode<K, V>(key, value);
307      this.setColor(BLACK, this.root);
308      this.memberNumber++;
309      this.isChange = true;
310    } else {
311      this.addProcess(key, value);
312    }
313    return this;
314  }
315  addProcess(key: K, value: V): TreeClass<K, V> {
316    let leafNode: TreeNode<K, V> | undefined = this.root;
317    let parentNode: TreeNode<K, V> = this.root as TreeNode<K, V>;
318    let comp: number = 0;
319    while (leafNode !== undefined) {
320      parentNode = leafNode;
321      comp = currencyCompare(leafNode.key, key, this.compFun);
322      if (comp === 0) {
323        leafNode.value = value;
324        return this;
325      } else if (comp < 0) {
326        leafNode = leafNode.right;
327      } else {
328        leafNode = leafNode.left;
329      }
330    }
331    leafNode = new TreeNode<K, V>(key, value);
332    leafNode.parent = parentNode;
333    if (comp < 0) {
334      parentNode.right = leafNode;
335    } else {
336      parentNode.left = leafNode;
337    }
338    this.insertRebalance(leafNode);
339    this.memberNumber++;
340    this.isChange = true;
341    return this;
342  }
343  removeNode(key: K): V | undefined {
344    let removeNode: TreeNode<K, V> | undefined = undefined;
345    removeNode = this.getNode(key);
346    if (removeNode === undefined) {
347      return undefined;
348    } else {
349      let result: V = removeNode.value;
350      this.removeNodeProcess(removeNode);
351      return result;
352    }
353  }
354  removeNodeProcess(removeNode: TreeNode<K, V>): void {
355    if (removeNode.left !== undefined && removeNode.right !== undefined) {
356      let successor: TreeNode<K, V> | undefined = removeNode.right;
357      while (successor.left !== undefined) {
358        successor = successor.left;
359      }
360      removeNode.key = successor.key;
361      removeNode.value = successor.value;
362      this.removeNodeProcess(successor); // only once
363      return;
364    } else { // one or zero child
365      let child: TreeNode<K, V> | undefined = undefined;
366      child = (removeNode.left === undefined ? removeNode.right : removeNode.left);
367      if (removeNode.parent === undefined) { // remove is root
368        if (child === undefined) {
369          this.root = undefined;
370        } else {
371          child.parent = undefined;
372          child.color = BLACK;
373          this.root = child;
374        }
375      } else {
376        if (child !== undefined) {
377          // delete removeNode
378          if (removeNode.parent.left === removeNode) {
379            removeNode.parent.left = child;
380          } else {
381            removeNode.parent.right = child;
382          }
383          if (this.getColor(removeNode) === BLACK) {
384            this.deleteRebalance(child);
385          }
386        } else {
387          if (this.getColor(removeNode) === BLACK) {
388            this.deleteRebalance(removeNode);
389          }
390          if (removeNode.parent.left === removeNode) {
391            removeNode.parent.left = child;
392          } else {
393            removeNode.parent.right = child;
394          }
395        }
396      }
397      this.memberNumber--;
398      this.isChange = true;
399    }
400  }
401  getNode(key: K): TreeNode<K, V> | undefined {
402    if (this.root === undefined) {
403      return undefined;
404    }
405    let findNode: TreeNode<K, V> | undefined = this.root;
406    while (findNode !== undefined && findNode.key !== key) {
407      findNode = currencyCompare(findNode.key, key, this.compFun) === ComparResult.BIGGER_THAN ?
408        findNode.left : findNode.right;
409    }
410    return findNode;
411  }
412  findNode(value: V): TreeNode<K, V> | undefined {
413    let tempNode: TreeNode<K, V> | undefined = undefined;
414    this.recordByMinToMax();
415    for (let i: number = 0; i < this.memberNumber; i++) {
416      if (this.treeNodeArray[i].value === value) {
417        tempNode = this.treeNodeArray[i];
418        break;
419      }
420    }
421    return tempNode;
422  }
423  firstNode(): TreeNode<K, V> | undefined {
424    let tempNode: TreeNode<K, V> | undefined = this.root;
425    while (tempNode !== undefined && tempNode.left !== undefined) {
426      tempNode = tempNode.left;
427    }
428    return tempNode;
429  }
430  lastNode(): TreeNode<K, V> | undefined {
431    let tempNode: TreeNode<K, V> | undefined = this.root;
432    while (tempNode !== undefined && tempNode.right !== undefined) {
433      tempNode = tempNode.right;
434    }
435    return tempNode;
436  }
437  isEmpty(): boolean {
438    return this.root === undefined;
439  }
440  setAll(map: TreeClass<K, V>): void {
441    let tempArray: TreeNode<K, V>[] = [];
442    tempArray = map.recordByMinToMax();
443    for (let i: number = 0; i < map.memberNumber; i++) {
444      this.addNode(tempArray[i].key, tempArray[i].value);
445    }
446  }
447  clearTree(): void {
448    this.root = undefined;
449    this.memberNumber = 0;
450  }
451  private recordByMinToMax(): Array<TreeNode<K, V>> {
452    if (!this.isChange) {
453      return this.treeNodeArray;
454    }
455    let stack: Array<TreeNode<K, V>> = [];
456    this.treeNodeArray = [];
457    let node: TreeNode<K, V> | undefined = this.root;
458    while (node !== undefined || stack.length) {
459      while (node !== undefined) {
460        stack.push(node);
461        node = node.left;
462      }
463      let tempNode = stack.pop();
464      if (tempNode === undefined) {
465        throw new Error('this function run error');
466      }
467      node = tempNode;
468      this.treeNodeArray.push(node);
469      node = node.right;
470    }
471    this.isChange = false;
472    this.memberNumber = this.treeNodeArray.length;
473    return this.treeNodeArray;
474  }
475  private lRotate(datumPointNode: TreeNode<K, V>): TreeClass<K, V> {
476    let newTopNode: TreeNode<K, V> | undefined = datumPointNode.right;
477    if (newTopNode === undefined) {
478      throw new Error('[rotate right error]: the right child node of the base node === undefined');
479    }
480    datumPointNode.right = newTopNode.left;
481    datumPointNode.right !== undefined ? datumPointNode.right.parent = datumPointNode : '';
482    newTopNode.parent = datumPointNode.parent;
483    if (datumPointNode.parent === undefined) {
484      this.root = newTopNode;
485    } else if (datumPointNode.parent.left === datumPointNode) {
486      datumPointNode.parent.left = newTopNode;
487    } else if (datumPointNode.parent.right === datumPointNode) {
488      datumPointNode.parent.right = newTopNode;
489    }
490    datumPointNode.parent = newTopNode;
491    newTopNode.left = datumPointNode;
492    return this;
493  }
494  private rRotate(datumPointNode: TreeNode<K, V>): TreeClass<K, V> {
495    let newTopNode: TreeNode<K, V> | undefined = datumPointNode.left;
496    if (newTopNode === undefined) {
497      throw new Error('[rotate right error]: the left child node of the base node === undefined');
498    }
499    datumPointNode.left = newTopNode.right;
500    datumPointNode.left !== undefined ? datumPointNode.left.parent = datumPointNode : '';
501    newTopNode.parent = datumPointNode.parent;
502    if (datumPointNode.parent === undefined) {
503      this.root = newTopNode;
504    } else if (datumPointNode === datumPointNode.parent.left) {
505      datumPointNode.parent.left = newTopNode;
506    } else if (datumPointNode === datumPointNode.parent.right) {
507      datumPointNode.parent.right = newTopNode;
508    }
509    datumPointNode.parent = newTopNode;
510    newTopNode.right = datumPointNode;
511    return this;
512  }
513  private insertRebalance(fixNode: TreeNode<K, V>): TreeClass<K, V> {
514    let parentNode: TreeNode<K, V> | undefined = fixNode.parent;
515    while (this.getColor(parentNode) === RED &&
516      parentNode !== undefined &&
517      parentNode.parent !== undefined) {
518      let grandpaNode = parentNode && parentNode.parent;
519      if (parentNode === grandpaNode.left &&
520        this.getColor(grandpaNode.right) === BLACK &&
521        fixNode === parentNode.left) {
522        this
523          .setColor(BLACK, parentNode)
524          .setColor(RED, grandpaNode)
525          .rRotate(grandpaNode);
526        break;
527      } else if (parentNode === grandpaNode.left &&
528        this.getColor(grandpaNode.right) === BLACK &&
529        fixNode === parentNode.right) {
530        this
531          .setColor(BLACK, fixNode)
532          .setColor(RED, grandpaNode)
533          .lRotate(parentNode)
534          .rRotate(grandpaNode);
535        break;
536      } else if (parentNode === grandpaNode.right &&
537        this.getColor(grandpaNode.left) === BLACK &&
538        fixNode === parentNode.left) {
539        this
540          .setColor(BLACK, fixNode)
541          .setColor(RED, grandpaNode)
542          .rRotate(parentNode)
543          .lRotate(grandpaNode);
544        break;
545      } else if (parentNode === grandpaNode.right &&
546        this.getColor(grandpaNode.left) === BLACK &&
547        fixNode === parentNode.right) {
548        this
549          .setColor(BLACK, parentNode)
550          .setColor(RED, grandpaNode)
551          .lRotate(grandpaNode);
552        break;
553      } else if ((parentNode === grandpaNode.right && this.getColor(grandpaNode.left) === RED) ||
554        (parentNode === grandpaNode.left && this.getColor(grandpaNode.right) === RED)) {
555        this
556          .setColor(BLACK, parentNode)
557          .setColor(BLACK, parentNode === grandpaNode.left ? grandpaNode.right : grandpaNode.left)
558          .setColor(RED, grandpaNode);
559        fixNode = grandpaNode;
560        parentNode = fixNode.parent;
561      } else {
562        throw new Error('Exceptions after adding');
563      }
564    }
565    this.root ? this.root.color = BLACK : '';
566    return this;
567  }
568  private deleteRebalance(fixNode: TreeNode<K, V>): void {
569    while (this.getColor(fixNode) === BLACK && fixNode !== this.root && fixNode.parent) {
570      let sibling: TreeNode<K, V> | undefined = undefined;
571      if (fixNode === fixNode.parent.left) {
572        sibling = fixNode.parent.right;
573        if (this.getColor(sibling) === RED) {
574          this
575            .setColor(RED, fixNode.parent)
576            .setColor(BLACK, sibling)
577            .lRotate(fixNode.parent);
578          sibling = fixNode.parent.right;
579        }
580        if (sibling === undefined) {
581          throw new Error('Error sibling node is undefined');
582        }
583        if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === BLACK) {
584          this.setColor(RED, sibling);
585          fixNode = fixNode.parent;
586        } else if (this.getColor(sibling.left) === RED && this.getColor(sibling.right) === BLACK) {
587          this
588            .setColor(RED, sibling)
589            .setColor(BLACK, sibling.left)
590            .rRotate(sibling);
591          sibling = fixNode.parent.right;
592          if (sibling === undefined) {
593            throw new Error('Error sibling node is empty');
594          }
595          this
596            .setColor(fixNode.parent.color, sibling)
597            .setColor(BLACK, fixNode.parent)
598            .setColor(BLACK, sibling.right)
599            .lRotate(fixNode.parent);
600          break;
601        } else if (this.getColor(sibling.right) === RED) {
602          this
603            .setColor(fixNode.parent.color, sibling)
604            .setColor(BLACK, fixNode.parent)
605            .setColor(BLACK, sibling.right)
606            .lRotate(fixNode.parent);
607          break;
608        } else {
609          throw new Error('Adjust the error after the error is deleted');
610        }
611      } else {
612        sibling = fixNode.parent.left;
613        if (this.getColor(sibling) === RED) {
614          this
615            .setColor(BLACK, sibling)
616            .setColor(RED, fixNode.parent)
617            .rRotate(fixNode.parent);
618          sibling = fixNode.parent.left;
619        }
620        if (sibling === undefined) {
621          throw new Error('Error sibling node is undefined');
622        }
623        if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === BLACK) {
624          this
625            .setColor(RED, sibling);
626          fixNode = fixNode.parent;
627        } else if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === RED) {
628          this
629            .setColor(RED, sibling)
630            .setColor(BLACK, sibling.right)
631            .lRotate(sibling);
632          sibling = fixNode.parent.left;
633          if (sibling === undefined) {
634            throw new Error('Adjust the error after the error is deleted');
635          }
636          this
637            .setColor(fixNode.parent.color, sibling)
638            .setColor(BLACK, fixNode.parent)
639            .setColor(BLACK, sibling.left)
640            .rRotate(fixNode.parent);
641          break;
642        } else if (this.getColor(sibling.left) === RED) {
643          this
644            .setColor(fixNode.parent.color, sibling)
645            .setColor(BLACK, fixNode.parent,)
646            .setColor(BLACK, sibling.left)
647            .rRotate(fixNode.parent);
648          break;
649        } else {
650          throw new Error('Adjust the error after the error is deleted');
651        }
652      }
653    }
654    this.setColor(BLACK, fixNode);
655  }
656  private getColor(node: TreeNode<K, V> | undefined): RBTreeNodeColor {
657    return node === undefined ? BLACK : node.color;
658  }
659  private setColor(color: RBTreeNodeColor, node: TreeNode<K, V> | undefined): TreeClass<K, V> {
660    if (node === undefined) {
661      throw new Error('Wrong color setting');
662    } else {
663      node.color = color;
664    }
665    return this;
666  }
667}
668const MAX_CAPACITY = 1 << 30; // 30 : means number
669const LOADER_FACTOR = 0.75;
670class DictionaryClass<K, V> {
671  private tableLink: { [hashIndex: number]: LinkedList<Pair<K, V>> | TreeClass<K, V> };
672  protected memberNumber: number;
673  private isChange: boolean;
674  private memberArray: Array<Pair<K, V>>;
675  private capacity: number;
676  constructor() {
677    this.tableLink = {};
678    this.memberNumber = 0;
679    this.isChange = true;
680    this.memberArray = [];
681    this.capacity = 16;
682  }
683  get keyValueArray(): Pair<K, V>[] {
684    let result: Pair<K, V>[] = [];
685    result = this.keyValues();
686    return result;
687  }
688  protected getHashIndex(key: K): number {
689    let h: number = 0;
690    let hash: number = 0;
691    hash = ((key === null) ? 0 : ((h = hashCode(key)) ^ (h >>> 16))); // 16 : means number
692    if (this.expandCapacity()) {
693      this.keyValues();
694      this.memberNumber = 0;
695      this.tableLink = {};
696      this.isChange = true;
697      for (let item of this.memberArray) {
698        this.put(item.key, item.value);
699      }
700      this.memberNumber++;
701    }
702    let n: number = 0;
703    n = this.power(this.capacity);
704    return (n - 1) & hash;
705  }
706  private power(size: number): number {
707    let n: number = 1;
708    let temp: number = size;
709    while (temp >>> 1 !== 1) {
710      n++;
711      temp = temp >>> 1;
712    }
713    return n;
714  }
715  private keyValues(): Pair<K, V>[] {
716    if (!this.isChange) {
717      return this.memberArray;
718    }
719    this.memberArray = [];
720    let keys: number[] = [];
721    keys = Object.keys(this.tableLink).map((item) => parseInt(item));
722    for (let i: number = 0; i < keys.length; i++) {
723      let members: TreeClass<K, V> | LinkedList<Pair<K, V>> = undefined;
724      members = this.tableLink[keys[i]];
725      if (members instanceof TreeClass) {
726        let tempArray: TreeNode<K, V>[] = members.keyValueArray;
727        for (let i: number = 0; i < members.memberNumber; i++) {
728          this.memberArray.push(new Pair(tempArray[i].key, tempArray[i].value));
729        }
730      } else {
731        if (members !== undefined && !members.isEmpty()) {
732          let current: Node<Pair<K, V>> = members.getHead();
733          while (current !== undefined) {
734            this.memberArray.push(current.element);
735            current = current.next;
736          }
737        }
738      }
739    }
740    this.memberNumber = this.memberArray.length;
741    let valuePairs: Pair<K, V>[] = this.memberArray;
742    return valuePairs;
743  }
744  protected expandCapacity(): boolean {
745    let capacityChange: boolean = false;
746    while (this.capacity < this.memberNumber / LOADER_FACTOR && this.capacity < MAX_CAPACITY) {
747      this.capacity = 2 * this.capacity; // 2 : means number
748      capacityChange = true;
749    }
750    return capacityChange;
751  }
752  protected put(key: K, value: V = key as unknown as V): boolean {
753    this.isChange = true;
754    if (!this.hasKey(key)) {
755      this.memberNumber++;
756    }
757    let position: number = 0;
758    position = this.getHashIndex(key);
759    let members: LinkedList<Pair<K, V>> | TreeClass<K, V> = undefined;
760    members = this.tableLink[position];
761    if (members instanceof LinkedList && members.count >= 8) { // 8 : means number
762      let newElement: TreeClass<K, V> = new TreeClass<K, V>();
763      let current: Node<Pair<K, V>> = undefined;
764      current = members.getHead();
765      while (current != null || current !== undefined) {
766        if (!(current.element instanceof Pair)) {
767          return false;
768        }
769        newElement.addNode(current.element.key, current.element.value);
770        current = current.next;
771      }
772      newElement.addNode(key, value);
773      this.tableLink[position] = newElement;
774      return true;
775    } else if (members instanceof TreeClass) {
776      members.addNode(key, value);
777      this.tableLink[position] = members;
778      return true;
779    } else {
780      if (this.tableLink[position] === undefined) {
781        members = new LinkedList<Pair<K, V>>();
782      }
783      if (!this.replaceMember(key, value)) {
784        members.push(new Pair(key, value));
785        this.tableLink[position] = members;
786      }
787      return true;
788    }
789  }
790  protected replaceMember(key: K, value: V = key as unknown as V): boolean {
791    let position: number = 0;
792    position = this.getHashIndex(key);
793    let members: LinkedList<Pair<K, V>> = undefined;
794    members = this.tableLink[position] as LinkedList<Pair<K, V>>;
795    if (members === null || members === undefined) {
796      return false;
797    }
798    let current: Node<Pair<K, V>> = undefined;
799    current = members.getHead();
800    while (current !== undefined) {
801      if (current.element.key === key) {
802        current.element.value = value;
803        return true;
804      }
805      current = current.next;
806    }
807    return false;
808  }
809  protected getValueByKey(key: K): V | undefined {
810    let position: number = 0;
811    position = this.getHashIndex(key);
812    let members: LinkedList<Pair<K, V>> | TreeClass<K, V> = undefined;
813    members = this.tableLink[position];
814    if (members instanceof TreeClass) {
815      let resultNode: TreeNode<K, V> | undefined = undefined;
816      resultNode = members.getNode(key);
817      if (resultNode === undefined) {
818        return undefined;
819      }
820      return resultNode.value;
821    } else {
822      if (members !== undefined && !members.isEmpty()) {
823        members as LinkedList<Pair<K, V>>;
824        let current: Node<Pair<K, V>> = undefined;
825        current = members.getHead();
826        while (current !== undefined) {
827          if (current.element.key === key) {
828            return current.element.value;
829          }
830          current = current.next;
831        }
832      }
833    }
834    return undefined;
835  }
836  protected removeMember(key: K): V | undefined {
837    let position: number = 0;
838    position = this.getHashIndex(key);
839    let members: LinkedList<Pair<K, V>> | TreeClass<K, V> = undefined;
840    members = this.tableLink[position];
841    if (members instanceof TreeClass) {
842      let result: V | undefined = members.removeNode(key);
843      if (result !== undefined) {
844        this.isChange = true;
845        this.memberNumber--;
846        return result;
847      }
848    } else {
849      if (members !== undefined && !members.isEmpty()) {
850        let current: Node<Pair<K, V>> = undefined;
851        current = members.getHead();
852        while (current !== undefined) {
853          if (current.element.key === key) {
854            let result: V | undefined = current.element.value;
855            members.remove(current.element);
856            if (members.isEmpty()) {
857              delete this.tableLink[position];
858            }
859            this.isChange = true;
860            this.memberNumber--;
861            return result;
862          }
863          current = current.next;
864        }
865      }
866    }
867    return undefined;
868  }
869  protected clear(): void {
870    this.tableLink = {};
871    this.memberNumber = 0;
872    this.isChange = true;
873    this.capacity = 16;
874  }
875  protected hasKey(key: K): boolean {
876    let position: number = 0;
877    position = this.getHashIndex(key);
878    let members: LinkedList<Pair<K, V>> | TreeClass<K, V> = undefined;
879    members = this.tableLink[position];
880    if (members === undefined || members === undefined) {
881      return false;
882    }
883    if (members instanceof TreeClass) {
884      return members.getNode(key) !== undefined;
885    }
886    let current: Node<Pair<K, V>> = undefined;
887    current = members.getHead();
888    while (current !== undefined && current !== undefined) {
889      if (current.element.key === key) {
890        return true;
891      }
892      current = current.next;
893    }
894    return false;
895  }
896  protected setAll(map: DictionaryClass<K, V>): void {
897    let memebers: Pair<K, V>[] = [];
898    memebers = map.keyValues();
899    for (let i: number = 0; i < memebers.length; i++) {
900      this.put(memebers[i].key, memebers[i].value);
901    }
902  }
903  protected values(): V[] {
904    let values: Array<V> = [];
905    let valuePairs: Pair<K, V>[] = [];
906    valuePairs = this.keyValues();
907    for (let i: number = 0; i < valuePairs.length; i++) {
908      values.push(valuePairs[i].value);
909    }
910    return values;
911  }
912}
913class Node<T> {
914  element: T;
915  next: Node<T> | undefined;
916  constructor(element: T, next?: Node<T>) {
917    this.element = element;
918    this.next = next;
919  }
920}
921class LinkedList<T> {
922  public count: number;
923  protected next: Node<T> | undefined;
924  protected head: Node<T> | undefined;
925  constructor() {
926    this.count = 0;
927    this.next = undefined;
928    this.head = undefined;
929  }
930  push(element: T): void {
931    let node: Node<T> = undefined;
932    node = new Node(element);
933    let current: undefined | Node<T>;
934    if (this.head === undefined) {
935      this.head = node;
936    } else {
937      current = this.head;
938      while (current.next !== undefined) {
939        current = current.next;
940      }
941      current.next = node;
942    }
943    this.count++;
944  }
945  removeAt(index: number): T {
946    if (index >= 0 && index < this.count) {
947      let current: Node<T> = this.head;
948      if (index === 0 && current !== undefined) {
949        this.head = current.next;
950      } else {
951        let previous: Node<T> = this.getElementAt(index--);
952        if (previous !== undefined) {
953          current = previous.next;
954          previous.next = (current === undefined ? undefined : current.next);
955        }
956      }
957      if (current !== undefined) {
958        this.count--;
959        return current.element;
960      }
961    }
962    return undefined;
963  }
964  getElementAt(index: number): Node<T> {
965    if (index > 0 && index < this.count) {
966      let current: Node<T> = this.head;
967      for (let i: number = 0; i < index && current !== undefined; i++) {
968        current = current.next;
969      }
970      return current;
971    }
972    return undefined;
973  }
974  insert(element: T, index: number): boolean {
975    if (index >= 0 && index <= this.count) {
976      let node: Node<T> = undefined;
977      node = new Node(element);
978      if (index === 0) {
979        node.next = this.head;
980        this.head = node;
981      } else {
982        let previous: Node<T> = this.getElementAt(index--);
983        if (previous === undefined) {
984          throw new Error('data storage error');
985        }
986        node.next = previous.next;
987        previous.next = node;
988      }
989      this.count++;
990      return true;
991    }
992    return false;
993  }
994  indexOf(element: T, compareFn?: CompFun<T>): number {
995    let current: Node<T> = this.head;
996    for (let i: number = 0; i < this.count && current !== undefined; i++) {
997      if (currencyCompare(element, current.element, compareFn) === ComparResult.EQUALS) {
998        return i;
999      }
1000      current = current.next;
1001    }
1002    return -1;
1003  }
1004  remove(element: T, compareFn?: CompFun<T>): void {
1005    this.removeAt(this.indexOf(element, compareFn));
1006  }
1007  clear(): void {
1008    this.head = undefined;
1009    this.count = 0;
1010  }
1011  isEmpty(): boolean {
1012    return this.count === 0;
1013  }
1014  getHead(): Node<T> {
1015    return this.head;
1016  }
1017  toString(): string {
1018    if (this.head === undefined) {
1019      return '';
1020    }
1021    let objString: string = '';
1022    objString = `${this.head.element}`;
1023    let current: Node<T> = undefined;
1024    current = this.head.next;
1025    for (let i: number = 1; i < this.count && current !== undefined; i++) {
1026      objString = `${objString}, ${current.element}`;
1027      current = current.next;
1028    }
1029    return objString;
1030  }
1031}
1032
1033const NEWTARGET_IS_NULL_ERROR_CODE = 10200012;
1034const BIND_ERROR_CODE = 10200011;
1035const RANGE_ERROR_CODE = 10200001;
1036const TYPE_ERROR_CODE = 401;
1037const EMPTY_ERROR_CODE = 10200010;
1038
1039class BusinessError extends Error {
1040  code: number;
1041  constructor(message, code) {
1042    super();
1043    this.name = 'BusinessError';
1044    this.message = message;
1045    this.code = code;
1046  }
1047}
1048
1049function checkBindError(methodName: string, className: Function, self: unknown): void {
1050  if (!(self instanceof className)) {
1051    throw new BusinessError(`The ${methodName} method cannot be bound`, BIND_ERROR_CODE);
1052  }
1053}
1054
1055function checkTypeError(paramName: string, type: string, receivedValue: unknown): void {
1056  let tmpType = '';
1057  if (typeof receivedValue === 'object') {
1058    tmpType = (receivedValue === null) ? 'Null' : receivedValue.constructor.name;
1059  } else {
1060    tmpType = typeof receivedValue;
1061  }
1062  if (tmpType === 'number' && type === 'Integer') {
1063    tmpType = Number.isInteger(receivedValue) ? 'Integer' : 'number';
1064  }
1065  if (tmpType === 'function' && type === 'callable') {
1066    tmpType = 'callable';
1067  }
1068  if (tmpType.toLocaleLowerCase() !== type.toLocaleLowerCase()) {
1069    type = (type === 'Integer') ? 'number' : type;
1070    throw new BusinessError(`The type of "${paramName}" must be ${type}. Received value is: ${receivedValue}`, TYPE_ERROR_CODE);
1071  }
1072}
1073
1074function checkRangeError(paramName: string, receivedValue: unknown, min?: number, max?: number, options?: string): void {
1075  let range = [];
1076  let minFlag = true;
1077  let maxFlag = true;
1078  if (min !== undefined) {
1079    if (options === '!=min') {
1080      minFlag = (receivedValue > min);
1081      range.push(`> ${min}`);
1082    } else {
1083      minFlag = (receivedValue >= min);
1084      range.push(`>= ${min}`);
1085    }
1086  }
1087  if (max !== undefined) {
1088    max = (max < 0) ? 0 : max;
1089    maxFlag = (receivedValue <= max);
1090    range.push(`<= ${max}`);
1091  }
1092  if (!(minFlag && maxFlag)) {
1093    throw new BusinessError(
1094      `The value of "${paramName}" is out of range. It must be ${range.join(' && ')}. Received value is: ${receivedValue}`, RANGE_ERROR_CODE);
1095  }
1096}
1097
1098function checkIsEmptyError(isEmpty: boolean): void {
1099  if (isEmpty) {
1100    throw new BusinessError('Container is empty', EMPTY_ERROR_CODE);
1101  }
1102}
1103
1104function checkNewTargetIsNullError(className: string, isNull: boolean): void {
1105  if (isNull) {
1106    throw new BusinessError(`The ${className}'s constructor cannot be directly invoked`, NEWTARGET_IS_NULL_ERROR_CODE);
1107  }
1108}
1109
1110let errorUtil = {
1111  checkBindError,
1112  checkTypeError,
1113  checkRangeError,
1114  checkIsEmptyError,
1115  checkNewTargetIsNullError
1116};
1117export default {
1118  isIncludeToArray,
1119  LightWeightClass,
1120  PlainArrayClass,
1121  TreeClass,
1122  DictionaryClass,
1123  errorUtil
1124};