From 0041888aea503b0a3c08ecf5ca59ea10f6244c5b Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Wed, 17 Aug 2016 22:06:59 +0000 Subject: [PATCH] Fix reverse to work on const rbegin()/rend(). Duncan found that reverse worked on mutable rbegin(), but the has_rbegin trait didn't work with a const method. See http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160815/382890.html for more details. Turns out this was already solved in clang with has_getDecl. Copied that and made it work for rbegin. This includes the tests Duncan attached to that thread, including the traits test. llvm-svn: 278991 --- llvm/include/llvm/ADT/STLExtras.h | 17 +++++++++++++---- llvm/unittests/ADT/RangeAdapterTest.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 00b796f..8e4d186 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -209,10 +209,19 @@ inline mapped_iterator map_iterator(const ItTy &I, FuncTy F) { } /// \brief Metafunction to determine if type T has a member called rbegin(). -template struct has_rbegin { - template static char(&f(const U &, decltype(&U::rbegin)))[1]; - static char(&f(...))[2]; - const static bool value = sizeof(f(std::declval(), nullptr)) == 1; +template +class has_rbegin { + typedef char yes[1]; + typedef char no[2]; + + template + static yes& test(Inner *I, decltype(I->rbegin()) * = nullptr); + + template + static no& test(...); + +public: + static const bool value = sizeof(test(nullptr)) == sizeof(yes); }; // Returns an iterator_range over the given container which iterates in reverse. diff --git a/llvm/unittests/ADT/RangeAdapterTest.cpp b/llvm/unittests/ADT/RangeAdapterTest.cpp index 634f5bb..a4e922e 100644 --- a/llvm/unittests/ADT/RangeAdapterTest.cpp +++ b/llvm/unittests/ADT/RangeAdapterTest.cpp @@ -27,8 +27,11 @@ public: ReverseOnlyVector(std::initializer_list list) : Vec(list) {} typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; reverse_iterator rbegin() { return Vec.rbegin(); } reverse_iterator rend() { return Vec.rend(); } + const_reverse_iterator rbegin() const { return Vec.rbegin(); } + const_reverse_iterator rend() const { return Vec.rend(); } }; // A wrapper around vector which exposes begin(), end(), rbegin() and rend(). @@ -49,6 +52,29 @@ public: reverse_iterator rend() { return Vec.rend(); } }; +/// This is the same as BidirectionalVector but with the addition of const +/// begin/rbegin methods to ensure that the type traits for has_rbegin works. +class BidirectionalVectorConsts { + std::vector Vec; + +public: + BidirectionalVectorConsts(std::initializer_list list) : Vec(list) {} + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + + typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; + reverse_iterator rbegin() { return Vec.rbegin(); } + reverse_iterator rend() { return Vec.rend(); } + const_reverse_iterator rbegin() const { return Vec.rbegin(); } + const_reverse_iterator rend() const { return Vec.rend(); } +}; + template void TestRev(const R &r) { int counter = 3; for (int i : r) @@ -80,4 +106,8 @@ TYPED_TEST(RangeAdapterRValueTest, TrivialOperation) { TestRev(reverse(TypeParam({0, 1, 2, 3}))); } +TYPED_TEST(RangeAdapterRValueTest, HasRbegin) { + EXPECT_TRUE(has_rbegin::value); +} + } // anonymous namespace -- 2.7.4