From fee1963538a3148f3f31dd91dc9a2cc4ffb40a2d Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sun, 9 Mar 2014 11:20:17 +0000 Subject: [PATCH] [C++11] Add llvm::make_unique, according to N3656. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203387 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/STLExtras.h | 169 +++++++++++++++++++++++++++++++ unittests/ADT/CMakeLists.txt | 1 + unittests/ADT/MakeUniqueTest.cpp | 76 ++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 unittests/ADT/MakeUniqueTest.cpp diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index c1a619838b9..5a3756de3dd 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -17,10 +17,12 @@ #ifndef LLVM_ADT_STLEXTRAS_H #define LLVM_ADT_STLEXTRAS_H +#include "llvm/Support/Compiler.h" #include // for std::size_t #include // for qsort #include #include +#include #include // for std::pair namespace llvm { @@ -255,6 +257,173 @@ void DeleteContainerSeconds(Container &C) { C.clear(); } +//===----------------------------------------------------------------------===// +// Extra additions to +//===----------------------------------------------------------------------===// + +#if LLVM_HAS_VARIADIC_TEMPLATES + +/// Implement make_unique according to N3656. +/// +/// template unique_ptr make_unique(Args&&... args); +/// Remarks: This function shall not participate in overload resolution unless +/// T is not an array. +/// Returns: unique_ptr(new T(std::forward(args)...)). +/// +/// template unique_ptr make_unique(size_t n); +/// Remarks: This function shall not participate in overload resolution unless +/// T is an array of unknown bound. +/// Returns: unique_ptr(new typename remove_extent::type[n]()). +/// +/// template unspecified make_unique(Args&&...) = delete; +/// Remarks: This function shall not participate in overload resolution unless +/// T is an array of known bound. +/// +/// Use scenarios: +/// +/// Single object case: +/// +/// auto p0 = make_unique(); +/// +/// auto p2 = make_unique>(0, 1); +/// +/// Array case: +/// +/// auto p1 = make_unique(2); // value-initializes the array with 0's. +/// +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Args &&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +typename std::enable_if::value && std::extent::value == 0, + std::unique_ptr>::type +make_unique(size_t n) { + return std::unique_ptr(new typename std::remove_extent::type[n]()); +} + +template +typename std::enable_if::value != 0>::type +make_unique(Args &&...) LLVM_DELETED_FUNCTION; + +#else + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique() { + return std::unique_ptr(new T()); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1) { + return std::unique_ptr(new T(std::forward(arg1))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3) { + return std::unique_ptr(new T(std::forward(arg1), + std::forward(arg2), + std::forward(arg3))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5, + Arg6 &&arg6) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5), std::forward(arg6))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5, + Arg6 &&arg6, Arg7 &&arg7) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5), std::forward(arg6), + std::forward(arg7))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5, + Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5), std::forward(arg6), + std::forward(arg7), std::forward(arg8))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5, + Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5), std::forward(arg6), + std::forward(arg7), std::forward(arg8), + std::forward(arg9))); +} + +template +typename std::enable_if::value, std::unique_ptr>::type +make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5, + Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9, Arg10 &&arg10) { + return std::unique_ptr( + new T(std::forward(arg1), std::forward(arg2), + std::forward(arg3), std::forward(arg4), + std::forward(arg5), std::forward(arg6), + std::forward(arg7), std::forward(arg8), + std::forward(arg9), std::forward(arg10))); +} + +template +typename std::enable_if::value &&std::extent::value == 0, + std::unique_ptr>::type +make_unique(size_t n) { + return std::unique_ptr(new typename std::remove_extent::type[n]()); +} + +#endif + } // End llvm namespace #endif diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt index 66e2d20ef73..dab70b903d9 100644 --- a/unittests/ADT/CMakeLists.txt +++ b/unittests/ADT/CMakeLists.txt @@ -20,6 +20,7 @@ set(ADTSources IntEqClassesTest.cpp IntervalMapTest.cpp IntrusiveRefCntPtrTest.cpp + MakeUniqueTest.cpp MapVectorTest.cpp OptionalTest.cpp OwningPtrTest.cpp diff --git a/unittests/ADT/MakeUniqueTest.cpp b/unittests/ADT/MakeUniqueTest.cpp new file mode 100644 index 00000000000..3b4938a2ef3 --- /dev/null +++ b/unittests/ADT/MakeUniqueTest.cpp @@ -0,0 +1,76 @@ +//===- llvm/unittest/ADT/MakeUniqueTest.cpp - make_unique unit tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "gtest/gtest.h" +#include +using namespace llvm; + +namespace { + +TEST(MakeUniqueTest, SingleObject) { + auto p0 = make_unique(); + EXPECT_TRUE((bool)p0); + EXPECT_EQ(0, *p0); + + auto p1 = make_unique(5); + EXPECT_TRUE((bool)p1); + EXPECT_EQ(5, *p1); + + auto p2 = make_unique>(0, 1); + EXPECT_TRUE((bool)p2); + EXPECT_EQ(std::make_tuple(0, 1), *p2); + + auto p3 = make_unique>(0, 1, 2); + EXPECT_TRUE((bool)p3); + EXPECT_EQ(std::make_tuple(0, 1, 2), *p3); + + auto p4 = make_unique>(0, 1, 2, 3); + EXPECT_TRUE((bool)p4); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3), *p4); + + auto p5 = make_unique>(0, 1, 2, 3, 4); + EXPECT_TRUE((bool)p5); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4), *p5); + + auto p6 = + make_unique>(0, 1, 2, 3, 4, 5); + EXPECT_TRUE((bool)p6); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4, 5), *p6); + + auto p7 = make_unique>( + 0, 1, 2, 3, 4, 5, 6); + EXPECT_TRUE((bool)p7); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4, 5, 6), *p7); + + auto p8 = make_unique>( + 0, 1, 2, 3, 4, 5, 6, 7); + EXPECT_TRUE((bool)p8); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4, 5, 6, 7), *p8); + + auto p9 = + make_unique>( + 0, 1, 2, 3, 4, 5, 6, 7, 8); + EXPECT_TRUE((bool)p9); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4, 5, 6, 7, 8), *p9); + + auto p10 = + make_unique>( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + EXPECT_TRUE((bool)p10); + EXPECT_EQ(std::make_tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), *p10); +} + +TEST(MakeUniqueTest, Array) { + auto p1 = make_unique(2); + EXPECT_TRUE((bool)p1); + EXPECT_EQ(0, p1[0]); + EXPECT_EQ(0, p1[1]); +} +}