/* * 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); } } } }