/** * Performs a binary search on the given sorted list using the given comparator. * This method has undefined behavior if the list is not sorted. * <p> * This method is different than that in java.util.Collections in the following ways: * 1. This one searches by a simple comparator, vs the ones in the Collections class which search for a specific element. * This one is useful if we don't have an instance of a search object or we want to implement a fuzzy comparison. * 2. This one returns -1 if the element is not found. The ones in the Collections class return (-(start+1)), which is * the index where the item should be inserted if it were to go in the list. * * @param list The list to search on. * @param comparator The comparator to use for comparison. Returns -1 if sought item is before the current item, * +1 if it is after or 0 if an exact match. * @param <T> Type of the elements in the list. * @return The index of the sought item, or -1 if not found. */ public static <T> int binarySearch(List<? extends T> list, Function<? super T, Integer> comparator) { return binarySearch(list, comparator, false); }
private static int getGreatestLowerBound(RetentionSet set, long value, Function<StreamCutReferenceRecord, Long> func) { return CollectionHelpers.findGreatestLowerBound(set.retentionRecords, x -> Long.compare(value, func.apply(x))); }
@Override public Collection<Long> values() { synchronized (StreamSegmentMetadata.this) { return CollectionHelpers.joinCollections( coreAttributes.values(), Callbacks::identity, extendedAttributes.values(), e -> e.value); } }
@Override public Set<UUID> keySet() { synchronized (StreamSegmentMetadata.this) { return CollectionHelpers.joinSets(coreAttributes.keySet(), extendedAttributes.keySet()); } }
Collection<Integer> containersToBeStarted = CollectionHelpers.filterOut(desiredList, runningContainers); containersToBeStarted = CollectionHelpers.filterOut(containersToBeStarted, containersPendingTasks); Collection<Integer> containersToBeStopped = CollectionHelpers.filterOut(runningContainers, desiredList); containersToBeStopped = CollectionHelpers.filterOut(containersToBeStopped, containersPendingTasks);
@Override public Set<Map.Entry<UUID, Long>> entrySet() { synchronized (StreamSegmentMetadata.this) { return CollectionHelpers.joinSets( coreAttributes.entrySet(), Callbacks::identity, extendedAttributes.entrySet(), e -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(), e.getValue().value)); } }
/** * Tests the filterOut method. */ @Test public void testFilterOut() { int size = 100; val collection = createCollection(0, size); val emptyRemoveResult = CollectionHelpers.filterOut(collection, Collections.emptySet()); AssertExtensions.assertContainsSameElements("Unexpected result with empty toExclude.", collection, emptyRemoveResult); val noMatchResult = CollectionHelpers.filterOut(collection, Collections.singleton(size + 1)); AssertExtensions.assertContainsSameElements("Unexpected result with no-match toExclude.", collection, noMatchResult); for (int i = 0; i < size; i++) { val toExclude = createCollection(0, i); val expectedResult = createCollection(i, size); val filterResult = CollectionHelpers.filterOut(collection, toExclude); AssertExtensions.assertContainsSameElements("Unexpected result from filterOut for i = " + i, expectedResult, filterResult); } }
/** * Performs a binary search on the given sorted list to find the greatest lower bound for the supplied element. * @param list list to search in * @param comparator A bifunction comparator that compares elements in list of type T to value of type U * @param <T> Type of elements in the list * @return returns index of element in the list is greatest lower bound for the given value. * If value is not found, this returns -1 */ public static <T> int findGreatestLowerBound(final List<? extends T> list, Function<? super T, Integer> comparator) { Preconditions.checkArgument(!list.isEmpty(), "supplied list is empty"); return binarySearch(list, comparator, true); }
/** * Tests the joinSets() method. */ @Test public void testJoinSets() { AssertExtensions.<Integer>assertContainsSameElements("Empty set.", Collections.emptySet(), CollectionHelpers.joinSets(Collections.emptySet(), Collections.emptySet())); AssertExtensions.assertContainsSameElements("Empty+non-empty.", Sets.newHashSet(1, 2, 3), CollectionHelpers.joinSets(Collections.emptySet(), Sets.newHashSet(1, 2, 3))); AssertExtensions.assertContainsSameElements("Non-empty+empty.", Sets.newHashSet(1, 2, 3), CollectionHelpers.joinSets(Sets.newHashSet(1, 2, 3), Collections.emptySet())); AssertExtensions.assertContainsSameElements("Non-empty+non-empty.", Sets.newHashSet(1, 2, 3), CollectionHelpers.joinSets(Sets.newHashSet(1, 3), Sets.newHashSet(2))); AssertExtensions.assertContainsSameElements("Non-empty+non-empty(duplicates).", Arrays.asList(1, 2, 2, 3), CollectionHelpers.joinSets(Sets.newHashSet(1, 2), Sets.newHashSet(2, 3))); }
private CompletableFuture<Integer> searchEpochAtTime(int lowest, int highest, Predicate<Integer> ignoreCached, long timestamp) { final int middle = (lowest + highest) / 2; if (lowest > highest) { // either return epoch 0 or latest epoch return CompletableFuture.completedFuture(-1); } return getHistoryTimeSeriesChunk(middle, ignoreCached.test(middle)) .thenCompose(chunk -> { List<HistoryTimeSeriesRecord> historyRecords = chunk.getHistoryRecords(); long rangeLow = historyRecords.get(0).getScaleTime(); long rangeHigh = historyRecords.get(historyRecords.size() - 1).getScaleTime(); if (timestamp >= rangeLow && timestamp <= rangeHigh) { // found int index = CollectionHelpers.findGreatestLowerBound(historyRecords, x -> Long.compare(timestamp, x.getScaleTime())); assert index >= 0; return CompletableFuture.completedFuture(historyRecords.get(index).getEpoch()); } else if (timestamp < rangeLow) { return searchEpochAtTime(lowest, middle - 1, ignoreCached, timestamp); } else { return searchEpochAtTime(middle + 1, highest, ignoreCached, timestamp); } }); }
/** * Tests the joinCollections() method. */ @Test public void testJoinCollections() { AssertExtensions.assertContainsSameElements("Empty set.", Collections.<Integer>emptySet(), CollectionHelpers.joinCollections(Collections.<Integer>emptySet(), i -> i, Collections.<Integer>emptySet(), i -> i)); AssertExtensions.assertContainsSameElements("Empty+non-empty.", Arrays.asList(1, 2, 3), CollectionHelpers.joinCollections(Collections.<Integer>emptySet(), i -> i, Arrays.asList("1", "2", "3"), Integer::parseInt)); AssertExtensions.assertContainsSameElements("Non-empty+empty.", Arrays.asList(1, 2, 3), CollectionHelpers.joinCollections(Arrays.asList("1", "2", "3"), Integer::parseInt, Collections.<Integer>emptySet(), i -> i)); AssertExtensions.assertContainsSameElements("Non-empty+non-empty.", Arrays.asList(1, 2, 3), CollectionHelpers.joinCollections(Arrays.asList("1", "3"), Integer::parseInt, Arrays.asList("2"), Integer::parseInt)); val c = CollectionHelpers.joinCollections(Arrays.asList("1", "2"), Integer::parseInt, Arrays.asList("2", "3"), Integer::parseInt); AssertExtensions.assertContainsSameElements("Non-empty+non-empty(duplicates).", Arrays.asList(1, 2, 2, 3), c); // Now test the iterator. val copy = new ArrayList<Integer>(c); AssertExtensions.assertContainsSameElements("Non-empty+non-empty(duplicates, copy).", c, copy); }
private int getLedgerMetadataIndex(long ledgerId) { return CollectionHelpers.binarySearch(this.ledgers, lm -> Long.compare(ledgerId, lm.getLedgerId())); }
@Test public void testSearchGLB() { List<TestElement> list = Lists.newArrayList(new TestElement(10L), new TestElement(30L), new TestElement(75L), new TestElement(100L), new TestElement(152L), new TestElement(200L), new TestElement(400L), new TestElement(700L)); int index = CollectionHelpers.findGreatestLowerBound(list, x -> Long.compare(0L, x.getElement())); assertEquals(index, -1); index = CollectionHelpers.findGreatestLowerBound(list, x -> Long.compare(29, x.getElement())); assertEquals(index, 0); index = CollectionHelpers.findGreatestLowerBound(list, x -> Long.compare(100L, x.getElement())); assertEquals(index, 3); index = CollectionHelpers.findGreatestLowerBound(list, x -> Long.compare(Long.MAX_VALUE, x.getElement())); assertEquals(index, 7); }
/** * Tests the binarySearch() method on a List. */ @Test public void testBinarySearchList() { int maxSize = 100; int skip = 3; ArrayList<Integer> list = new ArrayList<>(); for (int size = 0; size < maxSize; size++) { int maxSearchElement = (list.size() + 1) * skip; for (AtomicInteger search = new AtomicInteger(-1); search.incrementAndGet() < maxSearchElement; ) { int expectedIndex = list.indexOf(search.get()); int actualIndex = CollectionHelpers.binarySearch(list, i -> Integer.compare(search.get(), i)); Assert.assertEquals("Unexpected result for search = " + search + " for list of size " + list.size(), expectedIndex, actualIndex); } // Add an element. list.add(maxSearchElement); } }
int currentIndex = CollectionHelpers.binarySearch(chunks, s -> offset < s.getStartOffset() ? -1 : (offset >= s.getLastOffset() ? 1 : 0)); assert currentIndex >= 0 : "unable to locate first SegmentChunk index.";