WALA/com.ibm.wala.util/src/com/ibm/wala/util/collections/TwoLevelVector.java

180 lines
4.3 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.util.collections;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Vector;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.math.Logs;
/**
* An {@link IVector} implementation which delegates to pages of int vectors.
*/
public class TwoLevelVector<T> implements IVector<T>, Serializable {
private static final long serialVersionUID = -835376054736611070L;
private static final int PAGE_SIZE = 4096;
private static final int LOG_PAGE_SIZE = Logs.log2(PAGE_SIZE);
/**
* Array of IVector: data.get(i) holds data[i*PAGE_SIZE] ...
* data[(i+1)*PAGESIZE - 1]
*/
final private Vector<SparseVector<T>> data = new Vector<>(0);
private int maxPage = -1;
/*
* @see com.ibm.wala.util.intset.IntVector#get(int)
*/
@Override
public T get(int x) {
if (x < 0) {
throw new IllegalArgumentException("invalid x: " + x);
}
int page = getPageNumber(x);
if (page >= data.size()) {
return null;
}
IVector<T> v = data.get(page);
if (v == null) {
return null;
}
int localX = x - getFirstIndexOnPage(page);
return v.get(localX);
}
private static int getFirstIndexOnPage(int page) {
return page << LOG_PAGE_SIZE;
}
private static int getPageNumber(int x) {
return x >> LOG_PAGE_SIZE;
}
/*
* TODO: this can be optimized
*
* @see com.ibm.wala.util.intset.IntVector#set(int, int)
*/
@Override
public void set(int x, T value) {
if (x < 0) {
throw new IllegalArgumentException("illegal x: " + x);
}
int page = getPageNumber(x);
IVector<T> v = findOrCreatePage(page);
int localX = toLocalIndex(x, page);
v.set(localX, value);
}
private static int toLocalIndex(int x, int page) {
return x - getFirstIndexOnPage(page);
}
private IVector<T> findOrCreatePage(int page) {
if (page >= data.size()) {
SparseVector<T> v = new SparseVector<>();
data.setSize(page + 1);
data.add(page, v);
maxPage = Math.max(page, maxPage);
return v;
} else {
SparseVector<T> v = data.get(page);
if (v == null) {
v = new SparseVector<>();
data.set(page, v);
maxPage = Math.max(page, maxPage);
}
return v;
}
}
/*
* @see com.ibm.wala.util.debug.VerboseAction#performVerboseAction()
*/
@Override
public void performVerboseAction() {
// do nothing;
}
/*
* @see com.ibm.wala.util.intset.IVector#iterator()
*/
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
final Iterator<SparseVector<T>> outer = data.iterator();
Iterator<T> inner;
{
while (outer.hasNext()) {
IVector<T> v = outer.next();
if (v != null) {
Iterator<T> it = v.iterator();
if (it.hasNext()) {
inner = it;
break;
}
}
}
}
@Override
public boolean hasNext() {
return inner != null;
}
@Override
public T next() {
T result = inner.next();
if (!inner.hasNext()) {
inner = null;
while (outer.hasNext()) {
IVector<T> v = outer.next();
if (v != null) {
Iterator<T> it = v.iterator();
if (it.hasNext()) {
inner = it;
break;
}
}
}
}
return result;
}
@Override
public void remove() {
// TODO Auto-generated method stub
Assertions.UNREACHABLE();
}
};
}
@Override
public int getMaxIndex() {
if (maxPage == -1) {
return -1;
} else {
IVector<T> v = data.get(maxPage);
int localMax = v.getMaxIndex();
return maxPage * PAGE_SIZE + localMax;
}
}
}