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 createFromSorted( int s2Level, T... ranges)46 public static <T extends S2LevelRange> SortedS2Ranges<T> createFromSorted( 47 int s2Level, T... ranges) { 48 return createFromSorted(s2Level, Arrays.asList(ranges)); 49 } 50 createFromSorted( int s2Level, List<T> ranges)51 public static <T extends S2LevelRange> SortedS2Ranges<T> createFromSorted( 52 int s2Level, List<T> ranges) { 53 // Validate - look for overlapping ranges or ranges of the wrong level. 54 S2LevelRange previousRange = null; 55 for (S2LevelRange currentRange : ranges) { 56 int currentRangeLevel = currentRange.getS2Level(); 57 // Validate all the levels are the same. 58 if (s2Level != currentRangeLevel) { 59 throw new IllegalArgumentException( 60 "currentRange=" + currentRange + " is not at level " + s2Level); 61 } 62 63 if (previousRange != null) { 64 if (previousRange.overlaps(currentRange)) { 65 throw new IllegalArgumentException("previous range " + previousRange 66 + " overlaps next range " + currentRange); 67 } 68 if (!previousRange.startsBefore(currentRange)) { 69 throw new IllegalArgumentException("previous range " + previousRange 70 + " must start before next range " + currentRange); 71 } 72 } 73 74 previousRange = currentRange; 75 } 76 return new SortedS2Ranges<>(s2Level, ranges); 77 } 78 79 /** Returns the S2 level of the ranges. */ getS2Level()80 public int getS2Level() { 81 return mS2Level; 82 } 83 84 /** Returns an unmodifiable list of all of the ranges. */ getRanges()85 public List<T> getRanges() { 86 return mRanges; 87 } 88 89 @Override iterator()90 public Iterator<T> iterator() { 91 return mRanges.iterator(); 92 } 93 94 @Override forEach(Consumer<? super T> action)95 public void forEach(Consumer<? super T> action) { 96 mRanges.forEach(action); 97 } 98 99 @Override spliterator()100 public Spliterator<T> spliterator() { 101 return mRanges.spliterator(); 102 } 103 104 @Override equals(Object o)105 public boolean equals(Object o) { 106 if (this == o) { 107 return true; 108 } 109 if (o == null || getClass() != o.getClass()) { 110 return false; 111 } 112 SortedS2Ranges<?> that = (SortedS2Ranges<?>) o; 113 return mS2Level == that.mS2Level 114 && mRanges.equals(that.mRanges); 115 } 116 117 @Override hashCode()118 public int hashCode() { 119 return Objects.hash(mS2Level, mRanges); 120 } 121 122 @Override toString()123 public String toString() { 124 return "SortedS2Ranges{" 125 + "mS2Level=" + mS2Level 126 + ", mRanges=" + mRanges 127 + '}'; 128 } 129 } 130