d4401fe5a01f77d96cfa032766f62fb519c323b4
[platform/core/uifw/dali-adaptor.git] / dali / dali-bridge / src / Optional.hpp
1 /*
2  * Copyright 2017  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *  http://www.apache.org/licenses/LICENSE-2.0
9
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef OPTIONAL_HPP
18 #define OPTIONAL_HPP
19
20 /**
21  * Minimalistic implementation of standard library std::optional (c++17) for c++11 compiler.
22  *
23  * After project conversion to C++17 standard, this template class will be deleted and
24  * Optional will point to std::optional.
25  *
26  * Allowed operations (note, to make code simplier, than original, value class must have accessible copy and move constructor):
27  *  - constructing empty (valueless) object
28  *  - copying Optional (with and without value)
29  *  - moving Optional (with and without value)
30  *  - querying, if Optional has value (via explicit operator bool), for example:
31  *        Optional<int> v = ...;
32  *        if (v) ... // if v has value, then do something
33  *  - accessing value (via operator *), for example:
34  *        Optional<int> v = ...;
35  *        auto z = *v; // z now has the same int, as v (copied)
36  *        auto &y = *v; // y now has REFERENCE to int inside v, so modifying y modifies v
37  */
38
39 #include <cassert>
40 #include <new>
41 #include <type_traits>
42 #include <utility>
43
44 template < typename A >
45 class Optional
46 {
47   /// \cond
48   union
49   {
50     A place;
51   };
52   bool hasValue = false;
53   /// \endcond
54 public:
55   /**
56    * @brief Empty constructor.
57    * Creates empty Optional object, which will be false in boolean context.
58    * So:
59    *   \code{.cpp}
60    *   Optional<int> o;
61    *   if (o) printf("1\n");
62    *   \endcode
63    * won't print 1.
64    */
65   Optional() {}
66
67   /**
68    * @brief Single element constructor, when implicit convertion can be applied.
69    *
70    * This constructor will be selected, when type of given argument (U) is
71    * implicitly convertable to expected type A. In other words following
72    * code must be valid:
73    *   \code{.cpp}
74    *   A foo() {
75    *     return U();
76    *   }
77    *   \endcode
78    *
79    * @param a value held by Optional object will be initialized from a.
80    */
81   template < typename U = A, typename std::enable_if<
82                                  std::is_convertible< U&&, A >::value &&
83                                      std::is_constructible< A, U&& >::value &&
84                                      !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
85                                  int* >::type = nullptr >
86   constexpr Optional( U&& a )
87       : place( std::forward< U >( a ) ), hasValue( true )
88   {
89   }
90
91   /**
92    * @brief Single element constructor, when only explicit convertion can be applied.
93    *
94    * This constructor will be selected, when type of given argument (U) is
95    * convertable to expected type A.
96    *
97    * @param a value held by Optional object will be initialized from a.
98    */
99   template < typename U = A, typename std::enable_if<
100                                  !std::is_convertible< U&&, A >::value &&
101                                      std::is_constructible< A, U&& >::value &&
102                                      !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
103                                  int* >::type = nullptr >
104   explicit constexpr Optional( U&& a )
105       : place( std::forward< U >( a ) ), hasValue( true )
106   {
107   }
108
109   /**
110    * @brief Copy constructor.
111    *
112    * @param v Optional value to copy from. Will cause to copy data held by object v,
113    * if v has data.
114    */
115   Optional( const Optional& v ) : hasValue( v.hasValue )
116   {
117     if( hasValue )
118       new( &place ) A( v.place );
119   }
120
121   /**
122    * @brief Move constructor.
123    *
124    * @param v Optional value to copy from. Will move data help by v, if any.
125    * After construction \code{.cpp} bool(v) \endcode will be false.
126    */
127   Optional( Optional&& v ) : hasValue( v.hasValue )
128   {
129     if( hasValue )
130       new( &place ) A( std::move( v.place ) );
131   }
132
133   /**
134    * @brief Destructor.
135    */
136   ~Optional()
137   {
138     if( hasValue )
139     {
140       place.~A();
141     }
142   }
143
144   /**
145    * @brief Explicit bool operator
146    *
147    * Will return true if and only if object is helding data.
148    */
149   explicit operator bool() const
150   {
151     return hasValue;
152   }
153
154   /**
155    * @brief Accessor (*) operator
156    *
157    * Will return modifiable reference to held object. Will assert, if not object is held.
158    */
159   A& operator*()
160   {
161     assert( hasValue );
162     return place;
163   }
164
165   /**
166    * @brief Accessor (*) const operator
167    *
168    * Will return const reference to held object. Will assert, if not object is held.
169    */
170   const A& operator*() const
171   {
172     assert( hasValue );
173     return place;
174   }
175
176   /**
177    * @brief Accessor (->) operator
178    *
179    * Will return pointer to held object allowing access to the value's members.
180    * Will assert, if not object is held.
181    */
182   A* operator->()
183   {
184     assert( hasValue );
185     return &place;
186   }
187
188   /**
189    * @brief Accessor (->) operator
190    *
191    * Will return pointer to (const) held object allowing access to the value's members.
192    * Will assert, if not object is held.
193    */
194   const A* operator->() const
195   {
196     assert( hasValue );
197     return &place;
198   }
199
200   /**
201    * @brief Assignment operator
202    *
203    * Will copy held value from v, if any.
204    *
205    * @param v Value to copy from
206    */
207   Optional& operator=( const Optional& v )
208   {
209     if( this != &v )
210     {
211       if( hasValue != v.hasValue )
212       {
213         if( v.hasValue )
214           new( &place ) A( v.place );
215         else
216           place.~A();
217         hasValue = v.hasValue;
218       }
219       else if( hasValue )
220       {
221         place = v.place;
222       }
223     }
224     return *this;
225   }
226
227   /**
228    * @brief Assignment move operator
229    *
230    * Will move held value from v, if any. In all cases v won't held a value
231    * after assignment is done.
232    *
233    * @param v Value to copy from
234    */
235   Optional& operator=( Optional&& v )
236   {
237     if( this != &v )
238     {
239       if( hasValue != v.hasValue )
240       {
241         if( v.hasValue )
242           new( &place ) A( std::move( v.place ) );
243         else
244           place.~A();
245         hasValue = v.hasValue;
246       }
247       else if( hasValue )
248       {
249         place = std::move( v.place );
250       }
251     }
252     return *this;
253   }
254
255   /**
256    * @brief Assignment operator from value of type held.
257    *
258    * Will initialize held value from given parameter a.
259    * Type of the parameter must be the same (barring cv convertions),
260    * as the type of the value held.
261    *
262    * @param a Value to copy from
263    */
264   template < class U, class = typename std::enable_if<
265                           std::is_same< typename std::remove_reference< U >::type, A >::value &&
266                           std::is_constructible< A, U >::value &&
267                           std::is_assignable< A&, U >::value >::type >
268   Optional& operator=( U&& a )
269   {
270     if( hasValue )
271       place = std::forward< U >( a );
272     else
273     {
274       hasValue = true;
275       new( &place ) A( std::forward< U >( a ) );
276     }
277     return *this;
278   }
279 };
280
281 #endif