package com.tesora.dve.sql.node; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * 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/>. * #L% */ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.UnaryFunction; public class MultiEdge<O extends LanguageNode, T extends LanguageNode> extends Edge<O,T> implements Iterable<T> { protected List<SubEdge<O,T>> target; public MultiEdge(Class<O> oc, O owner, EdgeName name) { super(oc, owner, name); target = new ArrayList<SubEdge<O,T>>(); } @Override public boolean has() { return !target.isEmpty(); } @Override public boolean isMulti() { return true; } @Override public boolean isMultiMulti() { return false; } public int size() { return target.size(); } public T get(int i) { if (target.isEmpty()) return null; return target.get(i).get(); } public void remove(int i) { target.remove(i); } public T getLast() { if (target.isEmpty()) return null; return target.get(target.size() - 1).get(); } public void removeLast() { if (target.isEmpty()) return; target.remove(target.size() - 1); } public void addAll(Collection<T> in) { for(T t : in) add(t); } public SubEdge<O, T> getEdge(int i) { return target.get(i); } public boolean isEmpty() { return target.isEmpty(); } @Override public T get() { if (target.isEmpty()) return null; return target.get(0).get(); } @Override public List<T> getMulti() { return Collections.unmodifiableList( Functional.apply(target, new UnaryFunction<T, SubEdge<O,T>>() { @Override public T evaluate(SubEdge<O, T> object) { return object.get(); } })); } @Override public void set(T in) { set(Collections.singletonList(in)); } @Override public void set(List<T> in) { for(SubEdge<O, T> se : target) se.clear(); target.clear(); if (in != null) { for(T t : in) target.add(makeSubEdge(t,target.size())); } } public List<SubEdge<O,T>> getEdges() { return target; } @Override public Iterator<T> iterator() { return new MultiEdgeIterator<O,T>(this); } private SubEdge<O,T> makeSubEdge(T o, int offset) { SubEdge<O,T> ose = new SubEdge<O, T>(getParentClass(),getParent(),getName().makeOffset(offset)); ose.set(o); return ose; } @Override public boolean schemaEqual(Edge<O,T> other) { if (other == null) return false; if (!(other instanceof MultiEdge)) return false; MultiEdge<O,T> ome = (MultiEdge<O,T>) other; if (target.size() != ome.target.size()) return false; for(int i = 0; i < target.size(); i++) { if (!target.get(i).schemaEqual(ome.target.get(i))) return false; } return true; } @Override protected int schemaTargetHash() { int result = 0; for(int i = 0; i < target.size(); i++) result = LanguageNode.addSchemaHash(result, target.get(i).schemaHash()); return result; } @SuppressWarnings("unchecked") @Override public void clear() { set(Collections.EMPTY_LIST); } @Override public LanguageNode apply(LanguageNode in) { // should never get these, so this is an error throw new MigrationException("Unmigrated code path: MultiEdge.apply"); } protected static class MultiEdgeIterator<O extends LanguageNode, T extends LanguageNode> implements Iterator<T> { protected MultiEdge<O,T> owner; protected int position; protected MultiEdgeIterator(MultiEdge<O,T> o) { owner = o; position = -1; } @Override public boolean hasNext() { return (position + 1) < owner.getEdges().size(); } @Override public T next() { position++; return owner.getEdge(position).get(); } @Override public void remove() { owner.remove(position); position--; } } @Override public void add(List<T> in) { for(T t: in) add(t); } @Override public void add(T value) { target.add(makeSubEdge(value,target.size())); } }