1/* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15package com.google.common.collect; 16 17import static com.google.common.base.Preconditions.checkArgument; 18import static com.google.common.base.Preconditions.checkNotNull; 19import static com.google.common.collect.BoundType.CLOSED; 20 21import com.google.common.annotations.GwtCompatible; 22 23import java.util.Collection; 24 25import javax.annotation.Nullable; 26 27/** 28 * An implementation of {@link ContiguousSet} that contains one or more elements. 29 * 30 * @author Gregory Kick 31 */ 32@GwtCompatible(emulated = true) 33@SuppressWarnings("unchecked") // allow ungenerified Comparable types 34final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C> { 35 private final Range<C> range; 36 37 RegularContiguousSet(Range<C> range, DiscreteDomain<C> domain) { 38 super(domain); 39 this.range = range; 40 } 41 42 // Abstract method doesn't exist in GWT emulation 43 /* @Override */ ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) { 44 return range.intersection(Ranges.upTo(toElement, BoundType.forBoolean(inclusive))) 45 .asSet(domain); 46 } 47 48 // Abstract method doesn't exist in GWT emulation 49 /* @Override */ int indexOf(Object target) { 50 return contains(target) ? (int) domain.distance(first(), (C) target) : -1; 51 } 52 53 // Abstract method doesn't exist in GWT emulation 54 /* @Override */ ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement, 55 boolean toInclusive) { 56 return range.intersection(Ranges.range(fromElement, BoundType.forBoolean(fromInclusive), 57 toElement, BoundType.forBoolean(toInclusive))).asSet(domain); 58 } 59 60 // Abstract method doesn't exist in GWT emulation 61 /* @Override */ ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) { 62 return range.intersection(Ranges.downTo(fromElement, BoundType.forBoolean(inclusive))) 63 .asSet(domain); 64 } 65 66 @Override public UnmodifiableIterator<C> iterator() { 67 return new AbstractLinkedIterator<C>(first()) { 68 final C last = last(); 69 70 @Override 71 protected C computeNext(C previous) { 72 return equalsOrThrow(previous, last) ? null : domain.next(previous); 73 } 74 }; 75 } 76 77 private static boolean equalsOrThrow(Comparable<?> left, @Nullable Comparable<?> right) { 78 return right != null && Range.compareOrThrow(left, right) == 0; 79 } 80 81 @Override boolean isPartialView() { 82 return false; 83 } 84 85 @Override public C first() { 86 return range.lowerBound.leastValueAbove(domain); 87 } 88 89 @Override public C last() { 90 return range.upperBound.greatestValueBelow(domain); 91 } 92 93 @Override public int size() { 94 long distance = domain.distance(first(), last()); 95 return (distance >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) distance + 1; 96 } 97 98 @Override public boolean contains(Object object) { 99 try { 100 return range.contains((C) object); 101 } catch (ClassCastException e) { 102 return false; 103 } 104 } 105 106 @Override public boolean containsAll(Collection<?> targets) { 107 try { 108 return range.containsAll((Iterable<? extends C>) targets); 109 } catch (ClassCastException e) { 110 return false; 111 } 112 } 113 114 @Override public boolean isEmpty() { 115 return false; 116 } 117 118 // copied to make sure not to use the GWT-emulated version 119 @Override public Object[] toArray() { 120 return ObjectArrays.toArrayImpl(this); 121 } 122 123 // copied to make sure not to use the GWT-emulated version 124 @Override public <T> T[] toArray(T[] other) { 125 return ObjectArrays.toArrayImpl(this, other); 126 } 127 128 @Override public ContiguousSet<C> intersection(ContiguousSet<C> other) { 129 checkNotNull(other); 130 checkArgument(this.domain.equals(other.domain)); 131 if (other.isEmpty()) { 132 return other; 133 } else { 134 C lowerEndpoint = Ordering.natural().max(this.first(), other.first()); 135 C upperEndpoint = Ordering.natural().min(this.last(), other.last()); 136 return (lowerEndpoint.compareTo(upperEndpoint) < 0) 137 ? Ranges.closed(lowerEndpoint, upperEndpoint).asSet(domain) 138 : new EmptyContiguousSet<C>(domain); 139 } 140 } 141 142 @Override public Range<C> range() { 143 return range(CLOSED, CLOSED); 144 } 145 146 @Override public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) { 147 return Ranges.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain), 148 range.upperBound.withUpperBoundType(upperBoundType, domain)); 149 } 150 151 @Override public boolean equals(Object object) { 152 if (object == this) { 153 return true; 154 } else if (object instanceof RegularContiguousSet<?>) { 155 RegularContiguousSet<?> that = (RegularContiguousSet<?>) object; 156 if (this.domain.equals(that.domain)) { 157 return this.first().equals(that.first()) 158 && this.last().equals(that.last()); 159 } 160 } 161 return super.equals(object); 162 } 163 164 // copied to make sure not to use the GWT-emulated version 165 @Override public int hashCode() { 166 return Sets.hashCodeImpl(this); 167 } 168 169 private static final long serialVersionUID = 0; 170} 171 172