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

net.amygdalum.util.map.ByteObjectMap Maven / Gradle / Ivy

Go to download

Searching and Matching Strings with efficient algorithms: - Knuth-Morris-Pratt - Shift-And/Or - Boyer-Moore-Horspool - Sunday (QuickSearch) - BNDM - BOM - Aho-Corasick - Set-Horspool - Wu-Manber - Set-BOM

There is a newer version: 0.4.4
Show newest version
package net.amygdalum.util.map;

import static java.util.Arrays.sort;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class ByteObjectMap extends TuneableMap {

	private static final char NULL_KEY = 0;

	private float loadFactor;
	private int mask;
	private int expandAt;
	private int size;

	private byte[] keys;
	private T[] values;
	private T defaultValue;
	private T nullValue;

	public ByteObjectMap(T defaultValue) {
		this(DEFAULT_SIZE, DEFAULT_LOAD, defaultValue);
	}

	@SuppressWarnings("unchecked")
	public ByteObjectMap(int initialSize, float loadFactor, T defaultValue) {
		this.loadFactor = loadFactor;
		this.mask = mask(initialSize, loadFactor);
		this.expandAt = initialSize;
		this.size = 0;
		this.keys = new byte[mask + 1];
		this.values = (T[]) new Object[mask + 1];
		this.defaultValue = defaultValue;
		this.nullValue = defaultValue;
	}

	public byte[] keys() {
		int size = this.size;
		if (nullValue != defaultValue) {
			size++;
		}
		byte[] keys = new byte[size];
		int pos = 0;
		for (byte b : this.keys) {
			if (b != NULL_KEY) {
				keys[pos] = b;
				pos++;
			}
		}
		if (nullValue != defaultValue && pos < keys.length) {
			keys[pos] = NULL_KEY;
		}
		sort(keys);
		return keys;
	}

	public ByteObjectMap add(byte key, T value) {
		put(key, value);
		return this;
	}

	public void put(byte key, T value) {
		if (key == NULL_KEY) {
			nullValue = value;
			return;
		}
		int slot = hash(key) & mask;
		while (keys[slot] != key && keys[slot] != NULL_KEY) {
			slot = (slot + 1) & mask;
		}
		if (keys[slot] == NULL_KEY) {
			size++;
		}
		keys[slot] = key;
		values[slot] = value;
		if (size > expandAt) {
			expand(size * 2);
		}
	}

	public T get(byte key) {
		if (key == NULL_KEY) {
			return nullValue;
		}
		int slot = hash(key) & mask;
		while (keys[slot] != key && keys[slot] != NULL_KEY) {
			slot = (slot + 1) & mask;
		}
		if (keys[slot] == NULL_KEY) {
			return defaultValue;
		} else {
			return values[slot];
		}
	}

	public T getDefaultValue() {
		return defaultValue;
	}

	public Iterable cursor() {
		return new EntryIterable();
	}

	@SuppressWarnings("unchecked")
	private void expand(int size) {
		int mask = mask(size, this.loadFactor);

		byte[] oldkeys = this.keys;
		T[] oldvalues = this.values;

		byte[] keys = new byte[mask + 1];
		T[] values = (T[]) new Object[mask + 1];

		int[] delayed = new int[this.size];
		int pos = 0;

		for (int i = 0; i < oldkeys.length; i++) {
			byte key = oldkeys[i];
			if (key != NULL_KEY) {
				T value = oldvalues[i];
				int slot = hash(key) & mask;
				if (keys[slot] == NULL_KEY) {
					keys[slot] = key;
					values[slot] = value;
				} else {
					delayed[pos] = i;
					pos++;
				}
			}
		}
		for (int i = 0; i <= pos; i++) {
			int j = delayed[i];
			byte key = oldkeys[j];
			T value = oldvalues[j];
			int slot = hash(key) & mask;
			while (keys[slot] != key && keys[slot] != NULL_KEY) {
				slot = (slot + 1) & mask;
			}
			keys[slot] = key;
			values[slot] = value;
		}

		this.expandAt = size;
		this.mask = mask;
		this.keys = keys;
		this.values = values;
	}

	@Override
	public String toString() {
		StringBuilder buffer = new StringBuilder();
		buffer.append("{\n");
		if (keys.length > 0) {
			byte key = keys[0];
			T value = values[0];
			buffer.append(key).append(": ").append(value);

		}
		for (int i = 1; i < keys.length; i++) {
			byte key = keys[i];
			T value = values[i];
			buffer.append(",\n").append(key).append(": ").append(value);
		}
		buffer.append("\n}");
		return buffer.toString();
	}

	public class EntryIterable implements Iterable.Entry> {

		@Override
		public Iterator.Entry> iterator() {
			return new EntryIterator();
		}
	}

	public class EntryIterator implements Iterator.Entry> {

		private int index;
		private int currentKey;
		private int fixedSize;
		private Entry entry;

		public EntryIterator() {
			this.index = 0;
			this.currentKey = -1;
			this.fixedSize = size;
			this.entry = new Entry();
		}
		
		@Override
		public boolean hasNext() {
			if (size != fixedSize) {
				throw new ConcurrentModificationException();
			}
			return index < fixedSize || index == fixedSize && nullValue != defaultValue;
		}

		@Override
		public ByteObjectMap.Entry next() {
			if (size != fixedSize) {
				throw new ConcurrentModificationException();
			}
			while (currentKey < keys.length - 1) {
				currentKey++;
				byte b = keys[currentKey];
				if (b != NULL_KEY) {
					entry.key = keys[currentKey];
					entry.value = values[currentKey];
					index++;
					return entry;
				}
			}
			if (nullValue != defaultValue) {
				entry.key = NULL_KEY;
				entry.value = nullValue;
				index++;
				return entry;
			}
			throw new NoSuchElementException();
		}

		@Override
		public void remove() {
			if (currentKey < 0 || currentKey >= keys.length) {
				throw new NoSuchElementException();
			}
			keys[currentKey] = NULL_KEY;
			values[currentKey] = defaultValue;
		}
	}

	public class Entry {

		public byte key;
		public T value;

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy