fix: add base Option and Result implement, add unit tests

This commit is contained in:
DL
2024-02-27 17:57:44 +01:00
parent 596d84720b
commit 1664f86179
6 changed files with 399 additions and 0 deletions

45
src/error.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef NEER_ERROR_H
#define NEER_ERROR_H
#include <stdexcept>
#include <string>
#include <memory>
#define ERR(fmt,...) Error(nerr::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
namespace nerr
{
template <typename... Args>
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_t>(size_s);
std::unique_ptr<char[]> 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

10
src/nerr.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef NEER_H
#define NEER_H
#include <string>
#include <functional>
#include "error.h"
#include "option.h"
#include "result.h"
#endif

92
src/option.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef NEER_OPTION_H
#define NEER_OPTION_H
#define None(T) (nerr::Option<T>())
#define Some(v) (nerr::Option(v))
namespace nerr
{
template <typename T, typename E> class Result;
template <typename T>
class Option
{
public:
Option(T obj) : m_some(obj), m_notnull(true){};
Option() : m_notnull(false){};
Option<T>& operator=(const T& value) {insert(value); return *this;};
inline friend bool operator==(const Option<T>& l, const Option<T>& 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 <typename E>
inline Result<T, E> ok_or(E err)
{
if(m_notnull)
{
return Result<T, E>(m_some);
}
return Result<T, E>(err);
}
template<typename U>
inline Option<U> map(const std::function<U(T)>& fn)
{
if(is_some())
{
return fn(m_some);
}
return Option<U>();
}
template<typename U>
inline U map_or(U defv, const std::function<U(T)>& fn)
{
if(is_some())
{
return fn(m_some);
}
return defv;
}
private:
T m_some;
bool m_notnull;
};
}
#endif

82
src/result.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef NEER_RESULT_H
#define NEER_RESULT_H
//#define Ok(v) (nerr::Result(v))
//#define Err(e) (nerr::Result(e))
namespace nerr
{
//template <typename T> class Option;
template <typename T, typename E>
class Result
{
public:
Result(T obj) : m_result(obj) {};
Result(E err) { m_error.insert(err); };
Result(){};
inline Result<T,E>& operator=(const T& value) {m_result = value; m_error = None(E); return *this;};
inline Result<T,E>& 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<typename U>
inline Result<U,E> map(const std::function<U(T)>& fn)
{
if(is_ok())
{
return fn(m_result);
}
return m_error.unwrap();
}
template<typename E1>
inline Result<T,E1> map_err(const std::function<E1(E)>& fn)
{
if(!is_ok())
{
return fn(m_error.unwrap());
}
return m_result;
}
template<typename U>
inline U map_or(U defv, const std::function<U(T)>& fn)
{
if(is_ok())
{
return fn(m_result);
}
return defv;
}
Option<E> err() { return m_error; }
Option<T> ok() { return is_ok()?Option<T>(m_result): Option<T>(); }
private:
T m_result;
Option<E> m_error;
};
}
#endif