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