#ifndef FOLLY_BASE_TRAITS_H_
#define FOLLY_BASE_TRAITS_H_
+#include <memory>
+#include <type_traits>
+
+#include <bits/c++config.h>
+
#include <boost/type_traits.hpp>
#include <boost/mpl/and.hpp>
+#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/not.hpp>
-#include <memory>
-#include <bits/c++config.h>
namespace folly {
* types. You may want to add your own specializations. Do so in
* namespace folly and make sure you keep the specialization of
* IsRelocatable<SomeStruct> in the same header as SomeStruct.
+ *
+ * You may also declare a type to be relocatable by including
+ * `typedef std::true_type IsRelocatable;`
+ * in the class header.
+ *
+ * It may be unset in a base class by overriding the typedef to false_type.
+ */
+/*
+ * IsTriviallyCopyable describes the value semantics property. C++11 contains
+ * the type trait is_trivially_copyable; however, it is not yet implemented
+ * in gcc (as of 4.7.1), and the user may wish to specify otherwise.
*/
-template <class T> struct IsRelocatable : boost::mpl::not_<boost::is_class<T> >
-{};
+/*
+ * IsZeroInitializable describes the property that default construction is the
+ * same as memset(dst, 0, sizeof(T)).
+ */
+
+namespace traits_detail {
+
+#define FOLLY_HAS_TRUE_XXX(name) \
+ BOOST_MPL_HAS_XXX_TRAIT_DEF(name); \
+ template <class T> struct name ## _is_true \
+ : std::is_same<typename T::name, std::true_type> {}; \
+ template <class T> struct has_true_ ## name \
+ : std::conditional< \
+ has_ ## name <T>::value, \
+ name ## _is_true<T>, \
+ std::false_type \
+ >:: type {};
+
+FOLLY_HAS_TRUE_XXX(IsRelocatable)
+FOLLY_HAS_TRUE_XXX(IsZeroInitializable)
+FOLLY_HAS_TRUE_XXX(IsTriviallyCopyable)
+
+#undef FOLLY_HAS_TRUE_XXX
+}
+
+template <class T> struct IsTriviallyCopyable
+ : std::integral_constant<bool,
+ !std::is_class<T>::value ||
+ // TODO: add alternate clause is_trivially_copyable, when available
+ traits_detail::has_true_IsTriviallyCopyable<T>::value
+ > {};
+
+template <class T> struct IsRelocatable
+ : std::integral_constant<bool,
+ !std::is_class<T>::value ||
+ // TODO add this line (and some tests for it) when we upgrade to gcc 4.7
+ //std::is_trivially_move_constructible<T>::value ||
+ IsTriviallyCopyable<T>::value ||
+ traits_detail::has_true_IsRelocatable<T>::value
+ > {};
+
+template <class T> struct IsZeroInitializable
+ : std::integral_constant<bool,
+ !std::is_class<T>::value ||
+ traits_detail::has_true_IsZeroInitializable<T>::value
+ > {};
} // namespace folly
* FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
*/
#define FOLLY_ASSUME_RELOCATABLE(...) \
- struct IsRelocatable< __VA_ARGS__ > : ::boost::true_type {};
+ struct IsRelocatable< __VA_ARGS__ > : std::true_type {};
/**
* Use this macro ONLY inside namespace boost. When using it with a
--- /dev/null
+/*
+ * Copyright 2012 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/Benchmark.h"
+#include "folly/Traits.h"
+
+#include <gflags/gflags.h>
+#include <gtest/gtest.h>
+
+using namespace folly;
+using namespace std;
+
+struct T1 {}; // old-style IsRelocatable, below
+struct T2 {}; // old-style IsRelocatable, below
+struct T3 { typedef std::true_type IsRelocatable; };
+struct T4 { typedef std::true_type IsTriviallyCopyable; };
+struct T5 : T3 {};
+
+struct F1 {};
+struct F2 { typedef int IsRelocatable; };
+struct F3 : T3 { typedef std::false_type IsRelocatable; };
+struct F4 : T1 {};
+
+namespace folly {
+ template <> struct IsRelocatable<T1> : std::true_type {};
+ template <> FOLLY_ASSUME_RELOCATABLE(T2);
+}
+
+TEST(Traits, scalars) {
+ EXPECT_TRUE(IsRelocatable<int>::value);
+ EXPECT_TRUE(IsRelocatable<bool>::value);
+ EXPECT_TRUE(IsRelocatable<double>::value);
+ EXPECT_TRUE(IsRelocatable<void*>::value);
+}
+
+TEST(Traits, containers) {
+ EXPECT_TRUE (IsRelocatable<vector<F1>>::value);
+ EXPECT_FALSE((IsRelocatable<pair<F1, F1>>::value));
+ EXPECT_TRUE ((IsRelocatable<pair<T1, T2>>::value));
+ EXPECT_TRUE (IsRelocatable<set<F1>>::value);
+}
+
+TEST(Traits, original) {
+ EXPECT_TRUE(IsRelocatable<T1>::value);
+ EXPECT_TRUE(IsRelocatable<T2>::value);
+}
+
+TEST(Traits, typedefd) {
+ EXPECT_TRUE (IsRelocatable<T3>::value);
+ EXPECT_TRUE (IsRelocatable<T5>::value);
+ EXPECT_FALSE(IsRelocatable<F2>::value);
+ EXPECT_FALSE(IsRelocatable<F3>::value);
+}
+
+TEST(Traits, unset) {
+ EXPECT_FALSE(IsRelocatable<F1>::value);
+ EXPECT_FALSE(IsRelocatable<F4>::value);
+}
+
+TEST(Traits, bitprop) {
+ EXPECT_TRUE(IsTriviallyCopyable<T4>::value);
+ EXPECT_TRUE(IsRelocatable<T4>::value);
+}
+
+TEST(Traits, bitAndInit) {
+ EXPECT_TRUE (IsTriviallyCopyable<int>::value);
+ EXPECT_FALSE(IsTriviallyCopyable<vector<int>>::value);
+ EXPECT_TRUE (IsZeroInitializable<int>::value);
+ EXPECT_FALSE(IsZeroInitializable<vector<int>>::value);
+}
+
+int main(int argc, char ** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ if (FLAGS_benchmark) {
+ folly::runBenchmarks();
+ }
+ return RUN_ALL_TESTS();
+}
+