Adding a general doc for traits provided in folly/Traits.h
[folly.git] / folly / docs / Traits.md
1  'folly/Traits.h'
2  -----------------
3
4  Implements traits complementary to those provided in <boost/type_traits.h>
5
6   * Implements `IsRelocatable` trait.
7   * Implements `IsOneOf` trait
8   * Macros to state the assumptions easily
9
10   ### Motivation
11   ***
12
13   <boost/type_traits.hpp> is the Boost type-traits library defining a 
14   variety of traits such as `is_integral` or `is_floating_point`. This helps 
15   to gain more information about a given type.
16   Many traits introduced by Boost have been standardized in C++11.
17
18   folly/Traits.h implements traits complementing those present in boost. 
19
20  
21  ### IsRelocatable
22  ***
23
24   In C++, the default way to move an object is by 
25   calling the copy constructor and destroying the old copy 
26   instead of directly copying the memory contents by using memcpy(). 
27   The conservative approach of moving an object assumes that the copied 
28   object is not relocatable. 
29   The two following code sequences should be semantically equivalent for a
30   relocatable type:
31
32    ```Cpp
33    {
34      void conservativeMove(T * from, T * to) {
35        new(to) T(from);
36        (*from).~T();
37      }
38    }
39
40    {
41      void optimizedMove(T * from, T * to) {
42        memcpy(to, from, sizeof(T));
43      }
44    }
45    ```
46
47  Very few C++ types are non-relocatable.
48  The type defined below maintains a pointer inside an embedded buffer and 
49  hence would be non-relocatable. Moving the object by simply copying its 
50  memory contents would leave the internal pointer pointing to the old buffer.
51
52   ```Cpp
53   class NonRelocatableType {
54   private:
55     char buffer[1024];
56     char * pointerToBuffer;
57     ...
58   public:
59     NonRelocatableType() : pointerToBuffer(buffer) {}
60     ...
61   };
62   ```
63
64   We can optimize the task of moving a relocatable type T using memcpy. 
65   IsRelocatable<T>::value describes the ability of moving around memory 
66   a value of type T by using memcpy.
67
68  ### Usage
69  ***
70
71  * Declaring types
72   ```Cpp
73   template <class T1, class T2>
74   class MyParameterizedType;
75
76   class MySimpleType;
77   ```
78
79  * Declaring a type as relocatable
80
81  Appending the lines below after definition of My*Type 
82  (`MyParameterizedType` or `MySimpleType`) will declare it as relocatable
83
84   ```Cpp
85   /* Definition of My*Type goes here */
86   // global namespace (not inside any namespace)
87   namespace folly {
88     // defining specialization of IsRelocatable for MySimpleType
89     template <>
90     struct IsRelocatable<MySimpleType> : boost::true_type {};
91     // defining specialization of IsRelocatable for MyParameterizedType
92     template <class T1, class T2>
93     struct IsRelocatable<MyParameterizedType<T1, T2>>
94         : ::boost::true_type {};
95   }
96   ```
97
98   * To make it easy to state assumptions for a regular type or a family of 
99   parameterized type, various macros can be used as shown below.
100
101  * Stating that a type is Relocatable using a macro
102
103   ```Cpp
104   // global namespace
105   namespace folly {
106     // For a Regular Type
107     FOLLY_ASSUME_RELOCATABLE(MySimpleType);
108     // For a Parameterized Type
109     FOLLY_ASSUME_RELOCATABLE(MyParameterizedType<T1, T2>);
110   }
111   ```
112
113  * Stating that a type has no throw constructor using a macro
114
115   ```Cpp
116   namespace boost {
117     // For a Regular Type
118     FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MySimpleType);
119     // For a Parameterized Type
120     FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyParameterizedType<T1, T2>);
121   }
122   ```
123
124  `fbvector` only works with relocatable objects. If assumptions are not stated 
125  explicitly, `fbvector<MySimpleType>` or `fbvector<MyParameterizedType>` 
126  will fail to compile due to assertion below:
127
128   ```Cpp
129   BOOST_STATIC_ASSERT(
130     IsRelocatable<My*Type>::value
131   );
132   ```
133
134  FOLLY_ASSUME_FBVECTOR_COMPATIBLE*(type) macros can be used to state that type 
135  is relocatable and has nothrow constructor.
136
137  * Stating that a type is `fbvector-compatible` using macros
138   i.e. relocatable and has nothrow default constructor
139   
140   ```Cpp
141   // at global level, i.e no namespace
142   // macro for regular type
143   FOLLY_ASSUME_FBVECTOR_COMPATIBLE(MySimpleType);
144   // macro for types having 2 template parameters (MyParameterizedType)
145   FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(MyParameterizedType);
146   ```
147
148  Similary, 
149  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(MyTypeHavingOneParameter) macro is 
150  for family of parameterized types having 1 parameter
151  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(MyTypeHavingThreeParameters) macro is 
152  for family of parameterized types having 3 parameters
153  * FOLLY_ASSUME_FBVECTOR_COMPATIBLE_4(MyTypeHavingFourParameters) macro is 
154  for family of parameterized types having 4 parameters
155
156  * Few common types, namely `std::basic_string`, `std::vector`, `std::list`, 
157  `std::map`, `std::deque`, `std::set`, `std::unique_ptr`, `std::shared_ptr`, 
158  `std::function`, `boost::shared_ptr` which are compatible with `fbvector` 
159  are already instantiated and declared compatible with `fbvector`. 
160  `fbvector` can be directly used with any of these C++ types.
161
162  * `std::pair` can be safely assumed to be compatible with `fbvector` if both 
163  of its components are.
164
165  ### IsOneOf
166  ***
167
168  boost::is_same<T1, T2>::value can be used to test if types of T1 and T2 are 
169  same. folly::IsOneOf<T, T1, Ts...>::value can be used to test if type of T1 
170  matches the type of one of the other template parameter, T1, T2, ...Tn.
171  Recursion is used to implement this type trait.
172
173   if boost::is_integral<T>::value == 1 and boost::is_integral<T2>::value == 1
174   then folly::IsOneOf<T, T1, T2, T3>::value will return 1
175