1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.timezone.location.storage.s2; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.Collections; 22 import java.util.Iterator; 23 import java.util.List; 24 import java.util.Objects; 25 import java.util.Spliterator; 26 import java.util.function.Consumer; 27 28 /** 29 * Wraps a collection of {@link S2LevelRange} objects, sorted by {@link 30 * S2LevelRange#getStartCellId()} that must all be at the same level and must not overlap. Gaps 31 * are permitted. 32 * 33 * @param <T> the exact subtype of {@link S2LevelRange} 34 */ 35 public final class SortedS2Ranges<T extends S2LevelRange> implements Iterable<T> { 36 37 private final int mS2Level; 38 39 private final List<T> mRanges; 40 SortedS2Ranges(int s2Level, List<T> ranges)41 private SortedS2Ranges(int s2Level, List<T> ranges) { 42 mS2Level = s2Level; 43 mRanges = Collections.unmodifiableList(new ArrayList<>(ranges)); 44 } 45 46 /** 47 * Creates a {@link SortedS2Ranges} from a pre-sorted set of ranges with the same S2 level. 48 * 49 * @thorws IllegalArgumentException if the ranges are at different levels, ranges are not 50 * sorted, or ranges overlap 51 */ createFromSorted( int s2Level, T... ranges)52 public static <T extends S2LevelRange> SortedS2Ranges<T> createFromSorted( 53 int s2Level, T... ranges) { 54 return createFromSorted(s2Level, Arrays.asList(ranges)); 55 } 56 57 /** 58 * Creates a {@link SortedS2Ranges} from a pre-sorted set of ranges with the same S2 level. 59 * 60 * @thorws IllegalArgumentException if the ranges are at different levels, ranges are not 61 * sorted, or ranges overlap 62 */ createFromSorted( int s2Level, List<T> ranges)63 public static <T extends S2LevelRange> SortedS2Ranges<T> createFromSorted( 64 int s2Level, List<T> ranges) { 65 // Validate - look for overlapping ranges or ranges of the wrong level. 66 S2LevelRange previousRange = null; 67 for (S2LevelRange currentRange : ranges) { 68 int currentRangeLevel = currentRange.getS2Level(); 69 // Validate all the levels are the same. 70 if (s2Level != currentRangeLevel) { 71 throw new IllegalArgumentException( 72 "currentRange=" + currentRange + " is not at level " + s2Level); 73 } 74 75 if (previousRange != null) { 76 if (previousRange.overlaps(currentRange)) { 77 throw new IllegalArgumentException("previous range " + previousRange 78 + " overlaps next range " + currentRange); 79 } 80 if (!previousRange.startsBefore(currentRange)) { 81 throw new IllegalArgumentException("previous range " + previousRange 82 + " must start before next range " + currentRange); 83 } 84 } 85 86 previousRange = currentRange; 87 } 88 return new SortedS2Ranges<>(s2Level, ranges); 89 } 90 91 /** Returns the S2 level of the ranges. */ getS2Level()92 public int getS2Level() { 93 return mS2Level; 94 } 95 96 /** Returns an unmodifiable list of all of the ranges. */ getRanges()97 public List<T> getRanges() { 98 return mRanges; 99 } 100 101 @Override iterator()102 public Iterator<T> iterator() { 103 return mRanges.iterator(); 104 } 105 106 @Override forEach(Consumer<? super T> action)107 public void forEach(Consumer<? super T> action) { 108 mRanges.forEach(action); 109 } 110 111 @Override spliterator()112 public Spliterator<T> spliterator() { 113 return mRanges.spliterator(); 114 } 115 116 @Override equals(Object o)117 public boolean equals(Object o) { 118 if (this == o) { 119 return true; 120 } 121 if (o == null || getClass() != o.getClass()) { 122 return false; 123 } 124 SortedS2Ranges<?> that = (SortedS2Ranges<?>) o; 125 return mS2Level == that.mS2Level 126 && mRanges.equals(that.mRanges); 127 } 128 129 @Override hashCode()130 public int hashCode() { 131 return Objects.hash(mS2Level, mRanges); 132 } 133 134 @Override toString()135 public String toString() { 136 return "SortedS2Ranges{" 137 + "mS2Level=" + mS2Level 138 + ", mRanges=" + mRanges 139 + '}'; 140 } 141 } 142