From 8a96704909de067d550278daffcd03ab5fb86e0a Mon Sep 17 00:00:00 2001 From: Dany LE Date: Wed, 28 Feb 2024 09:35:14 +0100 Subject: [PATCH] refactor: comnbine all in to one single header --- src/error.h | 45 ----------- src/nerr.h | 10 --- src/option.h | 92 ----------------------- src/result.h | 82 -------------------- src/ro.h | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/test.cpp | 16 ++-- 6 files changed, 209 insertions(+), 240 deletions(-) delete mode 100644 src/error.h delete mode 100644 src/nerr.h delete mode 100644 src/option.h delete mode 100644 src/result.h create mode 100644 src/ro.h diff --git a/src/error.h b/src/error.h deleted file mode 100644 index 01493fe..0000000 --- a/src/error.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef NEER_ERROR_H -#define NEER_ERROR_H - -#include -#include -#include - -#define ERR(fmt,...) Error(nerr::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)) - -namespace nerr -{ - template - std::string sfmt(const std::string &format, Args... args) - { - int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' - if (size_s <= 0) - { - throw std::runtime_error("Error during formatting string."); - } - auto size = static_cast(size_s); - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), args...); - return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside - } - - class Error : public std::runtime_error - { - public: - Error(const std::string &s) : runtime_error(s){}; - Error(const char *s) : runtime_error(s){}; - Error(): runtime_error(""){}; - - inline friend bool operator==(const Error& l, const Error& r) - { - return std::string(l.what()) == std::string(r.what()); - } - - inline Error operator+(const Error& other) - { - return Error(std::string(this->what()) + "\n" + other.what()); - } - }; -} - -#endif \ No newline at end of file diff --git a/src/nerr.h b/src/nerr.h deleted file mode 100644 index aa37bf0..0000000 --- a/src/nerr.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NEER_H -#define NEER_H -#include -#include - -#include "error.h" -#include "option.h" -#include "result.h" - -#endif \ No newline at end of file diff --git a/src/option.h b/src/option.h deleted file mode 100644 index 4a11cb2..0000000 --- a/src/option.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef NEER_OPTION_H -#define NEER_OPTION_H - -#define None(T) (nerr::Option()) -#define Some(v) (nerr::Option(v)) - -namespace nerr -{ - template class Result; - - template - class Option - { - - public: - Option(T obj) : m_some(obj), m_notnull(true){}; - Option() : m_notnull(false){}; - - Option& operator=(const T& value) {insert(value); return *this;}; - inline friend bool operator==(const Option& l, const Option& r) { - if(!l.m_notnull && !r.m_notnull) - { - return true; - } - if(l.m_notnull && r.m_notnull) - { - return l.m_some == r.m_some; - } - return false; - }; - - inline bool is_none(){return !m_notnull;}; - inline bool is_some(){return m_notnull;}; - inline T& unwrap() - { - if(m_notnull) - { - return m_some; - } - throw Error("Object is None"); - } - inline T& get_or_insert(T value) - { - if(!m_notnull) - { - insert(value); - } - return m_some; - } - inline T& insert(T value) - { - m_some = value; - m_notnull = true; - return m_some; - } - - template - inline Result ok_or(E err) - { - if(m_notnull) - { - return Result(m_some); - } - return Result(err); - } - - template - inline Option map(const std::function& fn) - { - if(is_some()) - { - return fn(m_some); - } - return Option(); - } - - template - inline U map_or(U defv, const std::function& fn) - { - if(is_some()) - { - return fn(m_some); - } - return defv; - } - - private: - T m_some; - bool m_notnull; - }; -} -#endif \ No newline at end of file diff --git a/src/result.h b/src/result.h deleted file mode 100644 index 05b9e42..0000000 --- a/src/result.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef NEER_RESULT_H -#define NEER_RESULT_H -//#define Ok(v) (nerr::Result(v)) -//#define Err(e) (nerr::Result(e)) - -namespace nerr -{ - //template class Option; - - template - class Result - { - - public: - Result(T obj) : m_result(obj) {}; - Result(E err) { m_error.insert(err); }; - Result(){}; - - inline Result& operator=(const T& value) {m_result = value; m_error = None(E); return *this;}; - inline Result& operator=(const E& err) {m_error.insert(err); return *this;}; - - inline bool is_ok(){return m_error.is_none();}; - inline bool is_err(){return m_error.is_some();}; - - inline T& unwrap() - { - if(is_ok()) - { - return m_result; - } - throw m_error.unwrap(); - } - - inline T& expect(E e) - { - if(is_ok()) - { - return m_result; - } - throw e + m_error.unwrap(); - } - - template - inline Result map(const std::function& fn) - { - if(is_ok()) - { - return fn(m_result); - } - return m_error.unwrap(); - } - - template - inline Result map_err(const std::function& fn) - { - if(!is_ok()) - { - return fn(m_error.unwrap()); - } - return m_result; - } - - template - inline U map_or(U defv, const std::function& fn) - { - if(is_ok()) - { - return fn(m_result); - } - return defv; - } - - Option err() { return m_error; } - Option ok() { return is_ok()?Option(m_result): Option(); } - - private: - T m_result; - Option m_error; - }; -} - -#endif \ No newline at end of file diff --git a/src/ro.h b/src/ro.h new file mode 100644 index 0000000..14a40ad --- /dev/null +++ b/src/ro.h @@ -0,0 +1,204 @@ +#ifndef RO_H +#define RO_H + +#include +#include +#include +#include + +#define None(T) (ro::Option()) +#define Some(v) (ro::Option(v)) +#define ERR(fmt,...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)) +#define Err(e) (ro::Result(e)) +#define Ok(v) (ro::Result(v)) + +namespace ro +{ + template + std::string sfmt(const std::string &format, Args... args) + { + int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' + if (size_s <= 0) + { + throw std::runtime_error("Error during formatting string."); + } + auto size = static_cast(size_s); + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), args...); + return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside + } + + class Error : public std::runtime_error + { + public: + Error(const std::string &s) : runtime_error(s){}; + Error(const char *s) : runtime_error(s){}; + Error(): runtime_error(""){}; + + inline friend bool operator==(const Error& l, const Error& r) + { + return std::string(l.what()) == std::string(r.what()); + } + + inline Error operator+(const Error& other) + { + return Error(std::string(this->what()) + "\n" + other.what()); + } + }; + + template class Result; + + template + class Option + { + + public: + Option(T obj) : m_some(obj), m_notnull(true){}; + Option() : m_notnull(false){}; + + Option& operator=(const T& value) {insert(value); return *this;}; + inline friend bool operator==(const Option& l, const Option& r) { + if(!l.m_notnull && !r.m_notnull) + { + return true; + } + if(l.m_notnull && r.m_notnull) + { + return l.m_some == r.m_some; + } + return false; + }; + + inline bool is_none(){return !m_notnull;}; + inline bool is_some(){return m_notnull;}; + inline T& unwrap() + { + if(m_notnull) + { + return m_some; + } + throw Error("Object is None"); + } + inline T& get_or_insert(T value) + { + if(!m_notnull) + { + insert(value); + } + return m_some; + } + inline T& insert(T value) + { + m_some = value; + m_notnull = true; + return m_some; + } + + template + inline Result ok_or(E err) + { + if(m_notnull) + { + return Result(m_some); + } + return Result(err); + } + + template + inline Option map(const std::function& fn) + { + if(is_some()) + { + return fn(m_some); + } + return Option(); + } + + template + inline U map_or(U defv, const std::function& fn) + { + if(is_some()) + { + return fn(m_some); + } + return defv; + } + + private: + T m_some; + bool m_notnull; + }; + + template + class Result + { + + public: + Result(T obj) : m_result(obj) {}; + Result(E err) { m_error.insert(err); }; + Result(){}; + + inline Result& operator=(const T& value) {m_result = value; m_error = None(E); return *this;}; + inline Result& operator=(const E& err) {m_error.insert(err); return *this;}; + + inline bool is_ok(){return m_error.is_none();}; + inline bool is_err(){return m_error.is_some();}; + + inline T& unwrap() + { + if(is_ok()) + { + return m_result; + } + throw m_error.unwrap(); + } + + inline T& expect(E e) + { + if(is_ok()) + { + return m_result; + } + throw e + m_error.unwrap(); + } + + template + inline Result map(const std::function& fn) + { + if(is_ok()) + { + return fn(m_result); + } + return m_error.unwrap(); + } + + template + inline Result map_err(const std::function& fn) + { + if(!is_ok()) + { + return fn(m_error.unwrap()); + } + return m_result; + } + + template + inline U map_or(U defv, const std::function& fn) + { + if(is_ok()) + { + return fn(m_result); + } + return defv; + } + + Option err() { return m_error; } + Option ok() { return is_ok()?Option(m_result): Option(); } + + private: + T m_result; + Option m_error; + }; +} + +#endif \ No newline at end of file diff --git a/test/test.cpp b/test/test.cpp index 25fbab1..fb3e494 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,15 +1,15 @@ #include -#include "../src/nerr.h" +#include "../src/ro.h" #include #include using namespace std; -using namespace nerr; +using namespace ro; #define assert(v,fmt,...) if(!(v)) { \ - throw Error(nerr::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \ + throw Error(ro::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \ } @@ -20,18 +20,13 @@ void test(const char* desc, const std::function& lambda) lambda(); std::cout << "OK" << std::endl; } - catch(nerr::Error e) + catch(ro::Error e) { std::cout << "FAILED" << std::endl; std::cout << e.what() << std::endl; } } -Result test_return() -{ - return string("Error"); -} - int main(int argc, char const *argv[]) { test("Test Option", [](){ @@ -123,7 +118,6 @@ int main(int argc, char const *argv[]) test("Result map", [](){ auto err = ERR("Error"); auto fn = [](string data){ - cout << data << endl; return 1; }; Result ret = err; @@ -140,7 +134,6 @@ int main(int argc, char const *argv[]) test("Result map err", [](){ auto fn = [](int x){ - cout << "Error code is " << x << endl; return "Hello"; }; Result ret = true; @@ -165,4 +158,5 @@ int main(int argc, char const *argv[]) v = ret.map_or(0, fn); assert(v == 3, "Value mismatch %d",v); }); + }