
com.graphhopper.coll.SparseArray Maven / Gradle / Ivy
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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 com.graphhopper.coll;
import com.graphhopper.util.Helper;
/**
* Copied from Android project: android.util.SparseArray.java
*
* SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the
* indices. It is intended to be more efficient than using a HashMap to map Integers to Objects.
*/
public class SparseArray implements Cloneable
{
private static final Object DELETED = new Object();
private boolean mGarbage = false;
private int[] mKeys;
private Object[] mValues;
private int mSize;
/**
* Creates a new SparseArray containing no mappings.
*/
public SparseArray()
{
this(10);
}
/**
* Creates a new SparseArray containing no mappings that will not require any additional memory
* allocation to store the specified number of mappings.
*/
public SparseArray( int initialCapacity )
{
initialCapacity = Helper.idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new Object[initialCapacity];
mSize = 0;
}
@Override
@SuppressWarnings("unchecked")
public SparseArray clone()
{
SparseArray clone = null;
try
{
clone = (SparseArray) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse)
{
/* ignore */
}
return clone;
}
/**
* Gets the Object mapped from the specified key, or null
if no such mapping has
* been made.
*/
public E get( int key )
{
return get(key, null);
}
/**
* Gets the Object mapped from the specified key, or the specified Object if no such mapping has
* been made.
*/
@SuppressWarnings("unchecked")
public E get( int key, E valueIfKeyNotFound )
{
int i = binarySearch(mKeys, 0, mSize, key);
if (i < 0 || mValues[i] == DELETED)
{
return valueIfKeyNotFound;
} else
{
return (E) mValues[i];
}
}
/**
* Removes the mapping from the specified key, if there was any.
*/
public void remove( int key )
{
int i = binarySearch(mKeys, 0, mSize, key);
if (i >= 0)
{
if (mValues[i] != DELETED)
{
mValues[i] = DELETED;
mGarbage = true;
}
}
}
/**
* Removes the mapping at the specified index.
*/
public void removeAt( int index )
{
if (mValues[index] != DELETED)
{
mValues[index] = DELETED;
mGarbage = true;
}
}
private void gc()
{
// Log.e("SparseArray", "gc start with " + mSize);
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++)
{
Object val = values[i];
if (val != DELETED)
{
if (i != o)
{
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;
// Log.e("SparseArray", "gc end with " + mSize);
}
/**
* Adds a mapping from the specified key to the specified value, replacing the previous mapping
* from the specified key if there was one.
*/
public void put( int key, E value )
{
int i = binarySearch(mKeys, 0, mSize, key);
if (i >= 0)
{
mValues[i] = value;
} else
{
i = ~i;
if (i < mSize && mValues[i] == DELETED)
{
mKeys[i] = key;
mValues[i] = value;
return;
}
if (mGarbage && mSize >= mKeys.length)
{
gc();
// Search again because indices may have changed.
i = ~binarySearch(mKeys, 0, mSize, key);
}
if (mSize >= mKeys.length)
{
int n = Helper.idealIntArraySize(mSize + 1);
int[] nkeys = new int[n];
Object[] nvalues = new Object[n];
// Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
if (mSize - i != 0)
{
// Log.e("SparseArray", "move " + (mSize - i));
System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
}
mKeys[i] = key;
mValues[i] = value;
mSize++;
}
}
/**
* Returns the number of key-value mappings that this SparseArray currently stores.
*/
public int getSize()
{
if (mGarbage)
{
gc();
}
return mSize;
}
/**
* Given an index in the range 0...size()-1
, returns the key from the
* index
th key-value mapping that this SparseArray stores.
*/
public int keyAt( int index )
{
if (mGarbage)
{
gc();
}
return mKeys[index];
}
/**
* Given an index in the range 0...size()-1
, returns the value from the
* index
th key-value mapping that this SparseArray stores.
*/
@SuppressWarnings("unchecked")
public E valueAt( int index )
{
if (mGarbage)
{
gc();
}
return (E) mValues[index];
}
/**
* Given an index in the range 0...size()-1
, sets a new value for the
* index
th key-value mapping that this SparseArray stores.
*/
public void setValueAt( int index, E value )
{
if (mGarbage)
{
gc();
}
mValues[index] = value;
}
/**
* Returns the index for which {@link #keyAt} would return the specified key, or a negative
* number if the specified key is not mapped.
*/
public int indexOfKey( int key )
{
if (mGarbage)
{
gc();
}
return binarySearch(mKeys, 0, mSize, key);
}
/**
* Returns an index for which {@link #valueAt} would return the specified key, or a negative
* number if no keys map to the specified value. Beware that this is a linear search, unlike
* lookups by key, and that multiple keys can map to the same value and this will find only one
* of them.
*/
public int indexOfValue( E value )
{
if (mGarbage)
{
gc();
}
for (int i = 0; i < mSize; i++)
{
if (mValues[i] == value)
{
return i;
}
}
return -1;
}
/**
* Removes all key-value mappings from this SparseArray.
*/
public void clear()
{
trimTo(0);
}
public void trimTo( int size )
{
// let the gc do its work
int max = Math.min(mSize, size);
for (int i = max; i < mSize; i++)
{
mValues[i] = null;
}
mSize = 0;
mGarbage = false;
}
/**
* Puts a key/value pair into the array, optimizing for the case where the key is greater than
* all existing keys in the array.
*/
public void append( int key, E value )
{
if (mSize != 0 && key <= mKeys[mSize - 1])
{
put(key, value);
return;
}
if (mGarbage && mSize >= mKeys.length)
{
gc();
}
int pos = mSize;
if (pos >= mKeys.length)
{
int n = Helper.idealIntArraySize(pos + 1);
int[] nkeys = new int[n];
Object[] nvalues = new Object[n];
// Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
mKeys[pos] = key;
mValues[pos] = value;
mSize = pos + 1;
}
// Warning: returns ~index and not -(index+1) like trove and jdk do
private static int binarySearch( int[] a, int start, int len, int key )
{
int high = start + len, low = start - 1, guess;
while (high - low > 1)
{
guess = (high + low) / 2;
if (a[guess] < key)
{
low = guess;
} else
{
high = guess;
}
}
if (high == start + len)
{
return ~(start + len);
} else if (a[high] == key)
{
return high;
} else
{
return ~high;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy