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

com.ibm.wala.util.intset.BasicNaturalRelation Maven / Gradle / Ivy

The newest version!
/*
 * 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.intset;

import static com.ibm.wala.util.nullability.NullabilityUtil.castToNonNull;

import com.ibm.wala.util.collections.IVector;
import com.ibm.wala.util.collections.SimpleVector;
import com.ibm.wala.util.collections.TwoLevelVector;
import com.ibm.wala.util.debug.Assertions;
import java.io.Serializable;
import java.util.Iterator;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;

/**
 * A relation between non-negative integers
 *
 * 

This implementation uses n IntVectors, to hold the first n y's associated with each x, and * then 1 extra vector of SparseIntSet to hold the remaining ys. */ public final class BasicNaturalRelation implements IBinaryNaturalRelation, Serializable { private static final long serialVersionUID = 4483720230344867621L; private static final boolean VERBOSE = false; private static final boolean DEBUG = false; /** Tokens used as enumerated types to control the representation */ public static final byte SIMPLE = 0; public static final byte TWO_LEVEL = 1; public static final byte SIMPLE_SPACE_STINGY = 2; private static final int EMPTY_CODE = -1; private static final int DELEGATE_CODE = -2; /** * smallStore[i][x] holds * *

    *
  • if >=0, the ith integer associated with x *
  • if -2, then use the delegateStore instead of the small store *
  • if -1, then R(x) is empty *
* * represented. */ final IntVector[] smallStore; /** delegateStore[x] holds an int set of the y's s.t. R(x,y) */ final IVector<@Nullable IntSet> delegateStore; /** * @param implementation a set of codes that represent how the first n IntVectors should be * implemented. * @param vectorImpl a code that indicates how to represent the delegateStore. *

For example implementation = * {SIMPLE_INT_VECTOR,TWO_LEVEL_INT_VECTOR,TWO_LEVEL_INT_VECTOR} will result in an * implementation where the first 3 y's associated with each x are represented in IntVectors. * The IntVector for the first y will be implemented with a SimpleIntVector, and the 2nd and * 3rd are implemented with TwoLevelIntVector * @throws IllegalArgumentException if implementation is null * @throws IllegalArgumentException if implementation.length == 0 */ public BasicNaturalRelation(byte[] implementation, byte vectorImpl) throws IllegalArgumentException { if (implementation == null) { throw new IllegalArgumentException("implementation is null"); } if (implementation.length == 0) { throw new IllegalArgumentException("implementation.length == 0"); } smallStore = new IntVector[implementation.length]; for (int i = 0; i < implementation.length; i++) { switch (implementation[i]) { case SIMPLE: smallStore[i] = new SimpleIntVector(EMPTY_CODE); break; case TWO_LEVEL: smallStore[i] = new TwoLevelIntVector(EMPTY_CODE); break; case SIMPLE_SPACE_STINGY: smallStore[i] = new TunedSimpleIntVector(EMPTY_CODE, 1, 1.1f); break; default: throw new IllegalArgumentException("unsupported implementation " + implementation[i]); } } switch (vectorImpl) { case SIMPLE: delegateStore = new SimpleVector<>(); break; case TWO_LEVEL: delegateStore = new TwoLevelVector<>(); break; default: throw new IllegalArgumentException("unsupported implementation " + vectorImpl); } } public BasicNaturalRelation() { this(new byte[] {SIMPLE}, TWO_LEVEL); } /** maximum x for any pair in this relation. */ private int maxX = -1; /** * Add (x,y) to the relation. * *

This is performance-critical, so the implementation looks a little ugly in order to help out * the compiler with redundancy elimination. * * @return true iff the relation changes as a result of this call. */ @NullUnmarked @Override public boolean add(int x, int y) throws IllegalArgumentException { if (x < 0) { throw new IllegalArgumentException("illegal x: " + x); } if (y < 0) { throw new IllegalArgumentException("illegal y: " + y); } maxX = Math.max(maxX, x); MutableIntSet delegated = (MutableIntSet) delegateStore.get(x); if (delegated != null) { return delegated.add(y); } else { IntVector smallStore0 = smallStore[0]; if (smallStore0.get(x) != EMPTY_CODE) { int i = 0; IntVector v = null; int ssLength = smallStore.length; for (; i < ssLength; i++) { v = smallStore[i]; int val = v.get(x); if (val == y) { return false; } else if (val == EMPTY_CODE) { break; } } if (i == ssLength) { MutableIntSet s = new BimodalMutableIntSet(ssLength + 1, 1.1f); delegateStore.set(x, s); for (IntVector vv : smallStore) { s.add(vv.get(x)); vv.set(x, DELEGATE_CODE); } s.add(y); } else { v.set(x, y); } return true; } else { // smallStore[0].get(x) == EMPTY_CODE : just add smallStore0.set(x, y); return true; } } } private boolean usingDelegate(int x) { return smallStore[0].get(x) == DELEGATE_CODE; } @Override public Iterator iterator() { return new TotalIterator(); } private class TotalIterator implements Iterator { /** the next x that will be returned in a pair (x,y), or -1 if not hasNext() */ private int nextX = -1; /** * the source of the next y ... an integer between 0 and smallStore.length .. nextIndex == * smallStore.length means use the delegateIterator */ private int nextIndex = -1; private @Nullable IntIterator delegateIterator = null; TotalIterator() { advanceX(); } private void advanceX() { delegateIterator = null; for (int i = nextX + 1; i <= maxX; i++) { if (anyRelated(i)) { nextX = i; nextIndex = getFirstIndex(i); if (nextIndex == smallStore.length) { IntSet s = castToNonNull(delegateStore.get(i)); assert !s.isEmpty(); delegateIterator = s.intIterator(); } return; } } nextX = -1; } private int getFirstIndex(int x) { if (smallStore[0].get(x) >= 0) { // will get first y for x from smallStore[0][x] return 0; } else { // will get first y for x from delegateStore[x] return smallStore.length; } } @Override public boolean hasNext() { return nextX != -1; } @NullUnmarked @Override public IntPair next() { final IntPair result; if (nextIndex == smallStore.length) { int y = delegateIterator.next(); result = new IntPair(nextX, y); if (!delegateIterator.hasNext()) { advanceX(); } } else { result = new IntPair(nextX, smallStore[nextIndex].get(nextX)); if (nextIndex == (smallStore.length - 1) || smallStore[nextIndex + 1].get(nextX) == EMPTY_CODE) { advanceX(); } else { nextIndex++; } } return result; } @Override public void remove() { Assertions.UNREACHABLE(); } } private IntSet getDelegate(int x) { return castToNonNull(delegateStore.get(x)); } /** * @return true iff there exists pair (x,y) for some y */ @Override public boolean anyRelated(int x) { return smallStore[0].get(x) != EMPTY_CODE; } @NullUnmarked @Override public IntSet getRelated(int x) { if (DEBUG) { assert x >= 0; } int ss0 = smallStore[0].get(x); if (ss0 == EMPTY_CODE) { return null; } else { if (ss0 == DELEGATE_CODE) { return getDelegate(x); } else { int ssLength = smallStore.length; switch (ssLength) { case 2: { int ss1 = smallStore[1].get(x); if (ss1 == EMPTY_CODE) { return SparseIntSet.singleton(ss0); } else { return SparseIntSet.pair(ss0, ss1); } } case 1: return SparseIntSet.singleton(ss0); default: { int ss1 = smallStore[1].get(x); if (ss1 == EMPTY_CODE) { return SparseIntSet.singleton(ss0); } else { MutableSparseIntSet result = MutableSparseIntSet.createMutableSparseIntSet(ssLength); for (IntVector element : smallStore) { if (element.get(x) == EMPTY_CODE) { break; } result.add(element.get(x)); } return result; } } } } } } @Override public int getRelatedCount(int x) throws IllegalArgumentException { if (x < 0) { throw new IllegalArgumentException("x must be greater than zero"); } if (!anyRelated(x)) { return 0; } else { if (usingDelegate(x)) { return getDelegate(x).size(); } else { int result = 0; for (IntVector element : smallStore) { if (element.get(x) == EMPTY_CODE) { break; } result++; } return result; } } } @Override public void remove(int x, int y) { if (x < 0) { throw new IllegalArgumentException("illegal x: " + x); } if (y < 0) { throw new IllegalArgumentException("illegal y: " + y); } if (usingDelegate(x)) { // TODO: switch representation back to small store? MutableIntSet s = (MutableIntSet) castToNonNull(delegateStore.get(x)); s.remove(y); if (s.isEmpty()) { delegateStore.set(x, null); for (IntVector element : smallStore) { element.set(x, EMPTY_CODE); } } } else { for (int i = 0; i < smallStore.length; i++) { if (smallStore[i].get(x) == y) { for (int j = i; j < smallStore.length; j++) { if (j < (smallStore.length - 1)) { smallStore[j].set(x, smallStore[j + 1].get(x)); } else { smallStore[j].set(x, EMPTY_CODE); } } return; } } } } @Override public void removeAll(int x) { for (IntVector element : smallStore) { element.set(x, EMPTY_CODE); } delegateStore.set(x, null); } /** * @see com.ibm.wala.util.debug.VerboseAction#performVerboseAction() */ @Override public void performVerboseAction() { if (VERBOSE) { System.err.println((getClass() + " stats:")); System.err.println(("count: " + countPairs())); System.err.println(("delegate: " + delegateStore.getClass())); delegateStore.performVerboseAction(); for (int i = 0; i < smallStore.length; i++) { System.err.println(("smallStore[" + i + "]: " + smallStore[i].getClass())); } } } /** * This is slow. * * @return the size of this relation, in the number of pairs */ private int countPairs() { int result = 0; for (@SuppressWarnings("unused") Object name : this) { result++; } return result; } @Override public boolean contains(int x, int y) { if (x < 0) { throw new IllegalArgumentException("invalid x: " + x); } if (y < 0) { throw new IllegalArgumentException("invalid y: " + y); } if (usingDelegate(x)) { return getDelegate(x).contains(y); } else { for (IntVector element : smallStore) { if (element.get(x) == y) { return true; } } return false; } } @Override public int maxKeyValue() { return maxX; } @Override public String toString() { StringBuilder result = new StringBuilder(); for (int i = 0; i <= maxX; i++) { result.append(i).append(':'); result.append(getRelated(i)); result.append('\n'); } return result.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy