diff --git a/furlang/include/furlang/result.hpp b/furlang/include/furlang/result.hpp index 03948ff..88940d3 100644 --- a/furlang/include/furlang/result.hpp +++ b/furlang/include/furlang/result.hpp @@ -6,45 +6,101 @@ namespace furlang { +/** + * @brief Bad result access exception. + */ class bad_result_access : public std::exception { public: bad_result_access() = default; ~bad_result_access() override = default; - bad_result_access(bad_result_access&&) noexcept = default; + /** + * @brief Move constructor. + */ + bad_result_access(bad_result_access&&) noexcept = default; + + /** + * @brief Move constructor. + */ bad_result_access& operator=(bad_result_access&&) noexcept = default; - bad_result_access(const bad_result_access&) = default; - bad_result_access& operator=(const bad_result_access&) = default; + + /** + * @brief Copy constructor. + */ + bad_result_access(const bad_result_access&) = default; + + /** + * @brief Copy constructor. + */ + bad_result_access& operator=(const bad_result_access&) = default; public: + /** + * @brief Returns a C-style string describing the cause of the error. + * + * @return The cause of the error. + */ const char* what() const noexcept override { return "bad result access"; } }; +/** + * @brief Result. + * + * Result stores either value or error. + * + * @tparam R Value type. + * @tparam E Error type. + */ template class result { public: - using value_type = std::remove_reference_t; - using value_reference = value_type&; - using value_const_reference = const value_type&; - using value_pointer = value_type*; - using value_const_pointer = const value_type*; - using error_type = std::remove_reference_t; - using error_reference = error_type&; - using error_const_reference = const error_type&; + using value_type = std::remove_reference_t; /**< Value type. */ + using value_reference = value_type&; /**< Value reference type. */ + using value_const_reference = const value_type&; /**< Value const reference type. */ + using value_pointer = value_type*; /**< Value pointer type. */ + using value_const_pointer = const value_type*; /**< Value const pointer type. */ + using error_type = std::remove_reference_t; /**< Error type. */ + using error_reference = error_type&; /**< Error reference type. */ + using error_const_reference = const error_type&; /**< Error const reference type. */ public: + /** + * @brief Construct a new result. + * + * @param value Value to copy. + */ result(const value_type& value) { new (&m_value.result) value_type(value); } + /** + * @brief Construct a new result. + * + * @param value Value to move. + */ result(value_type&& value) { new (&m_value.result) value_type(std::move(value)); } + /** + * @brief Construct a new result. + * + * @param args Variadic arguments to construct the value with. + */ template result(Args&&... args) { new (&m_value.result) value_type(std::forward(args)...); } + /** + * @brief Construct a new error result. + * + * @param error Error to copy. + */ explicit result(const error_type& error) : m_error(true) { new (&m_value.error) error_type(error); } + /** + * @brief Construct a new error result. + * + * @param error Error to move. + */ explicit result(error_type&& error) : m_error(true) { new (&m_value.error) error_type(std::move(error)); @@ -58,6 +114,9 @@ public: } } + /** + * @brief Move constructor. + */ result(result&& other) noexcept : m_error(other.m_error) { if (m_error) { @@ -67,6 +126,9 @@ public: } } + /** + * @brief Move constructor. + */ result& operator=(result&& other) noexcept { if (this == &other) return *this; m_error = other.m_error; @@ -78,6 +140,9 @@ public: return *this; } + /** + * @brief Copy constructor. + */ result(const result& other) : m_error(other.m_error) { if (m_error) { @@ -87,6 +152,9 @@ public: } } + /** + * @brief Copy constructor. + */ result& operator=(const result& other) { if (this == &other) return *this; m_error = other.m_error; @@ -98,60 +166,156 @@ public: return *this; } public: - operator bool() const { return !m_error; } + /** + * @brief Checks if this result contains a value. + * + * @return true if contains a value. + */ + operator bool() const { return !m_error; } + + /** + * @brief Checks if this result contains an error. + * + * @return true if contains an error. + */ bool operator!() const { return m_error; } + /** + * @brief Compares two results for equality. + * + * @param rhs Result to compare against. + * @return true if the results are equal. + */ bool operator==(const result& rhs) const { return m_error == rhs.m_error && m_error ? m_value.error == rhs.m_value.error : m_value.result == rhs.m_value.result; } + /** + * @brief Compares two results for inequality. + * + * @param rhs Result to compare against. + * @return true if the results are not equal. + */ bool operator!=(const result& rhs) const { return !this->operator==(rhs); } - value_reference operator*() { return value(); } + /** + * @brief Returns a reference to value. + * + * @return Reference to the value. + */ + value_reference operator*() { return value(); } + + /** + * @brief Returns a reference to value. + * + * @return Const reference to the value. + */ value_const_reference operator*() const { return value(); } - value_pointer operator->() { return &value(); } + /** + * @brief Returns a pointer to value. + * + * @return Pointer to the value. + */ + value_pointer operator->() { return &value(); } + + /** + * @brief Returns a pointer to value. + * + * @return Const pointer to the value. + */ value_const_pointer operator->() const { return &value(); } public: + /** + * @brief Checks if this result has a value. + * + * @return true if has a value. + */ bool has_value() const { return !m_error; } + + /** + * @brief Checks if this result has an error. + * + * @return true if has an error. + */ bool has_error() const { return m_error; } + /** + * @brief Returns a reference to value. + * + * @return Reference to the value. + */ value_reference value() { if (m_error) throw bad_result_access(); return m_value.result; } + /** + * @brief Returns a reference to value. + * + * @return Const reference to the value. + */ value_const_reference value() const { if (m_error) throw bad_result_access(); return m_value.result; } + /** + * @brief Returns a reference to error. + * + * @return Reference to the error. + */ error_reference error() { if (!m_error) throw bad_result_access(); return m_value.error; } + /** + * @brief Returns a reference to error. + * + * @return Const reference to the error. + */ error_const_reference error() const { if (!m_error) throw bad_result_access(); return m_value.error; } public: + /** + * @brief Sets this results value. + * + * @param value Value to copy. + */ void set_value(const value_type& value) { if (m_error) m_value.error.~error_type(); new (&m_value.result) value_type(value); } + /** + * @brief Sets this results value. + * + * @param value Value to move. + */ void set_value(value_type&& value) { if (m_error) m_value.error.~error_type(); new (&m_value.result) value_type(std::move(value)); } + /** + * @brief Sets this results error. + * + * @param error Error to copy. + */ void set_error(const error_type& error) { if (!m_error) m_value.result.~value_type(); new (&m_value.error) error_type(error); } + /** + * @brief Sets this results error. + * + * @param error Error to move. + */ void set_error(error_type&& error) { if (!m_error) m_value.result.~value_type(); new (&m_value.error) error_type(std::move(error));