32 #include <system_error> 33 #include <type_traits> 39 #define ELECTRONEUM_PRECOND(...) \ 42 if (!( __VA_ARGS__ )) \ 43 return {::common_error::kInvalidArgument}; \ 47 #define ELECTRONEUM_CHECK(...) \ 50 const ::expect<void> result = __VA_ARGS__ ; \ 52 return result.error(); \ 60 #define ELECTRONEUM_UNWRAP(...) \ 61 ::detail::expect::unwrap( __VA_ARGS__ , nullptr, __FILE__ , __LINE__ ) 66 #define ELECTRONEUM_THROW(code, msg) \ 67 ::detail::expect::throw_( code , msg , __FILE__ , __LINE__ ) 81 static void throw_(std::error_code ec,
const char* msg,
const char* file,
unsigned line);
85 static T unwrap(::
expect<T>&& result,
const char* error_msg,
const char* file,
unsigned line)
88 throw_(result.error(), error_msg, file, line);
93 static void unwrap(::
expect<void>&& result,
const char* error_msg,
const char* file,
unsigned line);
134 static_assert(std::is_nothrow_destructible<T>(),
"T must have a nothrow destructor");
137 static constexpr
bool is_convertible() noexcept
139 return std::is_constructible<T, U>() &&
140 std::is_convertible<U, T>();
144 std::error_code code_;
145 typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
151 return *
reinterpret_cast<T*
>(std::addressof(storage_));
154 T const&
get()
const noexcept
157 return *
reinterpret_cast<T const*
>(std::addressof(storage_));
161 void store(U&&
value) noexcept(std::is_nothrow_constructible<T, U>())
163 new (std::addressof(storage_))
T{std::forward<U>(
value)};
164 code_ = std::error_code{};
167 void maybe_throw()
const 182 expect(std::error_code
const& code) noexcept
183 : code_(code), storage_()
186 code_ = ::common_error::kInvalidErrorCode;
190 expect(
T val) noexcept(std::is_nothrow_move_constructible<T>())
191 : code_(), storage_()
196 expect(
expect const& src) noexcept(std::is_nothrow_copy_constructible<T>())
197 : code_(src.
error()), storage_()
204 template<
typename U,
typename = detail::enable_if<is_convertible<U const&>()>>
206 : code_(src.
error()), storage_()
213 : code_(src.
error()), storage_()
220 template<
typename U,
typename = detail::enable_if<is_convertible<U>()>>
222 : code_(src.
error()), storage_()
234 expect&
operator=(
expect const& src) noexcept(std::is_nothrow_copy_constructible<T>() && std::is_nothrow_copy_assignable<T>())
236 if (
this != std::addressof(src))
242 else if (src.has_value())
251 expect&
operator=(
expect&& src) noexcept(std::is_nothrow_move_constructible<T>() && std::is_nothrow_move_assignable<T>())
253 if (
this != std::addressof(src))
259 else if (src.has_value())
276 std::error_code
error() const noexcept {
return code_; }
303 T const*
operator->() const noexcept {
return std::addressof(
get()); }
317 get() == *rhs :
error() == rhs.error();
321 bool equal(std::error_code
const& rhs)
const noexcept
331 bool equal(U
const& rhs)
const noexcept(noexcept(*std::declval<
expect<T>>() == rhs))
337 bool matches(std::error_condition
const& rhs)
const noexcept
346 std::error_code code_;
357 expect(std::error_code
const& code) noexcept
361 code_ = ::common_error::kInvalidErrorCode;
375 std::error_code
error() const noexcept {
return code_; }
380 return error() == rhs.error();
384 bool equal(std::error_code
const& rhs)
const noexcept
390 bool matches(std::error_condition
const& rhs)
const noexcept
399 template<
typename T,
typename U>
403 return lhs.equal(rhs);
406 template<
typename T,
typename U>
410 return lhs.equal(rhs);
413 template<
typename T,
typename U>
417 return rhs.equal(lhs);
420 template<
typename T,
typename U>
424 return !lhs.equal(rhs);
427 template<
typename T,
typename U>
431 return !lhs.equal(rhs);
434 template<
typename T,
typename U>
438 return !rhs.equal(lhs);
446 throw_(result.error(), error_msg, file, line);
bool equal(std::error_code const &rhs) const noexcept
expect(expect &&src) noexcept(std::is_nothrow_move_constructible< T >())
expect(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >())
bool has_value() const noexcept
bool operator!=(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
bool matches(std::error_condition const &rhs) const noexcept
T const & value() const &
expect() noexcept
Create a successful object.
T * operator->() noexcept
expect(expect< U > &&src) noexcept(std::is_nothrow_constructible< T, U >())
Move conversion from U to T.
bool equal(U const &rhs) const noexcept(noexcept(*std::declval< expect< T >>()==rhs))
std::error_code error_type
expect & operator=(expect &&src) noexcept(std::is_nothrow_move_constructible< T >() &&std::is_nothrow_move_assignable< T >())
expect & operator=(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >() &&std::is_nothrow_copy_assignable< T >())
bool operator==(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
expect(std::error_code const &code) noexcept
bool equal(std::error_code const &rhs) const noexcept
std::error_code error() const noexcept
static T unwrap(::expect< T > &&result, const char *error_msg, const char *file, unsigned line)
If result.has_error() call throw_. Otherwise,.
expect(expect< U > const &src) noexcept(std::is_nothrow_constructible< T, U const &>())
Copy conversion from U to T.
declaration and default definition for the functions used the API
bool equal(expect const &rhs) const noexcept
expect(std::error_code const &code) noexcept
bool matches(std::error_condition const &rhs) const noexcept
T const * operator->() const noexcept
bool has_error() const noexcept
expect< void > success() noexcept
const T & move(const T &t)
bool equal(expect< U > const &rhs) const noexcept(noexcept(*std::declval< expect< T >>()== *rhs))
const GenericPointer< typename T::ValueType > T2 value
static void throw_(std::error_code ec, const char *msg, const char *file, unsigned line)
std::error_code error_type
T const & operator*() const noexcept
bool has_error() const noexcept
typename std::enable_if< C >::type enable_if
expect(T val) noexcept(std::is_nothrow_move_constructible< T >())
Store a value, val, in the expect object.
std::error_code error() const noexcept