@Override @SuppressWarnings("unchecked") public String isValid() { String superIsValid = super.isValid(); if (superIsValid != null) return superIsValid; if (intervals.isEmpty()) { return "No intervals specified"; } for (int i = 1; i < intervals.size(); i++) { Interval<T> interval1 = intervals.get(i - 1); Interval<T> interval2 = intervals.get(i); if (!interval1.getMax().equals(interval2.getMin())) { return "Gap between " + interval1 + " and " + interval2; } if (interval1.getMin().equals(interval2.getMin()) && interval1.getMax().equals(interval2.getMax())) { return "Repeating intervals " + interval1 + " and " + interval2; } } DataTypeWithRatioScale<T> type = (DataTypeWithRatioScale<T>) getDataType(); if (lowerRange.getRepeatBound() != null && upperRange.getRepeatBound() != null && type.compare(lowerRange.getRepeatBound(), upperRange.getRepeatBound()) > 0) { return "Lower repeat bound must be < upper repeat bound"; } if (lowerRange.getSnapBound() != null && lowerRange.getRepeatBound() != null && type.compare(lowerRange.getSnapBound(), lowerRange.getRepeatBound()) > 0) { return "Lower snap bound must be <= lower repeat bound"; } if (lowerRange.getLabelBound() != null && lowerRange.getSnapBound() != null && type.compare(lowerRange.getLabelBound(), lowerRange.getSnapBound()) > 0) { return "Lower label bound must be <= lower snap bound"; } if (upperRange.getRepeatBound() != null && upperRange.getSnapBound() != null && type.compare(upperRange.getSnapBound(), upperRange.getRepeatBound()) < 0) { return "Upper snap bound must be >= upper repeat bound"; } if (lowerRange.getLabelBound() != null && upperRange.getSnapBound() != null && type.compare(upperRange.getLabelBound(), upperRange.getSnapBound()) < 0) { return "Upper label bound must be >= upper snap bound"; } return null; }
/** * Add a type to the slice at a given position, possibly changing the endpoints of some descendant * intervals. * * @param type the type to add to the slice * @param position a type already in the slice before which the new type will be placed, <code> * null</code> if the type should be placed at the end of the slice * @param ancestors the new type's ancestors * @return the event for the endpoint changes, though there might be none */ protected EndpointsChangedEvent add(Constant type, Constant position, Set<Constant> ancestors) { EndpointsChangedEvent event = new EndpointsChangedEvent(this, type); order.add(type, position); int typeLambda = lambdas.get(position), positionLambda = typeLambda; Set<Constant> reducedAncestors = new HashSet<Constant>(ancestors); for (Map.Entry<Constant, Interval<Constant>> entry : descendentIntervals.entrySet()) { Interval<Constant> value = entry.getValue(); if (reducedAncestors.remove(entry.getKey())) { if (value.getMin() == position) { ++positionLambda; value.setMin(type); event.addMinChange(entry.getKey()); } if (value.getMax() == position) { ++typeLambda; } } else if (value.getMax() == position) { value.setMax(type); event.addMaxChange(entry.getKey()); } } descendentIntervals.put(type, new Interval<Constant>(order, type, position)); for (Constant ancestor : reducedAncestors) { descendentIntervals.put(ancestor, new Interval<Constant>(order, type, position)); } lambdas.put(type, typeLambda); lambdas.put(position, positionLambda); return event; }
/** * Attempt to add a type to the slice, possibly changing the endpoints of some descendant * intervals. * * @param type the type to add to the slice * @param ancestors the new type's ancestors * @return if the addition was successful, the event for the endpoint changes, though there might * be none; if the addition failed, <code>null</code> */ public EndpointsChangedEvent add(Constant type, Set<Constant> ancestors) { Interval<Constant> common = asInterval(); for (Constant ancestor : ancestors) { Interval<Constant> mask = descendentIntervals.get(ancestor); if (mask != null) { common.intersect(mask); } } // empty is okay, as long as we still have location if (order.compare(common.getMin(), common.getMax()) > 0) { return null; } int surroundMin = 0, surroundMax = 0; for (Constant ancestor : ancestors) { Interval<Constant> range = descendentIntervals.get(ancestor); if (range != null) { if (order.compare(range.getMin(), common.getMin()) < 0 && order.compare(range.getMax(), common.getMin()) > 0) { ++surroundMin; } if (order.compare(range.getMin(), common.getMax()) < 0 && order.compare(range.getMax(), common.getMax()) > 0) { ++surroundMax; } } } if (lambdas.get(common.getMin()) == surroundMin) { return add(type, common.getMin(), ancestors); } if (lambdas.get(common.getMax()) == surroundMax) { return add(type, common.getMax(), ancestors); } //// fast slicing: don't check between min and max return null; }