/* * This file is part of the HyperGraphDB source distribution. This is copyrighted * software. For permitted uses, licensing options and redistribution, please see * the LicensingInformation file at the root level of the distribution. * * Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved. */ package org.hypergraphdb.query.impl; import java.util.NoSuchElementException; import org.hypergraphdb.HGSearchResult; /** * <p> * Combines two result set into a result representing their set theoretic union. It * is assumed that the input sets are ordered and hence that the objects contained * therein are <code>java.lang.Comparable</code> instances. * </p> * * <p> * The produced result set also has its elements in order. * </p> * * @author Borislav Iordanov */ public class UnionResult implements HGSearchResult { // // The left and right result sets. // private HGSearchResult left, right; private boolean leftBOF = false, rightBOF = false, leftEOF=false, rightEOF=false; // // Indicates whether both input sets should be moved because // the last comparison of their "current" elements yielded an // equality. // private boolean move_both = true; // // The input set (left or right) that hold the current element // of the union. // private HGSearchResult last_choice = null; // // IMPLEMENTATION NOTE: to understand how this works, one only // need to go through the logic of either 'next' or 'prev', as the // other is defined in completely analogous way, by symmetry. // private Object select(Comparable L, Comparable R) { int comp = L.compareTo(R); if (comp == 0) { last_choice = left; move_both = true; return L; } else if (comp < 0) { last_choice = left; move_both = false; return L; } else { last_choice = right; move_both = false; return R; } } private Object selectBack(Comparable L, Comparable R) { int comp = L.compareTo(R); if (comp == 0) { last_choice = left; move_both = true; return L; } else if (comp < 0) { last_choice = right; move_both = false; return R; } else { last_choice = left; move_both = false; return L; } } public UnionResult(HGSearchResult left, HGSearchResult right) { this.left = left; this.right = right; } public Object current() { if (last_choice == null) throw new NoSuchElementException(); else return last_choice.current(); } public void close() { left.close(); right.close(); } public Object prev() { if (!hasPrev()) throw new NoSuchElementException(); if (move_both) { if (left.hasPrev()) if (!right.hasPrev()) { last_choice = left; move_both = false; rightBOF = true; return left.prev(); } else return selectBack((Comparable)left.prev(), (Comparable)right.prev()); else { last_choice = right; move_both = false; leftBOF = true; return right.prev(); } } else if (last_choice == left) { if (!left.hasPrev()) { last_choice = right; move_both = false; leftBOF = true; return right.current(); } else if (rightBOF) return left.prev(); else return selectBack((Comparable)left.prev(), (Comparable)right.current()); } else if (last_choice == right) { if (!right.hasPrev()) { last_choice = left; move_both = false; rightBOF = true; return left.current(); } else if (leftBOF) return right.prev(); else return selectBack((Comparable)left.current(), (Comparable)right.prev()); } else throw new NoSuchElementException("This should never be thrown from here!!!"); // we'll never get here } public boolean hasPrev() { if (left.hasPrev()) return true; else if (right.hasPrev()) return true; else if (last_choice == null) return false; else if (last_choice == left && !rightBOF) return ((Comparable)left.current()).compareTo(right.current()) > 0; else if (last_choice == right && !leftBOF) return ((Comparable)right.current()).compareTo(left.current()) > 0; else return false; } public boolean hasNext() { if (left.hasNext()) return true; else if (right.hasNext()) return true; else if (last_choice == null) return false; else if (last_choice == left && !rightEOF) return ((Comparable)left.current()).compareTo(right.current()) < 0; else if (last_choice == right && !leftEOF) return ((Comparable)right.current()).compareTo(left.current()) < 0; else return false; } public Object next() { if (!hasNext()) throw new NoSuchElementException(); if (move_both) { if (left.hasNext()) if (!right.hasNext()) { last_choice = left; move_both = false; rightEOF = true; return left.next(); } else return select((Comparable)left.next(),(Comparable)right.next()); else { last_choice = right; move_both = false; leftEOF = true; return right.next(); } } else if (last_choice == left) { if (!left.hasNext()) { last_choice = right; move_both = false; leftEOF = true; return right.current(); } else if (rightEOF) return left.next(); else return select((Comparable)left.next(), (Comparable)right.current()); } else if (last_choice == right) { if (!right.hasNext()) { last_choice = left; move_both = false; rightEOF = true; return left.current(); } else if (leftEOF) return right.next(); else return select((Comparable)left.current(), (Comparable)right.next()); } else throw new NoSuchElementException("This should never be thrown from here!!!"); // we'll never get here } public void remove() { throw new UnsupportedOperationException(); } public boolean isOrdered() { return true; } }