Sleeping Wombat Common Library  0.50.0
swCommonLibrary
Nullable.h
1 #pragma once
2 
8 #include "Exception.h"
9 
10 #include <exception>
11 #include <string>
12 #include <memory>
13 #include <type_traits>
14 #include <assert.h>
15 
16 
17 
18 
19 namespace sw
20 {
21 
22 
25 enum class Result : uint8
26 {
27  Error,
28  Success
29 };
30 
31 
32 
35 template< typename ContentType >
36 class Nullable
37 {
38 public:
39 
40  typedef ExceptionPtr ErrorType;
41 
42 protected:
43  union
44  {
45  ContentType Content;
46  ErrorType Error;
47  };
48 
49  bool m_isValid;
50 
51 public:
52 
53  explicit Nullable ();
54  Nullable ( ContentType&& content );
55  Nullable ( const ContentType& content );
56  Nullable ( const ErrorType& error );
57  Nullable ( const std::string& error );
58  Nullable ( const Nullable< ContentType > & that );
59  ~Nullable ();
60 
61  template< typename ExceptionType >
62  Nullable ( std::shared_ptr< ExceptionType > error );
63 
64  bool IsValid ();
65  std::string GetErrorReason ();
66  ErrorType GetError ();
67 
68  bool operator== ( const ContentType & that );
69  bool operator!= ( const ContentType & that );
70  Nullable< ContentType >& operator= ( const Nullable< ContentType > & that );
71 
72  const ContentType & Get () const;
73  operator const ContentType & () const;
74 
75  ContentType & Get ();
76  operator ContentType & ();
77 
78 public:
79 
80  static Nullable FromError ( const ErrorType& error );
81  static Nullable FromError ( const std::string& reason );
82  static Nullable FromError ();
83 };
84 
85 
88 template<>
89 class Nullable< void >
90 {
91 public:
92 
93  typedef ExceptionPtr ErrorType;
94 
95 private:
96 
97  ErrorType Error;
98  bool m_isValid;
99 
100 public:
101 
102  explicit Nullable ();
103  Nullable ( Result result );
104  Nullable ( const ErrorType& error );
105  Nullable ( const std::string& error );
106 
107  template< typename ExceptionType >
108  Nullable ( std::shared_ptr< ExceptionType > error );
109 
110  bool IsValid ();
111  std::string GetErrorReason ();
112  ErrorType GetError ();
113 
114 };
115 
116 
118 
119 
120 // ========================================================================= //
121 // Implementation
122 // ========================================================================= //
123 
124 // ================================ //
125 //
126 template< typename ContentType >
128  : m_isValid( false )
129  , Error( nullptr )
130 {}
131 
132 // ================================ //
133 //
134 template< typename ContentType >
135 inline Nullable< ContentType >::Nullable ( ContentType&& content )
136  : m_isValid( true ), Content( std::move( content ) )
137 {}
138 
139 // ================================ //
140 //
141 template< typename ContentType >
142 inline Nullable< ContentType >::Nullable ( const ContentType& content )
143  : m_isValid( true ), Content( content )
144 {}
145 
146 // ================================ //
147 //
148 template< typename ContentType >
149 inline Nullable< ContentType >::Nullable ( const ErrorType & error )
150  : m_isValid( false ), Error( error )
151 {}
152 
153 // ================================ //
154 //
155 template< typename ContentType >
156 inline Nullable< ContentType >::Nullable ( const std::string& error )
157  : m_isValid( false ), Error( std::static_pointer_cast< Exception >( std::make_shared< RuntimeException >( error ) ) )
158 {}
159 
160 // ================================ //
161 //
162 template< typename ContentType >
164  : m_isValid( that.m_isValid )
165 {
166  if( m_isValid )
167  new( &Content ) ContentType( that.Content );
168  else
169  new( &Error ) ErrorType( that.Error );
170 }
171 
172 // ================================ //
173 //
174 template< typename ContentType >
175 template< typename ExceptionType >
176 inline Nullable< ContentType >::Nullable ( std::shared_ptr< ExceptionType > error )
177  : m_isValid( false ), Error( std::static_pointer_cast< Exception >( error ) )
178 {
179  static_assert( std::is_base_of< typename ErrorType::element_type, ExceptionType >::value, "ExceptionType should be derived from ErrorType" );
180 }
181 
182 // ================================ //
183 //
184 template< typename ContentType >
186 {
187  if( m_isValid )
188  Content.~ContentType();
189  else
190  Error.~ErrorType();
191 }
192 
193 // ================================ //
194 //
195 template< typename ContentType >
197 {
198  return m_isValid;
199 }
200 
201 // ================================ //
202 //
203 template< typename ContentType >
204 inline std::string Nullable< ContentType >::GetErrorReason ()
205 {
206  return Error->ErrorMessage();
207 }
208 
209 // ================================ //
210 //
211 template< typename ContentType >
213 {
214  if( m_isValid )
215  assert( false ); // FIXME: error handling(?)
216  return Error;
217 }
218 
219 // ================================ //
220 //
221 template< typename ContentType >
222 inline bool Nullable< ContentType >::operator== ( const ContentType & that )
223 {
224  return m_isValid && Content == that;
225 }
226 
227 // ================================ //
228 //
229 template< typename ContentType >
230 inline bool Nullable< ContentType >::operator!= ( const ContentType & that )
231 {
232  return !( *this == that );
233 }
234 
235 // ================================ //
236 //
237 template< typename ContentType >
239 {
240  if( m_isValid )
241  Content.~ContentType();
242  else
243  Error.~ErrorType();
244 
245  m_isValid = that.m_isValid;
246 
247  if( m_isValid )
248  new( &Content ) ContentType( that.Content );
249  else
250  new( &Error ) ErrorType( that.Error );
251 
252  return *this;
253 }
254 
255 // ================================ //
256 //
257 template< typename ContentType >
258 inline const ContentType & Nullable< ContentType >::Get () const
259 {
260  if( !m_isValid )
261  assert( false ); // FIXME: error handling(?)
262  return Content;
263 }
264 
265 // ================================ //
266 //
267 template< typename ContentType >
268 inline ContentType & Nullable< ContentType >::Get ()
269 {
270  if( !m_isValid )
271  throw Error;
272  return Content;
273 }
274 
275 // ================================ //
276 //
277 template< typename ContentType >
278 inline Nullable< ContentType >::operator const ContentType & () const
279 {
280  return Get();
281 }
282 
283 // ================================ //
284 //
285 template< typename ContentType >
286 inline Nullable< ContentType >::operator ContentType & ()
287 {
288  return Get();
289 }
290 
291 //====================================================================================//
292 // Creating Nullable from error
293 //====================================================================================//
294 
295 template< typename ContentType >
296 inline Nullable< ContentType > Nullable< ContentType >::FromError ( const ErrorType& error )
297 {
299  ret.Error = error;
300  return ret;
301 }
302 
303 template< typename ContentType >
304 inline Nullable< ContentType > Nullable< ContentType >::FromError ( const std::string& reason )
305 {
306  return FromError( std::make_shared< std::runtime_error >( reason ) );
307 }
308 
309 template< typename ContentType >
311 {
312  return Nullable< ContentType >();
313 }
314 
315 
316 //====================================================================================//
317 // Specialization for void
318 //====================================================================================//
319 
320 
321 // ================================ //
322 //
324  : m_isValid( false )
325  , Error( nullptr )
326 {}
327 
328 // ================================ //
329 //
330 inline Nullable< void >::Nullable ( const ErrorType & error )
331  : m_isValid( false ), Error( error )
332 {}
333 
334 // ================================ //
335 //
336 template< typename ExceptionType >
337 inline Nullable< void >::Nullable ( std::shared_ptr< ExceptionType > error )
338  : m_isValid( false ), Error( std::static_pointer_cast< Exception >( error ) )
339 {
340  static_assert( std::is_base_of< typename ErrorType::element_type, ExceptionType >::value, "ExceptionType should be derived from ErrorType" );
341 }
342 
343 // ================================ //
344 //
345 inline Nullable< void >::Nullable ( const std::string& error )
346  : m_isValid( false ), Error( std::static_pointer_cast< Exception >( std::make_shared< RuntimeException >( error ) ) )
347 {}
348 
349 // ================================ //
350 //
351 inline Nullable< void >::Nullable ( Result result )
352  : m_isValid( result == Result::Success ), Error( nullptr )
353 {}
354 
355 
356 // ================================ //
357 //
358 inline bool Nullable< void >::IsValid()
359 {
360  return m_isValid;
361 }
362 
363 // ================================ //
364 //
365 inline std::string Nullable< void >::GetErrorReason ()
366 {
367  return Error->ErrorMessage();
368 }
369 
370 // ================================ //
371 //
373 {
374  if( m_isValid )
375  assert( false ); // FIXME: error handling(?)
376  return Error;
377 }
378 
379 } // sw
Definition: Exception.h:11
Returns value or error.
Definition: Nullable.h:19
Result
Enumeration for nullable for creating valid and invalid object.
Definition: Nullable.h:25
Alexandrescu Expected type for error handling.
Definition: Nullable.h:36
Alexandrescu Expected type for error handling.
Definition: Nullable.h:89