diff --git a/folly/Array.h b/folly/Array.h new file mode 100644 index 0000000000000000000000000000000000000000..77faafe34d75e8c12752e5136fec2870efcd4f0a --- /dev/null +++ b/folly/Array.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <folly/Traits.h> +#include <array> +#include <type_traits> +#include <utility> + +namespace folly { + +namespace array_detail { +template <typename> +struct is_ref_wrapper : std::false_type {}; +template <typename T> +struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {}; + +template <typename T> +using not_ref_wrapper = + folly::Negation<is_ref_wrapper<typename std::decay<T>::type>>; + +template <typename D, typename...> +struct return_type_helper { + using type = D; +}; +template <typename... TList> +struct return_type_helper<void, TList...> { + static_assert( + folly::Conjunction<not_ref_wrapper<TList>...>::value, + "TList cannot contain reference_wrappers when D is void"); + using type = typename std::common_type<TList...>::type; +}; + +template <typename D, typename... TList> +using return_type = std:: + array<typename return_type_helper<D, TList...>::type, sizeof...(TList)>; +} // !array_detail + +template <typename D = void, typename... TList> +constexpr array_detail::return_type<D, TList...> make_array(TList&&... t) { + using value_type = + typename array_detail::return_type_helper<D, TList...>::type; + return {static_cast<value_type>(std::forward<TList>(t))...}; +} + +} // !folly diff --git a/folly/Makefile.am b/folly/Makefile.am index d9e8e77137c87af9859d1c2fbc8453cfc0045146..5eb27680e05cf1d0bac35758a122b3280061ab5c 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -25,6 +25,7 @@ nobase_follyinclude_HEADERS = \ ApplyTuple.h \ Arena.h \ Arena-inl.h \ + Array.h \ Assume.h \ AtomicBitSet.h \ AtomicHashArray.h \ diff --git a/folly/Traits.h b/folly/Traits.h index f34dc748e6d7998704e71d20720b1c9a84919c11..598a63a7d48b30b0910de9fb77cfec7da4737c91 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -132,6 +132,25 @@ template <class T> struct IsZeroInitializable traits_detail::has_true_IsZeroInitializable<T>::value > {}; +template <typename...> +struct Conjunction : std::true_type {}; +template <typename T> +struct Conjunction<T> : T {}; +template <typename T, typename... TList> +struct Conjunction<T, TList...> + : std::conditional<T::value, Conjunction<TList...>, T>::type {}; + +template <typename...> +struct Disjunction : std::false_type {}; +template <typename T> +struct Disjunction<T> : T {}; +template <typename T, typename... TList> +struct Disjunction<T, TList...> + : std::conditional<T::value, T, Disjunction<TList...>>::type {}; + +template <typename T> +struct Negation : std::integral_constant<bool, !T::value> {}; + } // namespace folly /** diff --git a/folly/test/ArrayTest.cpp b/folly/test/ArrayTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bfc73a8f51a55a4b237e8e413f49c72a344eb14 --- /dev/null +++ b/folly/test/ArrayTest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <folly/Array.h> +#include <gtest/gtest.h> +#include <string> + +using namespace std; +using folly::make_array; + +TEST(make_array, base_case) { + auto arr = make_array<int>(); + static_assert( + is_same<typename decltype(arr)::value_type, int>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 0); +} + +TEST(make_array, deduce_size_primitive) { + auto arr = make_array<int>(1, 2, 3, 4, 5); + static_assert( + is_same<typename decltype(arr)::value_type, int>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 5); +} + +TEST(make_array, deduce_size_class) { + auto arr = make_array<string>(string{"foo"}, string{"bar"}); + static_assert( + is_same<typename decltype(arr)::value_type, std::string>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 2); + EXPECT_EQ(arr[1], "bar"); +} + +TEST(make_array, deduce_everything) { + auto arr = make_array(string{"foo"}, string{"bar"}); + static_assert( + is_same<typename decltype(arr)::value_type, std::string>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 2); + EXPECT_EQ(arr[1], "bar"); +} + +TEST(make_array, fixed_common_type) { + auto arr = make_array<double>(1.0, 2.5f, 3, 4, 5); + static_assert( + is_same<typename decltype(arr)::value_type, double>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 5); +} + +TEST(make_array, deduced_common_type) { + auto arr = make_array(1.0, 2.5f, 3, 4, 5); + static_assert( + is_same<typename decltype(arr)::value_type, double>::value, + "Wrong array type"); + EXPECT_EQ(arr.size(), 5); +} diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index 71fe7a80a99126b1cb5c065fe938caa0e08211cf..229efaf54be8273f8a9507880b77dfe8ce1e71b3 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -37,6 +37,10 @@ spin_lock_test_SOURCES = SpinLockTest.cpp spin_lock_test_LDADD = libfollytestmain.la TESTS += spin_lock_test +array_test_SOURCES = ArrayTest.cpp +array_test_LDADD = libfollytestmain.la +TESTS += array_test + if RUN_ARCH_SPECIFIC_TESTS small_locks_test_SOURCES = SmallLocksTest.cpp small_locks_test_LDADD = libfollytestmain.la diff --git a/folly/test/TraitsTest.cpp b/folly/test/TraitsTest.cpp index 82cded6739d5883a82eb6131ec090a6c4fd3526f..453c29ed6a39db703629977a0b966b9ca474a46d 100644 --- a/folly/test/TraitsTest.cpp +++ b/folly/test/TraitsTest.cpp @@ -18,6 +18,7 @@ #include <cstring> #include <string> +#include <type_traits> #include <utility> #include <folly/ScopeGuard.h> @@ -84,6 +85,25 @@ TEST(Traits, bitAndInit) { EXPECT_FALSE(IsZeroInitializable<vector<int>>::value); } +TEST(Trait, logicOperators) { + static_assert(Conjunction<true_type>::value, ""); + static_assert(!Conjunction<false_type>::value, ""); + static_assert(is_same<Conjunction<true_type>::type, true_type>::value, ""); + static_assert(is_same<Conjunction<false_type>::type, false_type>::value, ""); + static_assert(Conjunction<true_type, true_type>::value, ""); + static_assert(!Conjunction<true_type, false_type>::value, ""); + + static_assert(Disjunction<true_type>::value, ""); + static_assert(!Disjunction<false_type>::value, ""); + static_assert(is_same<Disjunction<true_type>::type, true_type>::value, ""); + static_assert(is_same<Disjunction<false_type>::type, false_type>::value, ""); + static_assert(Disjunction<true_type, true_type>::value, ""); + static_assert(Disjunction<true_type, false_type>::value, ""); + + static_assert(!Negation<true_type>::value, ""); + static_assert(Negation<false_type>::value, ""); +} + TEST(Traits, is_negative) { EXPECT_TRUE(folly::is_negative(-1)); EXPECT_FALSE(folly::is_negative(0));