Commit 1fb83fbc authored by Mark Isaacson's avatar Mark Isaacson Committed by Facebook Github Bot 1

Add make_array to folly

Summary: This function is being proposed in WG21, the C++ standards body for inclusion in the STL via the Library Fundamentals v2 TS. Using the normal constructor for a std::array with an initializer list introduces a source of coupling between the # of elements you put in the initializer list and the size of the array you specify as a template argument. Worse still, if you put less things in the initializer list than the template argument specifies, it doesn't warn you that you've probably made a pretty devious and subtle error. With this function your array size will always be the same as the # of things you actually put in it. What's more, in some cases this can deduce the type of the elements as well.

Reviewed By: yfeldblum

Differential Revision: D3164432

fb-gh-sync-id: beceaae2ee01cd5f93dec86cf36efdb78a28b4a3
fbshipit-source-id: beceaae2ee01cd5f93dec86cf36efdb78a28b4a3
parent 35a8cc20
/*
* 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
......@@ -25,6 +25,7 @@ nobase_follyinclude_HEADERS = \
ApplyTuple.h \
Arena.h \
Arena-inl.h \
Array.h \
Assume.h \
AtomicBitSet.h \
AtomicHashArray.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
/**
......
/*
* 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);
}
......@@ -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
......
......@@ -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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment