1 /*******************************************************************************
2 * Copyright (c) 2000, 2019 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.jdt.internal.compiler.util;
15
16 import java.util.Arrays;
17 import java.util.Objects;
18 import java.util.stream.Collectors;
19
20 import org.eclipse.jdt.core.compiler.CharOperation;
21 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
22
23 public final class HashtableOfPackage<P extends PackageBinding> {
24 // to avoid using Enumerations, walk the individual tables skipping nulls
25 public char[] keyTable[];
26 private PackageBinding valueTable[];
27
28 public int elementSize; // number of elements in the table
29 int threshold;
HashtableOfPackage()30 public HashtableOfPackage() {
31 this(3); // usually not very large
32 }
HashtableOfPackage(int size)33 public HashtableOfPackage(int size) {
34 this.elementSize = 0;
35 this.threshold = size; // size represents the expected number of elements
36 int extraRoom = (int) (size * 1.75f);
37 if (this.threshold == extraRoom)
38 extraRoom++;
39 this.keyTable = new char[extraRoom][];
40 this.valueTable = new PackageBinding[extraRoom];
41 }
values()42 public Iterable<P> values() {
43 return Arrays.stream(this.valueTable)
44 .filter(Objects::nonNull)
45 .map(p -> { @SuppressWarnings("unchecked") P theP = (P)p; return theP; })
46 .collect(Collectors.toList());
47 }
containsKey(char[] key)48 public boolean containsKey(char[] key) {
49 int length = this.keyTable.length,
50 index = CharOperation.hashCode(key) % length;
51 int keyLength = key.length;
52 char[] currentKey;
53 while ((currentKey = this.keyTable[index]) != null) {
54 if (currentKey.length == keyLength && CharOperation.equals(currentKey, key))
55 return true;
56 if (++index == length) {
57 index = 0;
58 }
59 }
60 return false;
61 }
get(char[] key)62 public P get(char[] key) {
63 int length = this.keyTable.length,
64 index = CharOperation.hashCode(key) % length;
65 int keyLength = key.length;
66 char[] currentKey;
67 while ((currentKey = this.keyTable[index]) != null) {
68 if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) {
69 @SuppressWarnings("unchecked")
70 P p = (P) this.valueTable[index];
71 return p;
72 }
73 if (++index == length) {
74 index = 0;
75 }
76 }
77 return null;
78 }
put(char[] key, PackageBinding value)79 public PackageBinding put(char[] key, PackageBinding value) {
80 int length = this.keyTable.length,
81 index = CharOperation.hashCode(key) % length;
82 int keyLength = key.length;
83 char[] currentKey;
84 while ((currentKey = this.keyTable[index]) != null) {
85 if (currentKey.length == keyLength && CharOperation.equals(currentKey, key))
86 return this.valueTable[index] = value;
87 if (++index == length) {
88 index = 0;
89 }
90 }
91 this.keyTable[index] = key;
92 this.valueTable[index] = value;
93
94 // assumes the threshold is never equal to the size of the table
95 if (++this.elementSize > this.threshold)
96 rehash();
97 return value;
98 }
rehash()99 private void rehash() {
100 HashtableOfPackage<P> newHashtable = new HashtableOfPackage<P>(this.elementSize * 2); // double the number of expected elements
101 char[] currentKey;
102 for (int i = this.keyTable.length; --i >= 0;)
103 if ((currentKey = this.keyTable[i]) != null)
104 newHashtable.put(currentKey, this.valueTable[i]);
105
106 this.keyTable = newHashtable.keyTable;
107 this.valueTable = newHashtable.valueTable;
108 this.threshold = newHashtable.threshold;
109 }
size()110 public int size() {
111 return this.elementSize;
112 }
113 @Override
toString()114 public String toString() {
115 String s = ""; //$NON-NLS-1$
116 PackageBinding pkg;
117 for (int i = 0, length = this.valueTable.length; i < length; i++)
118 if ((pkg = this.valueTable[i]) != null)
119 s += pkg.toString() + "\n"; //$NON-NLS-1$
120 return s;
121 }
122 }
123