diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1543,6 +1543,13 @@ return std::copy(adl_begin(Range), adl_end(Range), Out); } +/// Provide wrappers to std::move which take ranges instead of having to +/// pass begin/end explicitly. +template +OutputIt move(R &&Range, OutputIt Out) { + return std::move(adl_begin(Range), adl_end(Range), Out); +} + /// Wrapper function around std::find to detect if an element exists /// in a container. template diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" #include "gtest/gtest.h" #include @@ -568,4 +569,41 @@ EXPECT_FALSE( hasNItemsOrLess(V3.begin(), V3.end(), 2, [](int x) { return x < 10; })); } + +TEST(STLExtras, MoveRange) { + class Foo { + bool A; + + public: + Foo() : A(true) {} + Foo(const Foo &) = delete; + Foo(Foo &&Other) : A(Other.A) { Other.A = false; } + Foo &operator=(const Foo &) = delete; + Foo &operator=(Foo &&Other) { + if (this != &Other) { + A = Other.A; + Other.A = false; + } + return *this; + } + operator bool() const { return A; } + }; + + constexpr size_t ItemCount = 4; + SmallVector In, Out; + auto HasVal = [](const Foo &Item) { return static_cast(Item); }; + + In.resize(ItemCount); + EXPECT_TRUE(llvm::all_of(In, HasVal)); + + llvm::move(In, std::back_inserter(Out)); + + // Ensure input container is same size, but its contents were moved out. + EXPECT_EQ(In.size(), ItemCount); + EXPECT_TRUE(llvm::none_of(In, HasVal)); + + // Ensure output container has the contents of the input container. + EXPECT_EQ(Out.size(), ItemCount); + EXPECT_TRUE(llvm::all_of(Out, HasVal)); +} } // namespace