All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jdt.internal.compiler.util.CharDeduplication Maven / Gradle / Ivy

There is a newer version: 3.39.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Joerg Kubitz    - threadlocal refactoring, all ASCII chars
 *                     - (copied content from PublicScanner.java / Scanner.java)
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.util;

import java.lang.ref.SoftReference;
import java.util.Arrays;
import java.util.function.Supplier;

public class CharDeduplication {

	// ----- immutable static part (thread safe): ----

	static final char[] ASCII_CHARS[] = new char[128][];
	static {
		for (int i = 0; i < ASCII_CHARS.length; i++) {
			ASCII_CHARS[i] = new char[] { (char) i };
		}
	}
	public static final int TABLE_SIZE = 30; // XXX thats not a prime -> bad for hashing, nor a power of 2 -> expensive
												// modulo computation
	public static final int INTERNAL_TABLE_SIZE = 6; // 30*6 =180 entries

	public static final int OPTIMIZED_LENGTH = 6;

	private final static char[] CHAR_ARRAY0 = new char[0];

	/** avoid OOME by additional CharDeduplication memory **/
	static final class CacheReference {
		private SoftReference reference;
		private final Supplier supplier;

		CacheReference(Supplier supplier) {
			this.supplier = supplier;
			this.reference = new SoftReference<>(supplier.get());
		}

		T get() {
			T referent = this.reference.get();
			if (referent == null) {
				referent = this.supplier.get();
				this.reference = new SoftReference<>(referent);
			}
			return referent;
		}
	}

	private final static ThreadLocal> mutableCache = ThreadLocal.withInitial(()->new CacheReference<>(CharDeduplication::new));

	private static final char[] optimizedCurrentTokenSource1(char[] source, int startPosition) {
		// optimization at no speed cost of 99.5 % of the singleCharIdentifier
		char charOne = source[startPosition];
		if (charOne < ASCII_CHARS.length) {
			return ASCII_CHARS[charOne];
		}
		return new char[] { charOne };
	}

	/** @return an instance that is *not* thread safe. To be used in a single thread only. **/
	public static CharDeduplication getThreadLocalInstance() {
		return mutableCache.get().get();
	}

	// ----- mutable non-static part (not thread safe!): ----

	/** single threaded only **/
	public final char[][][][] charArray_length = new char[OPTIMIZED_LENGTH - 1][TABLE_SIZE][INTERNAL_TABLE_SIZE][];

	int newEntry2 = 0;
	int newEntry3 = 0;
	int newEntry4 = 0;
	int newEntry5 = 0;
	int newEntry6 = 0;

	private CharDeduplication() {
		init();
	}

	private void init() {
		for (int i = 0; i < OPTIMIZED_LENGTH - 1; i++) {
			final char[] initCharArray = new char[i + 2];
			for (int j = 0; j < TABLE_SIZE; j++) {
				for (int k = 0; k < INTERNAL_TABLE_SIZE; k++) {
					this.charArray_length[i][j][k] = initCharArray;
				}
			}
		}
	}

	/** public for test purpose only **/
	@Deprecated
	public void reset() {
		init();
	}

	/**
	 * like Arrays.copyOfRange(source, from, to) but returns a cached instance of the former result if
	 * available
	 * 
	 * @param from
	 *                 start index (inclusive)
	 * @param to
	 *                 end index (exclusive)
	 * @return source[from..to-1]
	 * @see java.util.Arrays#copyOfRange(char[], int, int)
	 **/
	public char[] sharedCopyOfRange(char[] source, int from, int to) {
		int length = to - from;
		switch (length) { // see OptimizedLength
			case 1:
				return optimizedCurrentTokenSource1(source, from);
			case 2:
				return optimizedCurrentTokenSource2(source, from);
			case 3:
				return optimizedCurrentTokenSource3(source, from);
			case 4:
				return optimizedCurrentTokenSource4(source, from);
			case 5:
				return optimizedCurrentTokenSource5(source, from);
			case 6:
				return optimizedCurrentTokenSource6(source, from);
			case 0:
				return CHAR_ARRAY0;
		}
		return Arrays.copyOfRange(source, from, to);
	}

	private final char[] optimizedCurrentTokenSource2(char[] source, int startPosition) {

		char[] src = source;
		int start = startPosition;
		char c0, c1;
		int hash = (((c0 = src[start]) << 6) + (c1 = src[start + 1])) % TABLE_SIZE;
		char[][] table = this.charArray_length[0][hash];
		int i = this.newEntry2;
		while (++i < INTERNAL_TABLE_SIZE) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]))
				return charArray;
		}
		// ---------other side---------
		i = -1;
		int max = this.newEntry2;
		while (++i <= max) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]))
				return charArray;
		}
		// --------add the entry-------
		if (++max >= INTERNAL_TABLE_SIZE)
			max = 0;
		char[] r;
		System.arraycopy(src, start, r = new char[2], 0, 2);
		return table[this.newEntry2 = max] = r;
	}

	private final char[] optimizedCurrentTokenSource3(char[] source, int startPosition) {
		char[] src = source;
		int start = startPosition;
		char c0, c1 = src[start + 1], c2;
		int hash = (((c0 = src[start]) << 6) + (c2 = src[start + 2])) % TABLE_SIZE;
		char[][] table = this.charArray_length[1][hash];
		int i = this.newEntry3;
		while (++i < INTERNAL_TABLE_SIZE) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
				return charArray;
		}
		// ---------other side---------
		i = -1;
		int max = this.newEntry3;
		while (++i <= max) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
				return charArray;
		}
		// --------add the entry-------
		if (++max >= INTERNAL_TABLE_SIZE)
			max = 0;
		char[] r;
		System.arraycopy(src, start, r = new char[3], 0, 3);
		return table[this.newEntry3 = max] = r;
	}

	private final char[] optimizedCurrentTokenSource4(char[] source, int startPosition) {
		char[] src = source;
		int start = startPosition;
		char c0, c1 = src[start + 1], c2, c3 = src[start + 3];
		int hash = (((c0 = src[start]) << 6) + (c2 = src[start + 2])) % TABLE_SIZE;
		char[][] table = this.charArray_length[2][hash];
		int i = this.newEntry4;
		while (++i < INTERNAL_TABLE_SIZE) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]))
				return charArray;
		}
		// ---------other side---------
		i = -1;
		int max = this.newEntry4;
		while (++i <= max) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3]))
				return charArray;
		}
		// --------add the entry-------
		if (++max >= INTERNAL_TABLE_SIZE)
			max = 0;
		char[] r;
		System.arraycopy(src, start, r = new char[4], 0, 4);
		return table[this.newEntry4 = max] = r;
	}

	private final char[] optimizedCurrentTokenSource5(char[] source, int startPosition) {
		char[] src = source;
		int start = startPosition;
		char c0, c1 = src[start + 1], c2, c3 = src[start + 3], c4;
		int hash = (((c0 = src[start]) << 12) + ((c2 = src[start + 2]) << 6) + (c4 = src[start + 4])) % TABLE_SIZE;
		char[][] table = this.charArray_length[3][hash];
		int i = this.newEntry5;
		while (++i < INTERNAL_TABLE_SIZE) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
					&& (c4 == charArray[4]))
				return charArray;
		}
		// ---------other side---------
		i = -1;
		int max = this.newEntry5;
		while (++i <= max) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
					&& (c4 == charArray[4]))
				return charArray;
		}
		// --------add the entry-------
		if (++max >= INTERNAL_TABLE_SIZE)
			max = 0;
		char[] r;
		System.arraycopy(src, start, r = new char[5], 0, 5);
		return table[this.newEntry5 = max] = r;
	}

	private final char[] optimizedCurrentTokenSource6(char[] source, int startPosition) {
		char[] src = source;
		int start = startPosition;
		char c0, c1 = src[start + 1], c2, c3 = src[start + 3], c4, c5 = src[start + 5];
		int hash = (((c0 = src[start]) << 12) + ((c2 = src[start + 2]) << 6) + (c4 = src[start + 4])) % TABLE_SIZE;
		char[][] table = this.charArray_length[4][hash];
		int i = this.newEntry6;
		while (++i < INTERNAL_TABLE_SIZE) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
					&& (c4 == charArray[4]) && (c5 == charArray[5]))
				return charArray;
		}
		// ---------other side---------
		i = -1;
		int max = this.newEntry6;
		while (++i <= max) {
			char[] charArray = table[i];
			if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]) && (c3 == charArray[3])
					&& (c4 == charArray[4]) && (c5 == charArray[5]))
				return charArray;
		}
		// --------add the entry-------
		if (++max >= INTERNAL_TABLE_SIZE)
			max = 0;
		char[] r;
		System.arraycopy(src, start, r = new char[6], 0, 6);
		return table[this.newEntry6 = max] = r;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy