blob: 8554e610ab2b2388c3966bba549c2e185d7566b8 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.royale.utils;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Implements a sparse mapping from int -> Object. Iterators will
* traverse from lowest to highest. put() is O(1) if the key is
* higher than any existing key; O(logN) if the key already exists,
* and O(N) otherwise. get() is an O(logN) binary search.
*/
public class IntMap
{
private int[] keys;
private Object[] values;
private int size;
public IntMap()
{
this(10);
}
public IntMap(int capacity)
{
keys = new int[capacity];
values = new Object[capacity];
}
public int capacity()
{
return keys.length;
}
private int find(int k)
{
int lo = 0;
int hi = size-1;
while (lo <= hi)
{
int i = (lo + hi) >>> 1;
int m = keys[i];
if (k > m)
lo = i + 1;
else if (k < m)
hi = i - 1;
else
return i; // key found
}
return -(lo + 1); // key not found, low is the insertion point
}
public Object remove(int k)
{
Object old = null;
int i = find(k);
if (i >= 0)
{
old = values[i];
System.arraycopy(keys, i+1, keys, i, size-i-1);
System.arraycopy(values, i+1, values, i, size-i-1);
size--;
}
return old;
}
public void clear()
{
size = 0;
}
public Object put(int k, Object v)
{
if (size == 0 || k > keys[size-1])
{
if (size == keys.length)
grow();
keys[size] = k;
values[size] = v;
size++;
return null;
}
else
{
int i = find(k);
if (i >= 0)
{
Object old = values[i];
values[i] = v;
return old;
}
else
{
i = -i - 1; // recover the insertion point
if (size == keys.length)
grow();
System.arraycopy(keys,i,keys,i+1,size-i);
System.arraycopy(values,i,values,i+1,size-i);
keys[i] = k;
values[i] = v;
size++;
return null;
}
}
}
private void grow()
{
int[] newkeys = new int[size*2];
System.arraycopy(keys,0,newkeys,0,size);
keys = newkeys;
Object[] newvalues = new Object[size*2];
System.arraycopy(values,0,newvalues,0,size);
values = newvalues;
}
public Object get(int k)
{
int i = find(k);
return i >= 0 ? values[i] : null;
}
public boolean contains(int k)
{
return find(k) >= 0;
}
/**
* A bit of an aberration from an academic point of view,
* but since this is an ordered Map, why not!
*
* @return the element immediately following element k.
*/
public Object getNextAdjacent(int k)
{
int i = find(k);
return ( (i >= 0) && (i+1 < size) ) ? values[i+1] : null;
}
public Iterator<Map.Entry<Integer, Object>> iterator()
{
return new Iterator<Map.Entry<Integer, Object>>()
{
private int i = 0;
@Override
public boolean hasNext()
{
return i < size;
}
@Override
public Map.Entry<Integer, Object> next()
{
if (i >= size)
{
throw new NoSuchElementException();
}
final int j = i++;
return new Map.Entry<Integer, Object>()
{
@Override
public Integer getKey()
{
return keys[j];
}
@Override
public Object getValue()
{
return values[j];
}
@Override
public Object setValue(Object value)
{
Object old = values[j];
values[j] = value;
return old;
}
};
}
@Override
public void remove()
{
System.arraycopy(keys, i, keys, i-1, size-i);
System.arraycopy(values, i, values, i-1, size-i);
size--;
}
};
}
public int size()
{
return size;
}
/**
* @param ar must be of size size().
*/
public Object[] valuesToArray(Object[] ar)
{
System.arraycopy(values, 0, ar, 0, size);
return ar;
}
public int[] keySetToArray()
{
int[] ar = new int[size()];
System.arraycopy(keys, 0, ar, 0, size);
return ar;
}
}