/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.qp.rowtype;
import com.foundationdb.ais.model.Table;
import java.util.*;
public class SingleBranchTypeComposition extends TypeComposition
{
/**
* Indicates whether this is an ancestor of that: this is identical to that, or:
* - the tables comprising this and that are disjoint, and
* - the rootmost table of that has an ancestor among the tables of this.
* @param typeComposition
* @return true if this is an ancestor of that, false otherwise.
*/
public boolean isAncestorOf(TypeComposition typeComposition)
{
Boolean ancestor;
SingleBranchTypeComposition that = (SingleBranchTypeComposition) typeComposition;
if (this == that) {
ancestor = Boolean.TRUE;
} else {
ancestor = ancestorOf.get(that.rowType);
if (ancestor == null) {
// Check for tables in common
ancestor = Boolean.TRUE;
for (Table table : that.tables) {
if (this.tables.contains(table)) {
ancestor = Boolean.FALSE;
}
}
if (ancestor) {
ancestor = levelsApart(that) > 0;
}
ancestorOf.put(that.rowType, ancestor);
}
}
return ancestor;
}
/**
* Indicates whether this is a parentof that: this is not identical to that, and:
* - the tables comprising this and that are disjoint, and
* - the rootmost table's parent is among the tables of this.
* @param typeComposition
* @return true if this is an ancestor of that, false otherwise.
*/
public boolean isParentOf(TypeComposition typeComposition)
{
boolean ancestor;
SingleBranchTypeComposition that = (SingleBranchTypeComposition) typeComposition;
if (this == that) {
ancestor = false;
} else {
ancestor = isAncestorOf(that);
if (ancestor) {
ancestor = levelsApart(that) > 0;
}
}
return ancestor;
}
public SingleBranchTypeComposition(RowType rowType, Table table)
{
this(rowType, Arrays.asList(table));
}
public SingleBranchTypeComposition(RowType rowType, Collection<Table> tables)
{
super(rowType, tables);
}
// For use by this class
// If this is an ancestor of that, then the return value is the number of generations separating the two.
// (parent = 1). If this is not an ancestor of that, return -1.
public int levelsApart(SingleBranchTypeComposition that)
{
// Find rootmost table in that
Table thatRoot = that.tables.iterator().next();
while (thatRoot.getParentTable() != null && that.tables.contains(thatRoot.getParentTable())) {
thatRoot = thatRoot.getParentTable();
}
// this is an ancestor of that if that's rootmost table has an ancestor in this.
int generationsApart = 0;
Table thatAncestor = thatRoot;
boolean ancestor = false;
while (thatAncestor != null && !ancestor) {
thatAncestor = thatAncestor.getParentTable();
ancestor = this.tables.contains(thatAncestor);
generationsApart++;
}
return ancestor ? generationsApart : -1;
}
// Object state
private final Map<RowType, Boolean> ancestorOf = new HashMap<>();
}