* }
*
* void move2(T * from, T * to) {
- * memcpy(from, to, sizeof(T));
+ * memcpy(to, from, sizeof(T));
* }
*
* Most C++ types are relocatable; the ones that aren't would include
* When using it with a template type, use it like this:
*
* // Make sure you're at namespace ::folly scope
- * template<class T, class T2>
+ * template<class T1, class T2>
* FOLLY_ASSUME_RELOCATABLE(MyType<T1, T2>)
*/
#define FOLLY_ASSUME_RELOCATABLE(...) \
* When using it with a template type, use it like this:
*
* // Make sure you're at namespace ::boost scope
- * template<class T, class T2>
+ * template<class T1, class T2>
* FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType<T1, T2>)
*/
#define FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(...) \
--- /dev/null
+ 'folly/Traits.h'
+ -----------------
+
+ Implements traits complementary to those provided in <boost/type_traits.h>
+
+ * Implements `IsRelocatable` trait.
+ * Implements `IsOneOf` trait
+ * Macros to state the assumptions easily
+
+ ### Motivation
+ ***
+
+ <boost/type_traits.hpp> is the Boost type-traits library defining a
+ variety of traits such as `is_integral` or `is_floating_point`. This helps
+ to gain more information about a given type.
+ Many traits introduced by Boost have been standardized in C++11.
+
+ folly/Traits.h implements traits complementing those present in boost.
+
+
+ ### IsRelocatable
+ ***
+
+ In C++, the default way to move an object is by
+ calling the copy constructor and destroying the old copy
+ instead of directly copying the memory contents by using memcpy().
+ The conservative approach of moving an object assumes that the copied
+ object is not relocatable.
+ The two following code sequences should be semantically equivalent for a
+ relocatable type:
+
+ ```Cpp
+ {
+ void conservativeMove(T * from, T * to) {
+ new(to) T(from);
+ (*from).~T();
+ }
+ }
+
+ {
+ void optimizedMove(T * from, T * to) {
+ memcpy(to, from, sizeof(T));
+ }
+ }
+ ```
+
+ Very few C++ types are non-relocatable.
+ The type defined below maintains a pointer inside an embedded buffer and
+ hence would be non-relocatable. Moving the object by simply copying its
+ memory contents would leave the internal pointer pointing to the old buffer.
+
+ ```Cpp
+ class NonRelocatableType {
+ private:
+ char buffer[1024];
+ char * pointerToBuffer;
+ ...
+ public:
+ NonRelocatableType() : pointerToBuffer(buffer) {}
+ ...
+ };
+ ```
+
+ We can optimize the task of moving a relocatable type T using memcpy.
+ IsRelocatable<T>::value describes the ability of moving around memory
+ a value of type T by using memcpy.
+
+ ### Usage
+ ***
+
+ * Declaring types
+ ```Cpp
+ template <class T1, class T2>
+ class MyParameterizedType;
+
+ class MySimpleType;
+ ```
+
+ * Declaring a type as relocatable
+
+ Appending the lines below after definition of My*Type
+ (`MyParameterizedType` or `MySimpleType`) will declare it as relocatable
+
+ ```Cpp
+ /* Definition of My*Type goes here */
+ // global namespace (not inside any namespace)
+ namespace folly {
+ // defining specialization of IsRelocatable for MySimpleType
+ template <>
+ struct IsRelocatable<MySimpleType> : boost::true_type {};
+ // defining specialization of IsRelocatable for MyParameterizedType
+ template <class T1, class T2>
+ struct IsRelocatable<MyParameterizedType<T1, T2>>
+ : ::boost::true_type {};
+ }
+ ```
+
+ * To make it easy to state assumptions for a regular type or a family of
+ parameterized type, various macros can be used as shown below.
+
+ * Stating that a type is Relocatable using a macro
+
+ ```Cpp
+ // global namespace
+ namespace folly {
+ // For a Regular Type
+ FOLLY_ASSUME_RELOCATABLE(MySimpleType);
+ // For a Parameterized Type
+ FOLLY_ASSUME_RELOCATABLE(MyParameterizedType<T1, T2>);
+ }
+ ```
+
+ * Stating that a type has no throw constructor using a macro
+
+ ```Cpp
+ namespace boost {
+ // For a Regular Type
+ FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MySimpleType);
+ // For a Parameterized Type
+ FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyParameterizedType<T1, T2>);
+ }
+ ```
+
+ `fbvector` only works with relocatable objects. If assumptions are not stated
+ explicitly, `fbvector<MySimpleType>` or `fbvector<MyParameterizedType>`
+ will fail to compile due to assertion below:
+
+ ```Cpp
+ BOOST_STATIC_ASSERT(
+ IsRelocatable<My*Type>::value
+ );
+ ```
+
+ FOLLY_ASSUME_FBVECTOR_COMPATIBLE*(type) macros can be used to state that type
+ is relocatable and has nothrow constructor.
+
+ * Stating that a type is `fbvector-compatible` using macros
+ i.e. relocatable and has nothrow default constructor
+
+ ```Cpp
+ // at global level, i.e no namespace
+ // macro for regular type
+ FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MySimpleType);
+ // macro for types having 2 template parameters (MyParameterizedType)
+ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyParameterizedType);
+ ```
+
+ Similary,
+ * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(MyTypeHavingOneParameter) macro is
+ for family of parameterized types having 1 parameter
+ * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(MyTypeHavingThreeParameters) macro is
+ for family of parameterized types having 3 parameters
+ * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(MyTypeHavingFourParameters) macro is
+ for family of parameterized types having 4 parameters
+
+ * Few common types, namely `std::basic_string`, `std::vector`, `std::list`,
+ `std::map`, `std::deque`, `std::set`, `std::unique_ptr`, `std::shared_ptr`,
+ `std::function`, `boost::shared_ptr` which are compatible with `fbvector`
+ are already instantiated and declared compatible with `fbvector`.
+ `fbvector` can be directly used with any of these C++ types.
+
+ * `std::pair` can be safely assumed to be compatible with `fbvector` if both
+ of its components are.
+
+ ### IsOneOf
+ ***
+
+ boost::is_same<T1, T2>::value can be used to test if types of T1 and T2 are
+ same. folly::IsOneOf<T, T1, Ts...>::value can be used to test if type of T1
+ matches the type of one of the other template parameter, T1, T2, ...Tn.
+ Recursion is used to implement this type trait.
+
+ if boost::is_integral<T>::value == 1 and boost::is_integral<T2>::value == 1
+ then folly::IsOneOf<T, T1, T2, T3>::value will return 1
+