package com.revolsys.collection.range; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import com.revolsys.collection.iterator.MultiIterator; import com.revolsys.collection.list.Lists; import com.revolsys.datatype.DataType; import com.revolsys.geometry.model.End; import com.revolsys.util.Emptyable; import com.revolsys.util.Property; import com.revolsys.util.Strings; public class RangeSet extends AbstractSet<Object> implements Iterable<Object>, Emptyable, Cloneable { private static void addPart(final RangeSet set, final List<AbstractRange<?>> crossProductRanges, final String fromValue, final String rangeSpec, final int partStart, final int partEnd) { final String toValue = rangeSpec.substring(partStart, partEnd); final AbstractRange<?> partRange = Ranges.newRange(fromValue, toValue); if (crossProductRanges == null) { set.addRange(partRange); } else { crossProductRanges.add(partRange); } } public static RangeSet newRangeSet(final int from, final int to) { final RangeSet range = new RangeSet(); range.addRange(from, to); return range; } public static RangeSet newRangeSet(final String rangeSpec) { final RangeSet set = new RangeSet(); if (Property.hasValue(rangeSpec)) { int partStart = 0; int partEnd = 0; boolean inRange = false; String rangeFirstPart = null; List<AbstractRange<?>> crossProductRanges = null; final int charCount = rangeSpec.length(); for (int i = 0; i < charCount; i++) { final char character = rangeSpec.charAt(i); if (!Character.isWhitespace(character)) { switch (character) { case '+': if (crossProductRanges == null) { crossProductRanges = new ArrayList<>(); } addPart(set, crossProductRanges, rangeFirstPart, rangeSpec, partStart, partEnd); partStart = i + 1; inRange = false; break; case '~': if (inRange) { throw new RangeInvalidException( "The ~ character cannot be used twice in a range, see *~* in " + rangeSpec.substring(0, i) + "*~*" + rangeSpec.substring(i + 1)); } else { rangeFirstPart = rangeSpec.substring(partStart, partEnd); partStart = i + 1; inRange = true; } break; case ',': addPart(set, crossProductRanges, rangeFirstPart, rangeSpec, partStart, partEnd); if (crossProductRanges != null) { set.add(new CrossProductRange(crossProductRanges)); } partStart = i + 1; inRange = false; rangeFirstPart = null; crossProductRanges = null; break; } } partEnd = i + 1; } if (partStart < charCount) { addPart(set, crossProductRanges, rangeFirstPart, rangeSpec, partStart, partEnd); } if (crossProductRanges != null) { set.addRange(new CrossProductRange(crossProductRanges)); } } return set; } private final List<AbstractRange<?>> ranges = new LinkedList<>(); private int size; public RangeSet() { } public RangeSet(final Iterable<Integer> values) { addValues(values); } public RangeSet(final RangeSet rangeSet) { addRanges(rangeSet); } @Override public boolean add(final Object value) { if (value == null) { return false; } else if (value instanceof AbstractRange<?>) { final AbstractRange<?> range = (AbstractRange<?>)value; return addRange(range); } else if (value instanceof RangeSet) { final RangeSet ranges = (RangeSet)value; return addRanges(ranges); } else { for (final ListIterator<AbstractRange<?>> iterator = this.ranges.listIterator(); iterator .hasNext();) { final AbstractRange<?> range = iterator.next(); AbstractRange<?> newRange = range.expand(value); if (range == newRange) { return false; } else if (newRange != null) { this.size++; if (iterator.hasNext()) { final int nextIndex = iterator.nextIndex(); final AbstractRange<?> nextRange = this.ranges.get(nextIndex); final AbstractRange<?> expandedRange = newRange.expand(nextRange); if (expandedRange != null) { newRange = expandedRange; iterator.next(); iterator.remove(); iterator.previous(); } } iterator.set(newRange); return true; } else if (range.compareFromValue(value) > 0) { iterator.previous(); iterator.add(Ranges.newRange(value)); return true; } } this.ranges.add(Ranges.newRange(value)); this.size++; return true; } } public boolean addRange(final AbstractRange<?> addRange) { boolean added = false; if (addRange != null && addRange.size() > 0) { for (final ListIterator<AbstractRange<?>> iterator = this.ranges.listIterator(); iterator .hasNext();) { final AbstractRange<?> range = iterator.next(); AbstractRange<?> newRange = range.expand(addRange); if (range == newRange) { return false; } else if (newRange != null) { this.size -= range.size(); this.size += newRange.size(); if (iterator.hasNext()) { final int nextIndex = iterator.nextIndex(); final AbstractRange<?> nextRange = this.ranges.get(nextIndex); final AbstractRange<?> expandedRange = newRange.expand(nextRange); if (expandedRange != null) { this.size -= newRange.size(); this.size -= nextRange.size(); newRange = expandedRange; iterator.next(); iterator.remove(); iterator.previous(); this.size += newRange.size(); } } iterator.set(newRange); added = true; } else if (!added && range.compareFromValue(addRange.getFrom()) > 0 && (iterator.previousIndex() == 0 || range.compareFromValue(addRange.getTo()) > 0)) { this.ranges.add(iterator.previousIndex(), addRange); this.size += addRange.size(); return true; } } if (!added) { this.ranges.add(addRange); this.size += addRange.size(); } } return added; } public boolean addRange(final char from, final char to) { final AbstractRange<?> addRange = Ranges.newRange(from, to); return addRange(addRange); } public boolean addRange(final int from, final int to) { final IntRange addRange = new IntRange(from, to); return addRange(addRange); } public boolean addRange(final Object from, final Object to) { final AbstractRange<?> addRange = Ranges.newRange(from, to); return addRange(addRange); } public boolean addRanges(final RangeSet ranges) { boolean added = false; if (ranges != null) { for (final AbstractRange<?> range : ranges.getRanges()) { added |= addRange(range); } } return added; } public boolean addValues(final Iterable<? extends Number> values) { boolean added = false; for (final Number value : values) { added |= add(value); } return added; } @Override public void clear() { this.ranges.clear(); this.size = 0; } @Override public RangeSet clone() { return new RangeSet(this); } @Override public boolean contains(final Object object) { if (object != null) { for (final ListIterator<AbstractRange<?>> iterator = this.ranges.listIterator(); iterator .hasNext();) { final AbstractRange<?> range = iterator.next(); if (range.contains(object)) { return true; } } } return false; } public boolean equalEnd(final RangeSet ranges, final End end) { final Object value1 = getEndValue(end); final Object value2 = ranges.getEndValue(end); return DataType.equal(value1, value2); } public Object getEndValue(final End end) { if (!isEmpty()) { if (End.isFrom(end)) { final AbstractRange<?> range = this.ranges.get(0); return range.getFrom(); } else if (End.isTo(end)) { final AbstractRange<?> range = this.ranges.get(this.ranges.size() - 1); return range.getTo(); } } return null; } public List<AbstractRange<?>> getRanges() { return new ArrayList<>(this.ranges); } @Override public boolean isEmpty() { return this.size == 0; } @Override public Iterator<Object> iterator() { return new MultiIterator<>(this.ranges); } @Override public boolean remove(final Object value) { for (final ListIterator<AbstractRange<?>> iterator = this.ranges.listIterator(); iterator .hasNext();) { final AbstractRange<?> range = iterator.next(); if (range.contains(value)) { final Object from = range.getFrom(); final Object to = range.getTo(); if (DataType.equal(from, value)) { if (DataType.equal(to, value)) { iterator.remove(); } else { final Object next = range.next(value); final AbstractRange<?> newRange = range.newRange(next, to); iterator.set(newRange); } this.size--; return true; } else if (DataType.equal(to, value)) { final Object previous = range.previous(value); final AbstractRange<?> newRange = range.newRange(from, previous); iterator.set(newRange); this.size--; return true; } else { final Object previous = range.previous(value); final AbstractRange<?> newRange1 = range.newRange(from, previous); iterator.set(newRange1); final Object next = range.next(value); final AbstractRange<?> newRange2 = range.newRange(next, to); iterator.add(newRange2); this.size--; return true; } } } return false; } public boolean removeAll(final Iterable<Object> values) { boolean removed = false; for (final Object value : values) { removed |= remove(value); } return removed; } @SuppressWarnings("unchecked") public <V> V removeFirst() { if (size() == 0) { return null; } else { final AbstractRange<?> range = this.ranges.get(0); final Object value = range.getFrom(); remove(value); return (V)value; } } public boolean removeRange(final AbstractRange<?> range) { boolean removed = false; for (final Object object : range) { removed |= remove(object); } return removed; } public boolean removeRange(final Object from, final Object to) { boolean removed = false; for (final ListIterator<AbstractRange<?>> iterator = this.ranges.listIterator(); iterator .hasNext();) { final AbstractRange<?> range = iterator.next(); final Object rangeFrom = range.getFrom(); final Object rangeTo = range.getTo(); if (range.compareFromValue(from) >= 0) { if (range.compareFromValue(to) > 0) { return removed; } else if (range.compareToValue(to) <= 0) { iterator.remove(); } else { final Object next = range.next(to); final AbstractRange<?> newRange = range.newRange(next, rangeTo); this.size -= range.size(); this.size += newRange.size(); iterator.set(newRange); } } else if (range.compareToValue(from) >= 0) { if (range.compareToValue(to) > 0) { final Object next = range.next(to); final Object previous = range.previous(from); final AbstractRange<?> newRange1 = range.newRange(rangeFrom, previous); iterator.set(newRange1); final AbstractRange<?> newRange2 = range.newRange(next, rangeTo); iterator.add(newRange2); this.size -= range.size(); this.size += newRange1.size(); this.size += newRange2.size(); } else { final Object previous = range.previous(from); final AbstractRange<?> newRange = range.newRange(rangeFrom, previous); this.size -= range.size(); this.size += newRange.size(); iterator.set(newRange); if (to == rangeTo) { return true; } removed = true; } } } return removed; } public boolean removeRange(final RangeSet ranges) { boolean removed = false; for (final AbstractRange<?> range : ranges.ranges) { removed |= removeRange(range); } return removed; } @Override public int size() { return this.size; } public List<Object> toList() { return Lists.toArray(this); } @Override public String toString() { return Strings.toString(",", this.ranges); } }