/*
* 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.jena.reasoner.rulesys.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.jena.graph.Node ;
/**
* A multi set of BindingVector's divided in buckets matching an unique
* combination of values at given indices managed by RETEQueue
*/
public class BindingVectorMultiSet {
/**
* Inner class used to represent an updatable count.
* Formerly enclosed in RETEQueue
*/
protected static class Count {
/** the count */
int count;
/** Constructor */
public Count(int count) {
this.count = count;
}
/** Decrement the count value */
public void dec() {
count--;
}
/** Access count value */
public int getCount() {
return count;
}
/** Increment the count value */
public void inc() {
count++;
}
/** Set the count value */
public void setCount(int count) {
this.count = count;
}
}
/** Inner representation */
protected Map<BindingVector, Map<BindingVector, Count>> data = new HashMap<>();
/** An array of indices which mark the primary key */
protected byte[] matchIndices;
/**
* Constructor
*
* @param matchIndices
* a set of indices for matching
*/
public BindingVectorMultiSet(byte[] matchIndices) {
this.matchIndices = matchIndices;
}
/**
* Increase the current quantity of env
*
* @param env
*/
public void add(BindingVector env) {
Count c = get(env);
if (c == null) {
put(env, new Count(1));
} else {
c.inc();
}
}
/**
* Get current quantity of BindingVector env
*
* @param env
* @return
*/
protected Count get(BindingVector env) {
Map<BindingVector, Count> set = getRawSubSet(env);
return (set == null ? null : set.get(env));
}
/**
* Create a BindingVector containing only values at matchIndices so it can
* be used as key
*
* @param env
* BindingVector to find the key for
* @return the key BindingVector
*/
protected BindingVector getPartialEnv(BindingVector env) {
Node[] envNodes = env.getEnvironment();
Node[] partialEnv = new Node[envNodes.length];
for (byte i : matchIndices) {
partialEnv[i] = envNodes[i];
}
return new BindingVector(partialEnv);
}
/**
* Get the bucket into which env belongs if it exists
*
* @param env
* @return
*/
protected Map<BindingVector, Count> getRawSubSet(BindingVector env) {
return data.get(getPartialEnv(env));
}
/**
* Get an iterator over all BindingVectors currently present which match
* with env
*
* @param env
*/
public Iterator<BindingVector> getSubSet(BindingVector env) {
Map<BindingVector, Count> rawSubSet = getRawSubSet(env);
return (rawSubSet == null ? new HashMap<BindingVector, Count>(0)
: rawSubSet).keySet().iterator();
}
/**
* Set the quantity of env to a given Count value c
*
* @param env
* @param c
*/
protected void put(BindingVector env, Count c) {
Map<BindingVector, Count> set = getRawSubSet(env);
if (set == null) {
set = new HashMap<>();
data.put(getPartialEnv(env), set);
}
set.put(env, c);
}
/**
* Copy all item from queue.data into data.
* Assumes this and queue share the same matchIndices.
*
* @param queue
*/
public void putAll(BindingVectorMultiSet queue) {
for ( BindingVector env : queue.data.keySet() )
{
Map<BindingVector, Count> set = getRawSubSet( env );
if ( set == null )
{
set = new HashMap<>();
data.put( env, set );
}
set.putAll( queue.data.get( env ) );
}
}
/**
* Decrease the quantity of env
*
* @param env
*/
public void remove(BindingVector env) {
BindingVector key = getPartialEnv(env);
Map<BindingVector, Count> set = data.get(key);
if (set != null) {
Count c = set.get(env);
if (c != null) {
if (c.getCount() > 1) {
c.dec();
} else { // clean up
set.remove(env);
}
}
if (set.isEmpty()) {
data.remove(key);
}
}
}
}