From 82c9037a6a9a95196b31fb6738dd587f9cd7dfa3 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 31 May 2026 11:40:39 +0200 Subject: [PATCH] Add result to furlang Signed-off-by: CHatingPython --- .clang-tidy | 3 + furlang/include/furlang/result.hpp | 143 +++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 furlang/include/furlang/result.hpp diff --git a/.clang-tidy b/.clang-tidy index b8580c9..88d2f52 100755 --- a/.clang-tidy +++ b/.clang-tidy @@ -44,6 +44,9 @@ CheckOptions: - key: readability-identifier-length.MinimumVariableNameLength value: 2 + - key: cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove + value: true + # Namespaces - key: readability-identifier-naming.NamespaceCase value: lower_case diff --git a/furlang/include/furlang/result.hpp b/furlang/include/furlang/result.hpp new file mode 100644 index 0000000..e1eb04d --- /dev/null +++ b/furlang/include/furlang/result.hpp @@ -0,0 +1,143 @@ +#ifndef FURLANG_RESULT_HPP +#define FURLANG_RESULT_HPP + +#include +#include + +namespace furlang { + +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; + 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; +public: + const char* what() const noexcept override { return "bad result access"; } +}; + +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&; +public: + result(const value_type& value) { new (&m_value.result) value_type(value); } + + result(value_type&& value) { new (&m_value.result) value_type(std::move(value)); } + + template + result(Args&&... args) { + new (&m_value.result) value_type(std::forward(args)...); + } + + explicit result(const error_type& error) + : m_error(true) { + m_value.error = error; + } + + explicit result(error_type&& error) + : m_error(true) { + m_value.error = std::move(error); + } + + ~result() { + if (m_error) { + m_value.error.~error_type(); + } else { + m_value.result.~value_type(); + } + } + + result(result&& other) noexcept {} + + result& operator=(result&& other) noexcept { + if (this == &other) return *this; + return *this; + } + + result(const result& other) {} + + result& operator=(const result& other) { + if (this == &other) return *this; + return *this; + } +public: + operator bool() const { return !m_error; } + bool operator!() const { return m_error; } + + 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; + } + + bool operator!=(const result& rhs) const { return !this->operator==(rhs); } + + value_reference operator*() { return value(); } + value_const_reference operator*() const { return value(); } + + value_pointer operator->() { return &value(); } + value_const_pointer operator->() const { return &value(); } +public: + bool has_value() const { return !m_error; } + bool has_error() const { return m_error; } + + value_reference value() { + if (m_error) throw bad_result_access(); + return m_value.result; + } + + value_const_reference value() const { + if (m_error) throw bad_result_access(); + return m_value.result; + } + + error_reference error() { + if (!m_error) throw bad_result_access(); + return m_value.error; + } + + error_const_reference error() const { + if (!m_error) throw bad_result_access(); + return m_value.error; + } +public: + void set_value(const value_type& value) { + if (m_error) m_value.error.~error_type(); + new (&m_value.result) value_type(value); + } + + void set_value(value_type&& value) { + if (m_error) m_value.error.~error_type(); + new (&m_value.result) value_type(std::move(value)); + } + + void set_error(const error_type& error) { + if (!m_error) m_value.result.~value_type(); + new (&m_value.error) error_type(error); + } + + void set_error(error_type&& error) { + if (!m_error) m_value.result.~value_type(); + new (&m_value.error) error_type(std::move(error)); + } +private: + union value { + value_type result; + error_type error; + } m_value; + bool m_error = false; +}; + +} // namespace furlang + +#endif // FURLANG_RESULT_HPP \ No newline at end of file