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

io.datakernel.http.CaseInsensitiveTokenMap Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 SoftIndex LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.datakernel.http;

import java.lang.reflect.Array;

import static io.datakernel.bytebuf.ByteBufStrings.*;

abstract class CaseInsensitiveTokenMap {
	static abstract class Token {
		protected byte[] lowerCaseBytes;
		protected int lowerCaseHashCode;
	}

	protected final T[] TOKENS;
	protected final int maxProbings;

	protected CaseInsensitiveTokenMap(int slotsNumber, int maxProbings, Class elementsType) {
		this.maxProbings = maxProbings;
		@SuppressWarnings("unchecked") T[] ts = (T[]) Array.newInstance(elementsType, slotsNumber);
		TOKENS = ts;
	}

	public final T register(String name) {
		assert Integer.bitCount(TOKENS.length) == 1;

		T token = create(name);

		for (int p = 0; p < maxProbings; p++) {
			int slot = (token.lowerCaseHashCode + p) & (TOKENS.length - 1);
			if (TOKENS[slot] == null) {
				TOKENS[slot] = token;
				return token;
			}
		}
		throw new IllegalArgumentException("CaseInsensitiveTokenMap hash collision, try to increase size");
	}

	public final T create(String name) {
		byte[] bytes = encodeAscii(name);

		byte[] lowerCaseBytes = new byte[bytes.length];
		int lowerCaseHashCode = 1;
		for (int i = 0; i < bytes.length; i++) {
			byte b = bytes[i];
			if (b >= 'A' && b <= 'Z')
				b += 'a' - 'A';
			lowerCaseBytes[i] = b;
			lowerCaseHashCode = lowerCaseHashCode * 31 + b;
		}

		return create(bytes, 0, bytes.length, lowerCaseBytes, lowerCaseHashCode);
	}

	public final T getOrCreate(byte[] bytes, int offset, int length) {
		int lowerCaseHashCode = hashCodeLowerCaseAscii(bytes, offset, length);
		return getOrCreate(bytes, offset, length, lowerCaseHashCode);
	}

	public final T getOrCreate(byte[] bytes, int offset, int length, int lowerCaseHashCode) {
		T t = get(bytes, offset, length, lowerCaseHashCode);
		return (t != null) ? t : create(bytes, offset, length, null, lowerCaseHashCode);
	}

	public final T get(byte[] bytes, int offset, int length, int lowerCaseHashCode) {
		for (int p = 0; p < maxProbings; p++) {
			int slot = (lowerCaseHashCode + p) & (TOKENS.length - 1);
			T t = TOKENS[slot];
			if (t == null)
				break;
			if (t.lowerCaseHashCode == lowerCaseHashCode && equalsLowerCaseAscii(t.lowerCaseBytes, bytes, offset, length)) {
				return t;
			}
		}
		return null;
	}

	protected abstract T create(byte[] bytes, int offset, int length, byte[] lowerCaseBytes, int lowerCaseHashCode);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy