diff --git a/llvm/include/llvm/ADT/IterableTraits.h b/llvm/include/llvm/ADT/IterableTraits.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ADT/IterableTraits.h @@ -0,0 +1,51 @@ +//===- IterableTraits.h - A trait to identify iterables ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ITERABLETRAITS_H +#define LLVM_ADT_ITERABLETRAITS_H + +#include + +namespace llvm { +namespace detail { + +template auto is_range_iterable(...) -> std::false_type; +template ().begin())>::type> +auto is_range_iterable(int) -> decltype( + std::declval().begin(), std::declval().end(), ++std::declval(), + void(), + std::integral_constant< + bool, std::is_convertible() != + std::declval()), + bool>::value && + !std::is_void())>::value && + std::is_copy_constructible::value>{}); + +using std::begin; +using std::end; +template ()))>::type> +auto is_range_iterable(char) -> decltype( + begin(std::declval()), end(std::declval()), ++std::declval(), + void(), + std::integral_constant< + bool, std::is_convertible() != + std::declval()), + bool>::value && + !std::is_void())>::value && + std::is_copy_constructible::value>{}); +} // namespace detail + +// A convenient trait to check whether a type provides the begin / end semantic. +template +struct is_range_iterable : decltype(detail::is_range_iterable(0)) {}; + +} // namespace llvm + +#endif // LLVM_ADT_ITERABLETRAITS_H diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h --- a/llvm/include/llvm/ADT/SmallVector.h +++ b/llvm/include/llvm/ADT/SmallVector.h @@ -13,6 +13,7 @@ #ifndef LLVM_ADT_SMALLVECTOR_H #define LLVM_ADT_SMALLVECTOR_H +#include "llvm/ADT/IterableTraits.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -1188,10 +1189,11 @@ this->append(S, E); } - template - explicit SmallVector(const iterator_range &R) - : SmallVectorImpl(N) { - this->append(R.begin(), R.end()); + template < + typename Iterable, + std::enable_if_t::value, bool> = true> + explicit SmallVector(const Iterable &R) : SmallVectorImpl(N) { + this->append(std::begin(R), std::end(R)); } SmallVector(std::initializer_list IL) : SmallVectorImpl(N) { diff --git a/llvm/tools/llvm-xray/xray-converter.cpp b/llvm/tools/llvm-xray/xray-converter.cpp --- a/llvm/tools/llvm-xray/xray-converter.cpp +++ b/llvm/tools/llvm-xray/xray-converter.cpp @@ -158,6 +158,8 @@ // A structure that allows building a dictionary of stack ids for the Chrome // trace event format. struct StackIdData { + StackIdData(const StackIdData &) = default; + // Each Stack of function calls has a unique ID. unsigned id; diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -41,6 +41,7 @@ IntEqClassesTest.cpp IntervalMapTest.cpp IntrusiveRefCntPtrTest.cpp + IterableTraitsTest.cpp IteratorTest.cpp MappedIteratorTest.cpp MapVectorTest.cpp diff --git a/llvm/unittests/ADT/IterableTraitsTest.cpp b/llvm/unittests/ADT/IterableTraitsTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/ADT/IterableTraitsTest.cpp @@ -0,0 +1,39 @@ +//===- IterableTraitsTest.cpp - Unit tests for is_range_iterable ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IterableTraits.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "gtest/gtest.h" +#include +#include + +TEST(IteratorRangeTest, IsIterableCArray) { + EXPECT_TRUE(llvm::is_range_iterable::value); +} + +TEST(IteratorRangeTest, IsIterableVector) { + using Vector = std::vector; + EXPECT_TRUE(llvm::is_range_iterable::value); +} + +TEST(IteratorRangeTest, IsIterableArray) { + using Array = std::array; + EXPECT_TRUE(llvm::is_range_iterable::value); +} + +TEST(IteratorRangeTest, IsIterableSmallVector) { + using SVector = llvm::SmallVector; + EXPECT_TRUE(llvm::is_range_iterable::value); +} + +class Target {}; +TEST(IteratorRangeTest, IsIterableRange) { + using Range = llvm::iterator_range; + EXPECT_TRUE(llvm::is_range_iterable::value); +}