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

org.antlr.v4.runtime.dfa.SparseEdgeMap Maven / Gradle / Ivy

There is a newer version: 4.9.0
Show newest version
/*
 * Copyright (c) 2012 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD-3-Clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
package org.antlr.v4.runtime.dfa;

import org.antlr.v4.runtime.misc.NotNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Sam Harwell
 */
public final class SparseEdgeMap extends AbstractEdgeMap {
	private static final int DEFAULT_MAX_SIZE = 5;

	private final int[] keys;
	private final List values;

	public SparseEdgeMap(int minIndex, int maxIndex) {
		this(minIndex, maxIndex, DEFAULT_MAX_SIZE);
	}

	public SparseEdgeMap(int minIndex, int maxIndex, int maxSparseSize) {
		super(minIndex, maxIndex);
		this.keys = new int[maxSparseSize];
		this.values = new ArrayList(maxSparseSize);
	}

	private SparseEdgeMap(@NotNull SparseEdgeMap map, int maxSparseSize) {
		super(map.minIndex, map.maxIndex);
		synchronized (map) {
			if (maxSparseSize < map.values.size()) {
				throw new IllegalArgumentException();
			}

			keys = Arrays.copyOf(map.keys, maxSparseSize);
			values = new ArrayList(maxSparseSize);
			values.addAll(map.values);
		}
	}

	public final int[] getKeys() {
		return keys;
	}

	public final List getValues() {
		return values;
	}

	public final int getMaxSparseSize() {
		return keys.length;
	}

	@Override
	public int size() {
		return values.size();
	}

	@Override
	public boolean isEmpty() {
		return values.isEmpty();
	}

	@Override
	public boolean containsKey(int key) {
		return get(key) != null;
	}

	@Override
	public T get(int key) {
		// Special property of this collection: values are only even added to
		// the end, else a new object is returned from put(). Therefore no lock
		// is required in this method.
		int index = Arrays.binarySearch(keys, 0, size(), key);
		if (index < 0) {
			return null;
		}

		return values.get(index);
	}

	@Override
	public AbstractEdgeMap put(int key, T value) {
		if (key < minIndex || key > maxIndex) {
			return this;
		}

		if (value == null) {
			return remove(key);
		}

		synchronized (this) {
			int index = Arrays.binarySearch(keys, 0, size(), key);
			if (index >= 0) {
				// replace existing entry
				values.set(index, value);
				return this;
			}

			assert index < 0 && value != null;
			int insertIndex = -index - 1;
			if (size() < getMaxSparseSize() && insertIndex == size()) {
				// stay sparse and add new entry
				keys[insertIndex] = key;
				values.add(value);
				return this;
			}

			int desiredSize = size() >= getMaxSparseSize() ? getMaxSparseSize() * 2 : getMaxSparseSize();
			int space = maxIndex - minIndex + 1;
			// SparseEdgeMap only uses less memory than ArrayEdgeMap up to half the size of the symbol space
			if (desiredSize >= space / 2) {
				ArrayEdgeMap arrayMap = new ArrayEdgeMap(minIndex, maxIndex);
				arrayMap = arrayMap.putAll(this);
				arrayMap.put(key, value);
				return arrayMap;
			}
			else {
				SparseEdgeMap resized = new SparseEdgeMap(this, desiredSize);
				System.arraycopy(resized.keys, insertIndex, resized.keys, insertIndex + 1, size() - insertIndex);
				resized.keys[insertIndex] = key;
				resized.values.add(insertIndex, value);
				return resized;
			}
		}
	}

	@Override
	public SparseEdgeMap remove(int key) {
		synchronized (this) {
			int index = Arrays.binarySearch(keys, 0, size(), key);
			if (index < 0) {
				return this;
			}

			SparseEdgeMap result = new SparseEdgeMap(this, getMaxSparseSize());
			System.arraycopy(result.keys, index + 1, result.keys, index, size() - index - 1);
			result.values.remove(index);
			return result;
		}
	}

	@Override
	public AbstractEdgeMap clear() {
		if (isEmpty()) {
			return this;
		}

		return new EmptyEdgeMap(minIndex, maxIndex);
	}

	@Override
	public Map toMap() {
		if (isEmpty()) {
			return Collections.emptyMap();
		}

		synchronized (this) {
			Map result = new LinkedHashMap();
			for (int i = 0; i < size(); i++) {
				result.put(keys[i], values.get(i));
			}

			return result;
		}
	}

	@Override
	public Set> entrySet() {
		return toMap().entrySet();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy