Monero
expect.h
Go to the documentation of this file.
1 // Copyright (c) 2018-2022, The Monero Project
2 
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #pragma once
31 
32 #include <cassert>
33 #include <system_error>
34 #include <type_traits>
35 #include <utility>
36 
37 #include "common/error.h"
38 
40 #define MONERO_PRECOND(...) \
41  do \
42  { \
43  if (!( __VA_ARGS__ )) \
44  return {::common_error::kInvalidArgument}; \
45  } while (0)
46 
48 #define MONERO_CHECK(...) \
49  do \
50  { \
51  const ::expect<void> result = __VA_ARGS__ ; \
52  if (!result) \
53  return result.error(); \
54  } while (0)
55 
61 #define MONERO_UNWRAP(...) \
62  ::detail::expect::unwrap( __VA_ARGS__ , nullptr, __FILE__ , __LINE__ )
63 
64 /* \throw std::system_error with `code` and `msg` as part of the details. The
65 filename and line number will automatically be injected into the explanation
66 string. `code` can be any enum convertible to `std::error_code`. */
67 #define MONERO_THROW(code, msg) \
68  ::detail::expect::throw_( code , msg , __FILE__ , __LINE__ )
69 
70 
71 template<typename> class expect;
72 
73 namespace detail
74 {
75  // Shortens the characters in the places that `enable_if` is used below.
76  template<bool C>
78 
79  struct expect
80  {
82  static void throw_(std::error_code ec, const char* msg, const char* file, unsigned line);
83 
85  template<typename T>
86  static T unwrap(::expect<T>&& result, const char* error_msg, const char* file, unsigned line)
87  {
88  if (!result)
89  throw_(result.error(), error_msg, file, line);
90  return std::move(*result);
91  }
92 
94  static void unwrap(::expect<void>&& result, const char* error_msg, const char* file, unsigned line);
95  };
96 }
97 
132 template<typename T>
133 class expect
134 {
135  static_assert(std::is_nothrow_destructible<T>(), "T must have a nothrow destructor");
136 
137  template<typename U>
138  static constexpr bool is_convertible() noexcept
139  {
140  return std::is_constructible<T, U>() &&
141  std::is_convertible<U, T>();
142  }
143 
144  // MEMBERS
145  std::error_code code_;
147  // MEMBERS
148 
149  T& get() noexcept
150  {
151  assert(has_value());
152  return *reinterpret_cast<T*>(std::addressof(storage_));
153  }
154 
155  T const& get() const noexcept
156  {
157  assert(has_value());
158  return *reinterpret_cast<T const*>(std::addressof(storage_));
159  }
160 
161  template<typename U>
162  void store(U&& value) noexcept(std::is_nothrow_constructible<T, U>())
163  {
164  new (std::addressof(storage_)) T{std::forward<U>(value)};
165  code_ = std::error_code{};
166  }
167 
168  void maybe_throw() const
169  {
170  if (has_error())
171  ::detail::expect::throw_(error(), nullptr, nullptr, 0);
172  }
173 
174 public:
175  using value_type = T;
176  using error_type = std::error_code;
177 
178  expect() = delete;
179 
183  expect(std::error_code const& code) noexcept
184  : code_(code), storage_()
185  {
186  if (!has_error())
187  code_ = ::common_error::kInvalidErrorCode;
188  }
189 
191  expect(T val) noexcept(std::is_nothrow_move_constructible<T>())
192  : code_(), storage_()
193  {
194  store(std::move(val));
195  }
196 
197  expect(expect const& src) noexcept(std::is_nothrow_copy_constructible<T>())
198  : code_(src.error()), storage_()
199  {
200  if (src.has_value())
201  store(src.get());
202  }
203 
205  template<typename U, typename = detail::enable_if<is_convertible<U const&>()>>
206  expect(expect<U> const& src) noexcept(std::is_nothrow_constructible<T, U const&>())
207  : code_(src.error()), storage_()
208  {
209  if (src.has_value())
210  store(*src);
211  }
212 
213  expect(expect&& src) noexcept(std::is_nothrow_move_constructible<T>())
214  : code_(src.error()), storage_()
215  {
216  if (src.has_value())
217  store(std::move(src.get()));
218  }
219 
221  template<typename U, typename = detail::enable_if<is_convertible<U>()>>
222  expect(expect<U>&& src) noexcept(std::is_nothrow_constructible<T, U>())
223  : code_(src.error()), storage_()
224  {
225  if (src.has_value())
226  store(std::move(*src));
227  }
228 
229  ~expect() noexcept
230  {
231  if (has_value())
232  get().~T();
233  }
234 
235  expect& operator=(expect const& src) noexcept(std::is_nothrow_copy_constructible<T>() && std::is_nothrow_copy_assignable<T>())
236  {
237  if (this != std::addressof(src))
238  {
239  if (has_value() && src.has_value())
240  get() = src.get();
241  else if (has_value())
242  get().~T();
243  else if (src.has_value())
244  store(src.get());
245  code_ = src.error();
246  }
247  return *this;
248  }
249 
252  expect& operator=(expect&& src) noexcept(std::is_nothrow_move_constructible<T>() && std::is_nothrow_move_assignable<T>())
253  {
254  if (this != std::addressof(src))
255  {
256  if (has_value() && src.has_value())
257  get() = std::move(src.get());
258  else if (has_value())
259  get().~T();
260  else if (src.has_value())
261  store(std::move(src.get()));
262  code_ = src.error();
263  }
264  return *this;
265  }
266 
268  explicit operator bool() const noexcept { return has_value(); }
269 
271  bool has_error() const noexcept { return bool(code_); }
272 
274  bool has_value() const noexcept { return !has_error(); }
275 
277  std::error_code error() const noexcept { return code_; }
278 
280  T& value() &
281  {
282  maybe_throw();
283  return get();
284  }
285 
287  T const& value() const &
288  {
289  maybe_throw();
290  return get();
291  }
292 
295  T&& value() &&
296  {
297  maybe_throw();
298  return std::move(get());
299  }
300 
302  T* operator->() noexcept { return std::addressof(get()); }
304  T const* operator->() const noexcept { return std::addressof(get()); }
306  T& operator*() noexcept { return get(); }
308  T const& operator*() const noexcept { return get(); }
309 
314  template<typename U>
315  bool equal(expect<U> const& rhs) const noexcept(noexcept(*std::declval<expect<T>>() == *rhs))
316  {
317  return has_value() && rhs.has_value() ?
318  get() == *rhs : error() == rhs.error();
319  }
320 
322  bool equal(std::error_code const& rhs) const noexcept
323  {
324  return has_error() && error() == rhs;
325  }
326 
332  bool equal(U const& rhs) const noexcept(noexcept(*std::declval<expect<T>>() == rhs))
333  {
334  return has_value() && get() == rhs;
335  }
336 
338  bool matches(std::error_condition const& rhs) const noexcept
339  {
340  return has_error() && error() == rhs;
341  }
342 };
343 
344 template<>
345 class expect<void>
346 {
347  std::error_code code_;
348 
349 public:
350  using value_type = void;
351  using error_type = std::error_code;
352 
354  expect() noexcept
355  : code_()
356  {}
357 
358  expect(std::error_code const& code) noexcept
359  : code_(code)
360  {
361  if (!has_error())
362  code_ = ::common_error::kInvalidErrorCode;
363  }
364 
365  expect(expect const&) = default;
366  ~expect() = default;
367  expect& operator=(expect const&) = default;
368 
370  explicit operator bool() const noexcept { return !has_error(); }
371 
373  bool has_error() const noexcept { return bool(code_); }
374 
376  std::error_code error() const noexcept { return code_; }
377 
379  bool equal(expect const& rhs) const noexcept
380  {
381  return error() == rhs.error();
382  }
383 
385  bool equal(std::error_code const& rhs) const noexcept
386  {
387  return has_error() && error() == rhs;
388  }
389 
391  bool matches(std::error_condition const& rhs) const noexcept
392  {
393  return has_error() && error() == rhs;
394  }
395 };
396 
398 inline expect<void> success() noexcept { return expect<void>{}; }
399 
400 template<typename T, typename U>
401 inline
402 bool operator==(expect<T> const& lhs, expect<U> const& rhs) noexcept(noexcept(lhs.equal(rhs)))
403 {
404  return lhs.equal(rhs);
405 }
406 
407 template<typename T, typename U>
408 inline
409 bool operator==(expect<T> const& lhs, U const& rhs) noexcept(noexcept(lhs.equal(rhs)))
410 {
411  return lhs.equal(rhs);
412 }
413 
414 template<typename T, typename U>
415 inline
416 bool operator==(T const& lhs, expect<U> const& rhs) noexcept(noexcept(rhs.equal(lhs)))
417 {
418  return rhs.equal(lhs);
419 }
420 
421 template<typename T, typename U>
422 inline
423 bool operator!=(expect<T> const& lhs, expect<U> const& rhs) noexcept(noexcept(lhs.equal(rhs)))
424 {
425  return !lhs.equal(rhs);
426 }
427 
428 template<typename T, typename U>
429 inline
430 bool operator!=(expect<T> const& lhs, U const& rhs) noexcept(noexcept(lhs.equal(rhs)))
431 {
432  return !lhs.equal(rhs);
433 }
434 
435 template<typename T, typename U>
436 inline
437 bool operator!=(T const& lhs, expect<U> const& rhs) noexcept(noexcept(rhs.equal(lhs)))
438 {
439  return !rhs.equal(lhs);
440 }
441 
442 namespace detail
443 {
444  inline void expect::unwrap(::expect<void>&& result, const char* error_msg, const char* file, unsigned line)
445  {
446  if (!result)
447  throw_(result.error(), error_msg, file, line);
448  }
449 }
450 
T & value() &
Definition: expect.h:280
bool equal(std::error_code const &rhs) const noexcept
Definition: expect.h:385
expect(expect &&src) noexcept(std::is_nothrow_move_constructible< T >())
Definition: expect.h:213
expect(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >())
Definition: expect.h:197
const uint32_t T[512]
Definition: groestl_tables.h:36
std::error_code code_
Definition: expect.h:347
std::error_code code_
Definition: expect.h:145
bool has_value() const noexcept
Definition: expect.h:274
bool operator!=(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
Definition: expect.h:423
bool matches(std::error_condition const &rhs) const noexcept
Definition: expect.h:391
T const & value() const &
Definition: expect.h:287
std::aligned_storage< sizeof(T), alignof(T)>::type storage_
Definition: expect.h:146
void maybe_throw() const
Definition: expect.h:168
expect() noexcept
Create a successful object.
Definition: expect.h:354
T * operator->() noexcept
Definition: expect.h:302
int type
Definition: superscalar.cpp:50
expect(expect< U > &&src) noexcept(std::is_nothrow_constructible< T, U >())
Move conversion from U to T.
Definition: expect.h:222
bool equal(U const &rhs) const noexcept(noexcept(*std::declval< expect< T >>()==rhs))
Definition: expect.h:332
std::error_code error_type
Definition: expect.h:351
expect & operator=(expect &&src) noexcept(std::is_nothrow_move_constructible< T >() &&std::is_nothrow_move_assignable< T >())
Definition: expect.h:252
tools::wallet2::message_signature_result_t result
Definition: signature.cpp:62
expect & operator=(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >() &&std::is_nothrow_copy_assignable< T >())
Definition: expect.h:235
bool operator==(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
Definition: expect.h:402
expect(std::error_code const &code) noexcept
Definition: expect.h:183
bool equal(std::error_code const &rhs) const noexcept
Definition: expect.h:322
void store(U &&value) noexcept(std::is_nothrow_constructible< T, U >())
Definition: expect.h:162
Definition: expect.h:79
std::error_code error() const noexcept
Definition: expect.h:277
static T unwrap(::expect< T > &&result, const char *error_msg, const char *file, unsigned line)
If result.has_error() call throw_. Otherwise,.
Definition: expect.h:86
T && value() &&
Definition: expect.h:295
expect(expect< U > const &src) noexcept(std::is_nothrow_constructible< T, U const &>())
Copy conversion from U to T.
Definition: expect.h:206
void value_type
Definition: expect.h:350
const portMappingElt code
Definition: portlistingparse.c:22
static constexpr bool is_convertible() noexcept
Definition: expect.h:138
declaration and default definition for the functions used the API
Definition: expect.cpp:33
expect()=delete
Definition: expect.h:71
T value_type
Definition: expect.h:175
bool equal(expect const &rhs) const noexcept
Definition: expect.h:379
expect(std::error_code const &code) noexcept
Definition: expect.h:358
bool matches(std::error_condition const &rhs) const noexcept
Definition: expect.h:338
T & get() noexcept
Definition: expect.h:149
T const * operator->() const noexcept
Definition: expect.h:304
~expect() noexcept
Definition: expect.h:229
bool has_error() const noexcept
Definition: expect.h:373
expect< void > success() noexcept
Definition: expect.h:398
T & operator*() noexcept
Definition: expect.h:306
const T & move(const T &t)
Definition: gtest-port.h:1317
bool equal(expect< U > const &rhs) const noexcept(noexcept(*std::declval< expect< T >>()== *rhs))
Definition: expect.h:315
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
static void throw_(std::error_code ec, const char *msg, const char *file, unsigned line)
Definition: expect.cpp:64
Definition: expect.h:345
int bool
Definition: stdbool.h:35
std::error_code error_type
Definition: expect.h:176
T const & operator*() const noexcept
Definition: expect.h:308
bool has_error() const noexcept
Definition: expect.h:271
typename std::enable_if< C >::type enable_if
Definition: expect.h:77
expect(T val) noexcept(std::is_nothrow_move_constructible< T >())
Store a value, val, in the expect object.
Definition: expect.h:191
line
Definition: check.py:23
#define const
Definition: ipfrdr.c:80
std::error_code error() const noexcept
Definition: expect.h:376