/* * Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.nic.graph.impl; import org.opendaylight.nic.graph.api.Term; import org.opendaylight.nic.graph.api.TermLabel; import org.opendaylight.nic.graph.api.TermType; import java.util.*; public final class TermImpl implements Term { private final TermType type; private final List<IntervalImpl> intervals; @Override public TermLabel typeLabel() { return type.label(); } @Override public List<IntervalImpl> getIntervals() { return intervals; } @Override public boolean isEmpty() { return (intervals.isEmpty()); } /** * @param tt term * @return term */ public static TermImpl getInstance(TermType tt) { return new TermImpl(tt); } /** * @param type term type * @param interval interval type * @return term */ public static TermImpl getInstance(TermType type, IntervalImpl interval) { if (interval.isNull() || !type.isLegal(interval)) { return getInstance(type); } return new TermImpl(type, interval, false); } /** * @param type term type * @return term */ public static TermImpl getInstanceMax(TermType type) { IntervalImpl in = IntervalImpl.getInstance(type.min(), type.max()); return new TermImpl(type, in, true); } /** * @param type term type * @param intervalCollection collection of interval * @return term */ public static TermImpl getInstance(TermType type, Collection<IntervalImpl> intervalCollection) { return new TermImpl(type, intervalCollection); } /** * @return term */ TermType getType() { return type; } /** * @param in interval * @param allowMax boolean */ private void addInterval(IntervalImpl in, boolean allowMax) { if (type.isMax(in)) { if (allowMax) { intervals.add(in); } return; } intervals.add(in); } /** * @param type term type * @param interval interval * @param allowMax boolean */ private TermImpl(TermType type, IntervalImpl interval, boolean allowMax) { this.type = type; intervals = new LinkedList<IntervalImpl>(); addInterval(interval, allowMax); } /** * @param type term type */ private TermImpl(TermType type) { this.type = type; intervals = new LinkedList<IntervalImpl>(); } /** * @param type term type * @param intervalCollection interval */ public TermImpl(TermType type, Collection<IntervalImpl> intervalCollection) { this.type = type; intervals = new LinkedList<IntervalImpl>(); for (IntervalImpl in : intervalCollection) { if (type.isLegal(in)) { addInterval(in, false); } } IntervalImpl.sortAndCombine(intervals); } @Override public String toString() { return "Term {type:" + type + intervals + "}"; } /** * Method performs operator "greater than" logic: this "greater than" other. * <p> * Returns True if the {@link TermTypeImpl}s are the same and every * {@link IntervalImpl} in other are contained by Intervals in this. Terms * are sorted and combined, so no overlaps or adjacent Intervals exist. * @param other term * @return boolean */ public boolean greaterThan(TermImpl other) { if (this.type != other.getType()) { return false; } for (IntervalImpl otherI : other.getIntervals()) { boolean found = false; for (IntervalImpl in : intervals) { if (in.greaterThan(otherI)) { found = true; continue; } } if (!found) { return false; } } return true; } /** * Method performs operator "less than" logic: this "less than" other. * <p> * Returns True if the {@link TermTypeImpl}s are the same and every * {@link IntervalImpl} in this are contained by Intervals in other. Terms * are sorted and combined, so no overlaps or adjacent Intervals exist. * @param other term * @return boolean * */ public boolean lessThan(TermImpl other) { return other.greaterThan(this); } /** * The <em>add</em> operator is union of this and other Term. * <p> * Performs union of the list of {@link IntervalImpl}s. * @param other term * @return term */ public TermImpl add(TermImpl other) { if (!(this.type == other.getType())) { return this; } Collection<IntervalImpl> co = new HashSet<IntervalImpl>(); co.addAll(intervals); co.addAll(other.getIntervals()); return getInstance(this.type, co); } /** * The <em>and</em> operator is intersection of this and the other Term. * <p> * Performs and of the list of {@link IntervalImpl}s. * @param other term * @return term */ public TermImpl and(TermImpl other) { if (!(this.type == other.getType())) { return getInstance(this.type); } Collection<IntervalImpl> co = new HashSet<IntervalImpl>(); for (IntervalImpl in : this.intervals) { for (IntervalImpl in2 : other.getIntervals()) { IntervalImpl overlap = in.and(in2); if (!overlap.isNull()) { co.add(overlap); } } } return getInstance(this.type, co); } /** * The <em>sub</em> operator is intersection of this and the other Term. * <p> * Performs and of the list of {@link IntervalImpl}s. * @param other term * @return term */ public TermImpl sub(TermImpl other) { if (!(this.type == other.getType())) { return this; } // this holds intervals which are resolved // since other is sorted, once the 'o' is past a 'w', the 'w' is // resolved Collection<IntervalImpl> resolved = new HashSet<IntervalImpl>(); Collection<IntervalImpl> unresolved = new HashSet<IntervalImpl>( this.getIntervals()); // loop across the Intervals to subtract 'o' for (IntervalImpl in : other.getIntervals()) { // base the working set off of the current result List<IntervalImpl> workingSet = new LinkedList<IntervalImpl>( unresolved); Collections.sort(workingSet); unresolved.clear(); // loop over intervals being subtracted from 'w' int windex = 0; // used to efficiently calculate sublists for (IntervalImpl wo : workingSet) { // if o is past w, move w to resolved if (wo.end() < in.start()) { resolved.add(wo); windex++; continue; // continue the current 'o', move to next 'w' } // if the subtracted Interval is before the working set // Interval, // then move the rest of working set unresolved and move to the // next 'o' if (wo.start() > in.end()) { unresolved.addAll(workingSet.subList(windex, workingSet.size())); break; } // 'o' is not past or before 'w', so subtract them List<IntervalImpl> newIntervalList = wo.sub(in); if (!newIntervalList.get(0).isNull()) { unresolved.addAll(newIntervalList); } windex++; // move to next 'w' } } resolved.addAll(unresolved); return getInstance(this.type, resolved); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((intervals == null) ? 0 : intervals.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } public boolean notEquals(Object obj) { return !equals(obj); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } TermImpl other = (TermImpl) obj; if (intervals == null) { if (other.intervals != null) { return false; } } else if (!intervals.equals(other.intervals)) { return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } return true; } }