32#include <system_error>
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__ )
70template<
typename>
class expect;
81 static void throw_(std::error_code ec,
const char* msg,
const char* file,
unsigned line);
88 throw_(result.error(), error_msg, file, line);
89 return std::move(*result);
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_()
190 expect(
T val)
noexcept(std::is_nothrow_move_constructible<T>())
191 : code_(), storage_()
193 store(std::move(val));
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_()
216 store(std::move(src.get()));
220 template<typename U, typename = detail::enable_if<is_convertible<U>()>>
222 : code_(src.
error()), storage_()
225 store(std::move(*src));
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))
256 get() = std::move(src.get());
259 else if (src.has_value())
260 store(std::move(src.get()));
267 explicit operator bool() const noexcept {
return has_value(); }
270 bool has_error() const noexcept {
return bool(code_); }
273 bool has_value() const noexcept {
return !has_error(); }
276 std::error_code
error() const noexcept {
return code_; }
297 return std::move(get());
301 T* operator->() noexcept {
return std::addressof(get()); }
303 T const* operator->() const noexcept {
return std::addressof(get()); }
305 T& operator*() noexcept {
return get(); }
307 T const& operator*() const noexcept {
return get(); }
314 bool equal(
expect<U> const& rhs)
const noexcept(
noexcept(*std::declval<expect<T>>() == *rhs))
317 get() == *rhs :
error() == rhs.error();
321 bool equal(std::error_code
const& rhs)
const noexcept
323 return has_error() &&
error() == rhs;
330 template<typename U, typename = detail::enable_if<!std::is_constructible<std::error_code, U>::value>>
331 bool equal(U
const& rhs)
const noexcept(
noexcept(*std::declval<expect<T>>() == rhs))
337 bool matches(std::error_condition
const& rhs)
const noexcept
339 return has_error() &&
error() == rhs;
346 std::error_code code_;
357 expect(std::error_code
const& code) noexcept
369 explicit operator bool() const noexcept {
return !
has_error(); }
375 std::error_code
error() const noexcept {
return code_; }
380 return error() == rhs.error();
384 bool equal(std::error_code
const& rhs)
const noexcept
386 return has_error() &&
error() == rhs;
390 bool matches(std::error_condition
const& rhs)
const noexcept
392 return has_error() &&
error() == rhs;
399template<
typename T,
typename U>
403 return lhs.equal(rhs);
406template<
typename T,
typename U>
410 return lhs.equal(rhs);
413template<
typename T,
typename U>
417 return rhs.equal(lhs);
420template<
typename T,
typename U>
424 return !lhs.equal(rhs);
427template<
typename T,
typename U>
431 return !lhs.equal(rhs);
434template<
typename T,
typename U>
438 return !rhs.equal(lhs);
446 throw_(result.error(), error_msg, file, line);
*return True if this is storing an error instead of a value bool has_error() const noexcept
std::error_code error_type
*Create a successful object expect() noexcept
expect(std::error_code const &code) noexcept
expect(expect const &)=default
expect & operator=(expect const &)=default
*return Error alway std::error_code error() const noexcept
expect & operator=(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >() &&std::is_nothrow_copy_assignable< T >())
expect(expect< U > &&src) noexcept(std::is_nothrow_constructible< T, U >())
Move conversion from U to T.
*return False if otherwise error()
expect(expect< U > const &src) noexcept(std::is_nothrow_constructible< T, U const & >())
Copy conversion from U to T.
expect(expect const &src) noexcept(std::is_nothrow_copy_constructible< T >())
*return pre has_value()`. T *operator->() noexcept
expect(T val) noexcept(std::is_nothrow_move_constructible< T >())
Store a value, val, in the expect object.
expect(expect &&src) noexcept(std::is_nothrow_move_constructible< T >())
bool equal(expect< U > const &rhs) const noexcept(noexcept(*std::declval< expect< T > >()== *rhs))
std::error_code error_type
expect(std::error_code const &code) noexcept
bool operator!=(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
bool operator==(expect< T > const &lhs, expect< U > const &rhs) noexcept(noexcept(lhs.equal(rhs)))
void get(std::istream &input, bool &res)
declaration and default definition for the functions used the API
typename std::enable_if< C >::type enable_if
const GenericPointer< typename T::ValueType > T2 value
@ kInvalidErrorCode
Default std::error_code given to expect<T>.
static T unwrap(::expect< T > &&result, const char *error_msg, const char *file, unsigned line)
If result.has_error() call throw_. Otherwise,.
static void throw_(std::error_code ec, const char *msg, const char *file, unsigned line)