Adding a general doc for traits provided in folly/Traits.h
authorSumeet Ungratwar <sumeet@fb.com>
Mon, 13 Aug 2012 13:48:55 +0000 (06:48 -0700)
committerJordan DeLong <jdelong@fb.com>
Mon, 29 Oct 2012 23:30:42 +0000 (16:30 -0700)
Summary:
Understood how traits are implemented in folly/Traits.h and added
examples on how to use them.

Test Plan: no specific tests

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D546631

folly/Traits.h
folly/docs/Traits.md [new file with mode: 0644]

index 566036bb77774b8d7a8f62b3f1ed95eb34ac406d..84c7132c029d96bf88f49d3157931d52b2f5a092 100644 (file)
@@ -41,7 +41,7 @@ namespace folly {
  * }
  *
  * 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
@@ -73,7 +73,7 @@ template <class T> struct IsRelocatable : boost::mpl::not_<boost::is_class<T> >
  * 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(...) \
@@ -89,7 +89,7 @@ template <class T> struct IsRelocatable : boost::mpl::not_<boost::is_class<T> >
  * 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(...) \
diff --git a/folly/docs/Traits.md b/folly/docs/Traits.md
new file mode 100644 (file)
index 0000000..b376162
--- /dev/null
@@ -0,0 +1,175 @@
+ '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
+