/* * (c) Copyright 2008 Hewlett-Packard Development Company, LP * All rights reserved. * [See end of file] */ package dev.g2; import org.openjena.atlas.iterator.*; import java.util.Iterator; import org.openjena.atlas.lib.ColumnMap; import org.openjena.atlas.lib.Tuple; import com.hp.hpl.jena.graph.Node; public class TupleDex { // Currently assumes 3-Tuple. // Later support into N-tuple with a M<=N key // Reconsider naming. Index> index = new IndexImpl>() ; ColumnMap colMap ; Transform, Tuple> unmap ; static Iterator> zero = new NullIterator>() ; public TupleDex(ColumnMap cm){ this.colMap = cm ; this.unmap = new Transform, Tuple> () { @Override public Tuple convert(Tuple item) { return colMap.unmap(item) ; }} ; } public boolean add(Tuple tuple) { Node n1 = colMap.fetchSlot(0, tuple) ; Node n2 = colMap.fetchSlot(1, tuple) ; Node n3 = colMap.fetchSlot(2, tuple) ; MultiBunch bunch = index.get(n1) ; // XXX Adjust the MultiBunch implementation as it grows. if ( bunch == null ) { bunch = new MultiBunchSimple() ; index.put(n1, bunch) ; } return bunch.add(n2, n3) ; } public boolean remove(Tuple tuple) { Node n1 = colMap.fetchSlot(0, tuple) ; Node n2 = colMap.fetchSlot(1, tuple) ; Node n3 = colMap.fetchSlot(2, tuple) ; MultiBunch bunch = index.get(n1) ; if ( bunch == null ) return false ; boolean b = bunch.remove(n2, n3) ; // Could adjust the MultiBunch implementation as it shrinks // but if we are doing a lot of removals (e.g. implicit removeAll), then that makes work if ( bunch.isEmpty() ) index.put(n1, null) ; return b ; } public Iterator> find(Tuple tuple) { tuple = colMap.map(tuple) ; Iterator> iter = find(tuple.get(0), tuple.get(1), tuple.get(2)) ; return Iter.map(iter, unmap) ; } private Iterator> find(final Node x, final Node y, Node z) { if ( x == null ) { // X=? (Maybe Y and Z - 4 cases) Iterator iter1 = index.keys() ; IteratorConcat> iter = new IteratorConcat>() ; for ( ; iter1.hasNext() ; ) { Node node1 = iter1.next() ; MultiBunch bunch = index.get(node1) ; // if ( bunch == null ) // continue ; // ???!!! iter.add(find1(node1, bunch, y, z)) ; } return iter ; } MultiBunch bunch = index.get(x) ; if ( bunch == null ) return zero ; if ( y != null ) { if ( z != null ) { // X Y Z - 1 case if ( bunch.contains(y, z) ) return new SingletonIterator>(Tuple.create(x,y,z)) ; else return zero ; } // X Y ? - 1 case Iterator zPart = bunch.iterator(y) ; return find2(x, y, zPart) ; } // y is null. // X ? ? or X ? Z - 2 cases // Total cases: 8 // ----- return find1(x, bunch, y, z) ; } private Iterator> find1(Node x, MultiBunch bunch, final Node y, final Node z) { // if ( bunch == null ) // return zero ; IteratorConcat> iter = new IteratorConcat>() ; Iterator iter1 = bunch.keys() ; for ( ; iter1.hasNext() ; ) { Node key = iter1.next() ; Iterator part3 = bunch.iterator(key) ; Iterator> iter2 = find2(x, key, part3) ; iter.add(iter2) ; } if ( y == null && z == null ) return iter ; // Some sort of scan. Filter> filter = new Filter>() { @Override public boolean accept(Tuple tuple) { if ( y != null && !y.equals(tuple.get(1)) ) return false ; if ( z != null && !z.equals(tuple.get(2)) ) return false ; return true ; }} ; return Iter.filter(iter, filter) ; } private Iterator> find2(final Node x, final Node y, Iterator part) { Transform> t = new Transform>(){ @Override public Tuple convert(Node item) { return Tuple.create(x, y, item) ; }} ; Iterator> iter2 = Iter.map(part, t) ; return iter2 ; } private static void checkNotNull(Node x) { if ( x == null ) throw new RuntimeException("Null") ; } private static void checkNull(Node x) { if ( x != null ) throw new RuntimeException("Not null: "+x) ; } public int weight(Tuple tuple) { // System.out.println("Index: "+this) ; // System.out.println("Weight: "+tuple) ; // // System.out.println(" "+colMap.fetchSlot(0, tuple)) ; // System.out.println(" "+colMap.fetchSlot(1, tuple)) ; // System.out.println(" "+colMap.fetchSlot(2, tuple)) ; // System.out.println("Mapped: "+colMap.map(tuple)) ; // if ( undef(colMap.fetchSlot(0, tuple)) ) return 0 ; if ( undef(colMap.fetchSlot(1, tuple)) ) return 1 ; if ( undef(colMap.fetchSlot(2, tuple)) ) return 2 ; return 3 ; } private boolean undef(Object x) { return x == null ; } @Override public String toString() { return label() ; } public String label() { return colMap.getLabel() ; } } /* * (c) Copyright 2008 Hewlett-Packard Development Company, LP * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */