Index: llvm/trunk/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/trunk/include/llvm/ADT/STLExtras.h +++ llvm/trunk/include/llvm/ADT/STLExtras.h @@ -1304,6 +1304,47 @@ return std::upper_bound(adl_begin(Range), adl_end(Range), std::forward(Value), C); } + +/// Binary search for the first index where a predicate is true. +/// Returns the first I in [Lo, Hi) where C(I) is true, or Hi if it never is. +/// Requires that C is always false below some limit, and always true above it. +/// +/// Example: +/// size_t DawnModernEra = bsearch(1776, 2050, [](size_t Year){ +/// return Presidents.for(Year).twitterHandle() != None; +/// }); +/// +/// Note the return value differs from std::binary_search! +template +size_t bsearch(size_t Lo, size_t Hi, Predicate P) { + while (Lo != Hi) { + assert(Hi > Lo); + size_t Mid = Lo + (Hi - Lo) / 2; + if (P(Mid)) + Hi = Mid; + else + Lo = Mid + 1; + } + return Hi; +} + +/// Binary search for the first iterator where a predicate is true. +/// Returns the first I in [Lo, Hi) where C(*I) is true, or Hi if it never is. +/// Requires that C is always false below some limit, and always true above it. +template ())> +It bsearch(It Lo, It Hi, Predicate P) { + return std::lower_bound(Lo, Hi, 0u, + [&](const Val &V, unsigned) { return !P(V); }); +} + +/// Binary search for the first iterator in a range where a predicate is true. +/// Requires that C is always false below some limit, and always true above it. +template +auto bsearch(R &&Range, Predicate P) -> decltype(adl_begin(Range)) { + return bsearch(adl_begin(Range), adl_end(Range), P); +} + /// Wrapper function around std::equal to detect if all elements /// in a container are same. template Index: llvm/trunk/unittests/ADT/STLExtrasTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/STLExtrasTest.cpp +++ llvm/trunk/unittests/ADT/STLExtrasTest.cpp @@ -469,4 +469,25 @@ EXPECT_EQ(V1, to_address(V3)); } +TEST(STLExtrasTest, bsearch) { + // Integer version. + EXPECT_EQ(7u, bsearch(5, 10, [](unsigned X) { return X >= 7; })); + EXPECT_EQ(5u, bsearch(5, 10, [](unsigned X) { return X >= 0; })); + EXPECT_EQ(10u, bsearch(5, 10, [](unsigned X) { return X >= 50; })); + + // Iterator version. + std::vector V = {1, 3, 5, 7, 9}; + EXPECT_EQ(V.begin() + 3, + bsearch(V.begin(), V.end(), [](unsigned X) { return X >= 7; })); + EXPECT_EQ(V.begin(), + bsearch(V.begin(), V.end(), [](unsigned X) { return X >= 0; })); + EXPECT_EQ(V.end(), + bsearch(V.begin(), V.end(), [](unsigned X) { return X >= 50; })); + + // Range version. + EXPECT_EQ(V.begin() + 3, bsearch(V, [](unsigned X) { return X >= 7; })); + EXPECT_EQ(V.begin(), bsearch(V, [](unsigned X) { return X >= 0; })); + EXPECT_EQ(V.end(), bsearch(V, [](unsigned X) { return X >= 50; })); +} + } // namespace