feat: imrpovement and add more methods to Option and Result
This commit is contained in:
parent
8a96704909
commit
47a2d0a64d
321
src/ro.h
321
src/ro.h
@ -4,13 +4,14 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#define None(T) (ro::Option<T>())
|
#define None(T) (ro::Option<T>())
|
||||||
#define Some(v) (ro::Option(v))
|
#define Some(v) (ro::Option(v))
|
||||||
#define ERR(fmt,...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
|
#define ERR(fmt, ...) Error(ro::sfmt("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__))
|
||||||
#define Err(e) (ro::Result(e))
|
// #define Err(e) (ro::Result(e))
|
||||||
#define Ok(v) (ro::Result(v))
|
// #define Ok(v) (ro::Result(v))
|
||||||
|
|
||||||
namespace ro
|
namespace ro
|
||||||
{
|
{
|
||||||
@ -33,20 +34,21 @@ namespace ro
|
|||||||
public:
|
public:
|
||||||
Error(const std::string &s) : runtime_error(s){};
|
Error(const std::string &s) : runtime_error(s){};
|
||||||
Error(const char *s) : runtime_error(s){};
|
Error(const char *s) : runtime_error(s){};
|
||||||
Error(): runtime_error(""){};
|
Error() : runtime_error(""){};
|
||||||
|
|
||||||
inline friend bool operator==(const Error& l, const Error& r)
|
inline friend bool operator==(const Error &l, const Error &r)
|
||||||
{
|
{
|
||||||
return std::string(l.what()) == std::string(r.what());
|
return std::string(l.what()) == std::string(r.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error operator+(const Error& other)
|
inline Error operator+(const Error &other)
|
||||||
{
|
{
|
||||||
return Error(std::string(this->what()) + "\n" + other.what());
|
return Error(std::string(this->what()) + "\n" + other.what());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename E> class Result;
|
template <typename T, typename E>
|
||||||
|
class Result;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Option
|
class Option
|
||||||
@ -56,38 +58,94 @@ namespace ro
|
|||||||
Option(T obj) : m_some(obj), m_notnull(true){};
|
Option(T obj) : m_some(obj), m_notnull(true){};
|
||||||
Option() : m_notnull(false){};
|
Option() : m_notnull(false){};
|
||||||
|
|
||||||
Option<T>& operator=(const T& value) {insert(value); return *this;};
|
Option<T> &operator=(const T &value)
|
||||||
inline friend bool operator==(const Option<T>& l, const Option<T>& r) {
|
{
|
||||||
if(!l.m_notnull && !r.m_notnull)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
if(l.m_notnull && r.m_notnull)
|
if (l.m_notnull && r.m_notnull)
|
||||||
{
|
{
|
||||||
return l.m_some == r.m_some;
|
return l.m_some == r.m_some;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool is_none(){return !m_notnull;};
|
inline friend Option<T> operator|(const Option<T> &l, const Option<T> &r)
|
||||||
inline bool is_some(){return m_notnull;};
|
|
||||||
inline T& unwrap()
|
|
||||||
{
|
{
|
||||||
if(m_notnull)
|
if (l.is_some())
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline friend Option<U> operator&(const Option<T> &l, const Option<U> &r)
|
||||||
|
{
|
||||||
|
if (l.is_some())
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return Option<U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline friend Option<T> operator^(const Option<T> &l, const Option<T> &r)
|
||||||
|
{
|
||||||
|
if (l.is_some() != r.is_some())
|
||||||
|
{
|
||||||
|
if (l.is_some())
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return Option<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_none() const { return !m_notnull; };
|
||||||
|
inline bool is_some() const { return m_notnull; };
|
||||||
|
inline const T &unwrap() const
|
||||||
|
{
|
||||||
|
if (m_notnull)
|
||||||
{
|
{
|
||||||
return m_some;
|
return m_some;
|
||||||
}
|
}
|
||||||
throw Error("Object is None");
|
throw Error("Object is None");
|
||||||
}
|
}
|
||||||
inline T& get_or_insert(T value)
|
|
||||||
|
inline const T &unwrap_or(const T &alt) const
|
||||||
{
|
{
|
||||||
if(!m_notnull)
|
if (m_notnull)
|
||||||
|
{
|
||||||
|
return m_some;
|
||||||
|
}
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T unwrap_or_else(const std::function<T()> &fn) const
|
||||||
|
{
|
||||||
|
if (m_notnull)
|
||||||
|
{
|
||||||
|
return m_some;
|
||||||
|
}
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T &get_or_insert(const T &value)
|
||||||
|
{
|
||||||
|
if (!m_notnull)
|
||||||
{
|
{
|
||||||
insert(value);
|
insert(value);
|
||||||
}
|
}
|
||||||
return m_some;
|
return m_some;
|
||||||
}
|
}
|
||||||
inline T& insert(T value)
|
inline const T &insert(const T &value)
|
||||||
{
|
{
|
||||||
m_some = value;
|
m_some = value;
|
||||||
m_notnull = true;
|
m_notnull = true;
|
||||||
@ -95,35 +153,92 @@ namespace ro
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
inline Result<T, E> ok_or(E err)
|
inline Result<T, E> ok_or(const E &err)
|
||||||
{
|
{
|
||||||
if(m_notnull)
|
if (m_notnull)
|
||||||
{
|
{
|
||||||
return Result<T, E>(m_some);
|
return Result<T, E>(m_some);
|
||||||
}
|
}
|
||||||
return Result<T, E>(err);
|
return Result<T, E>(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template <typename U>
|
||||||
inline Option<U> map(const std::function<U(T)>& fn)
|
inline Option<U> and_then(const std::function<Option<U>(const T &)> &fn)
|
||||||
{
|
{
|
||||||
if(is_some())
|
if (m_notnull)
|
||||||
{
|
{
|
||||||
return fn(m_some);
|
return fn(m_some);
|
||||||
}
|
}
|
||||||
return Option<U>();
|
return Option<U>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
inline Option<T> or_else(const std::function<Option<T>()> &fn)
|
||||||
inline U map_or(U defv, const std::function<U(T)>& fn)
|
|
||||||
{
|
{
|
||||||
if(is_some())
|
if (m_notnull)
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline Option<U> map(const std::function<U(const T &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
|
{
|
||||||
|
return fn(m_some);
|
||||||
|
}
|
||||||
|
return Option<U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline U map_or(const U &defv, const std::function<U(const T &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_some())
|
||||||
{
|
{
|
||||||
return fn(m_some);
|
return fn(m_some);
|
||||||
}
|
}
|
||||||
return defv;
|
return defv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Option<T> filter(const std::function<bool(const T &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_some() && fn(m_some))
|
||||||
|
{
|
||||||
|
return Option<T>(m_some);
|
||||||
|
}
|
||||||
|
return Option<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Option<T> take()
|
||||||
|
{
|
||||||
|
if (m_notnull)
|
||||||
|
{
|
||||||
|
m_notnull = false;
|
||||||
|
return Option<T>(m_some);
|
||||||
|
}
|
||||||
|
return Option<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Option<T> take_if(const std::function<bool(const T &)> &fn)
|
||||||
|
{
|
||||||
|
if (m_notnull && fn(m_some))
|
||||||
|
{
|
||||||
|
return take();
|
||||||
|
}
|
||||||
|
return Option<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline Option<std::tuple<T, U>> zip(const Option<U> &other)
|
||||||
|
{
|
||||||
|
if (m_notnull && other.is_some())
|
||||||
|
{
|
||||||
|
return Option<std::tuple<T, U>>(std::tuple<T, U>(m_some, other.unwrap()));
|
||||||
|
}
|
||||||
|
return Option<std::tuple<T, U>>();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_some;
|
T m_some;
|
||||||
bool m_notnull;
|
bool m_notnull;
|
||||||
@ -134,66 +249,172 @@ namespace ro
|
|||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Result(T obj) : m_result(obj) {};
|
Result(T obj) : m_result(obj){};
|
||||||
Result(E err) { m_error.insert(err); };
|
Result(E err) { m_error.insert(err); };
|
||||||
Result(){};
|
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 Result<T, E> &operator=(const T &value)
|
||||||
inline bool is_err(){return m_error.is_some();};
|
|
||||||
|
|
||||||
inline T& unwrap()
|
|
||||||
{
|
{
|
||||||
if(is_ok())
|
m_result = value;
|
||||||
|
m_error = None(E);
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
inline Result<T, E> &operator=(const E &err)
|
||||||
|
{
|
||||||
|
m_error.insert(err);
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline friend bool operator==(const Result<T, E> &l, const Result<T, E> &r)
|
||||||
|
{
|
||||||
|
if (l.is_ok() != r.is_ok())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (l.is_ok())
|
||||||
|
{
|
||||||
|
return l.m_result == r.m_result;
|
||||||
|
}
|
||||||
|
return l.m_error == r.m_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline friend bool operator==(const Result<T, E> &l, const E &r)
|
||||||
|
{
|
||||||
|
if (l.is_ok())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return l.m_error == r;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline friend bool operator==(const Result<T, E> &l, const T &r)
|
||||||
|
{
|
||||||
|
if (l.is_err())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return l.m_result == r;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline friend Result<T, E> operator|(const Result<T, E> &l, const Result<T, E> &r)
|
||||||
|
{
|
||||||
|
if (l.is_ok())
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
inline friend Result<U, E> operator&(const Result<T, E> &l, const Result<U, E> &r)
|
||||||
|
{
|
||||||
|
if (l.is_ok())
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return Result<U, E>(l.m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_ok() const { return m_error.is_none(); };
|
||||||
|
inline bool is_err() const { return m_error.is_some(); };
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline Result<T, F> or_else(const std::function<Result<T, F>(const E &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return Result<T, F>(m_result);
|
||||||
|
}
|
||||||
|
return fn(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T &unwrap() const
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
{
|
{
|
||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
throw m_error.unwrap();
|
throw m_error.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T& expect(E e)
|
inline const E &unwrap_err() const
|
||||||
{
|
{
|
||||||
if(is_ok())
|
if (is_err())
|
||||||
|
{
|
||||||
|
return m_error.unwrap();
|
||||||
|
}
|
||||||
|
throw m_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T &expect(E e) const
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
{
|
{
|
||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
throw e + m_error.unwrap();
|
throw e + m_error.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template <typename U>
|
||||||
inline Result<U,E> map(const std::function<U(T)>& fn)
|
inline Result<U, E> map(const std::function<U(const T &)> &fn)
|
||||||
{
|
{
|
||||||
if(is_ok())
|
if (is_ok())
|
||||||
{
|
{
|
||||||
return fn(m_result);
|
return fn(m_result);
|
||||||
}
|
}
|
||||||
return m_error.unwrap();
|
return m_error.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename E1>
|
template <typename E1>
|
||||||
inline Result<T,E1> map_err(const std::function<E1(E)>& fn)
|
inline Result<T, E1> map_err(const std::function<E1(const E &)> &fn)
|
||||||
{
|
{
|
||||||
if(!is_ok())
|
if (!is_ok())
|
||||||
{
|
{
|
||||||
return fn(m_error.unwrap());
|
return fn(m_error.unwrap());
|
||||||
}
|
}
|
||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template <typename U>
|
||||||
inline U map_or(U defv, const std::function<U(T)>& fn)
|
inline U map_or(const U &defv, const std::function<U(const T &)> &fn)
|
||||||
{
|
{
|
||||||
if(is_ok())
|
if (is_ok())
|
||||||
{
|
{
|
||||||
return fn(m_result);
|
return fn(m_result);
|
||||||
}
|
}
|
||||||
return defv;
|
return defv;
|
||||||
}
|
}
|
||||||
|
|
||||||
Option<E> err() { return m_error; }
|
template <typename U>
|
||||||
Option<T> ok() { return is_ok()?Option<T>(m_result): Option<T>(); }
|
inline Result<U, E> and_then(const std::function<Result<U, E>(const T &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return fn(m_result);
|
||||||
|
}
|
||||||
|
return Result<U, E>(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T &unwrap_or(const T &alt) const
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T unwrap_or_else(const std::function<T(const E &)> &fn)
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
return fn(m_error.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Option<E> &err() const { return m_error; }
|
||||||
|
inline Option<T> ok() const { return is_ok() ? Option<T>(m_result) : Option<T>(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_result;
|
T m_result;
|
||||||
|
246
test/test.cpp
246
test/test.cpp
@ -2,12 +2,19 @@
|
|||||||
#include "../src/ro.h"
|
#include "../src/ro.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ro;
|
using namespace ro;
|
||||||
|
|
||||||
|
struct Stat{
|
||||||
|
int passed;
|
||||||
|
int total;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Stat g_stat = {0,0};
|
||||||
|
|
||||||
#define assert(v,fmt,...) if(!(v)) { \
|
#define assert(v,fmt,...) if(!(v)) { \
|
||||||
throw Error(ro::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \
|
throw Error(ro::sfmt("ASSERT ERROR %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)); \
|
||||||
}
|
}
|
||||||
@ -19,12 +26,14 @@ void test(const char* desc, const std::function<void()>& lambda)
|
|||||||
try {
|
try {
|
||||||
lambda();
|
lambda();
|
||||||
std::cout << "OK" << std::endl;
|
std::cout << "OK" << std::endl;
|
||||||
|
g_stat.passed++;
|
||||||
}
|
}
|
||||||
catch(ro::Error e)
|
catch(ro::Error e)
|
||||||
{
|
{
|
||||||
std::cout << "FAILED" << std::endl;
|
std::cout << "FAILED" << std::endl;
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
g_stat.total++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char const *argv[])
|
int main(int argc, char const *argv[])
|
||||||
@ -52,6 +61,14 @@ int main(int argc, char const *argv[])
|
|||||||
assert(ret.unwrap() == "abc", "Data mistmatch");
|
assert(ret.unwrap() == "abc", "Data mistmatch");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("OPtion get_or_insert", [](){
|
||||||
|
auto x = None(int);
|
||||||
|
int y = x.get_or_insert(5);
|
||||||
|
assert(y == 5, "Unexpected value");
|
||||||
|
|
||||||
|
assert(x == 5, "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
test("Option map", [](){
|
test("Option map", [](){
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return "Hello";
|
return "Hello";
|
||||||
@ -67,7 +84,7 @@ int main(int argc, char const *argv[])
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test("Option map or", [](){
|
test("Option map_or", [](){
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return ++x;
|
return ++x;
|
||||||
};
|
};
|
||||||
@ -81,6 +98,140 @@ int main(int argc, char const *argv[])
|
|||||||
assert(v == 3, "Value mismatch %d",v);
|
assert(v == 3, "Value mismatch %d",v);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Option filter", [](){
|
||||||
|
auto fn = [](int n) {
|
||||||
|
return n % 2 == 0;
|
||||||
|
};
|
||||||
|
//Option<int> opt = None(int).filter(fn);
|
||||||
|
assert(None(int).filter(fn).is_none(), "Filter value shall be None");
|
||||||
|
assert(Some(3).filter(fn).is_none(), "Filter value shall be None");
|
||||||
|
assert(Some(4).filter(fn).is_some(), "Filter value shall not be None");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option OR", [](){
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = None(int);
|
||||||
|
assert((x | y) == Some(2), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x | y) == Some(100), "Unexpected value");
|
||||||
|
|
||||||
|
x = Some(2);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x|y) == Some(2), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = None(int);
|
||||||
|
assert((x | y) == None(int), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option AND", [](){
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = None(int);
|
||||||
|
assert((x & y) == None(int), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x & y) == None(int), "Unexpected value");
|
||||||
|
|
||||||
|
x = Some(2);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x&y) == Some(100), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = None(int);
|
||||||
|
assert((x & y) == None(int), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option XOR", [](){
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = None(int);
|
||||||
|
assert((x ^ y) == Some(2), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x ^ y) == Some(100), "Unexpected value");
|
||||||
|
|
||||||
|
x = Some(2);
|
||||||
|
y = Some(100);
|
||||||
|
assert((x^y) == None(int), "Unexpected value");
|
||||||
|
|
||||||
|
x = None(int);
|
||||||
|
y = None(int);
|
||||||
|
assert((x ^ y) == None(int), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option or_else", [](){
|
||||||
|
auto nobody = [](){return None(int);};
|
||||||
|
auto vikings = [](){return Some(100);};
|
||||||
|
|
||||||
|
assert(None(int).or_else(vikings) == Some(100), "Unexpected value");
|
||||||
|
assert(None(int).or_else(nobody) == None(int), "Unexpected value");
|
||||||
|
|
||||||
|
assert(Some(2).or_else(vikings) == Some(2), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option and_then", [](){
|
||||||
|
auto fn = [](int x){return string("Hello");};
|
||||||
|
|
||||||
|
assert(Some(1).and_then<string>(fn) == Some(string("Hello")), "Unexpected value");
|
||||||
|
assert(None(int).and_then<string>(fn) == None(string), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option take", [](){
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = x.take();
|
||||||
|
|
||||||
|
assert(x == None(int), "Unexpected value");
|
||||||
|
assert(y == Some(2), "Unexpected value");
|
||||||
|
|
||||||
|
auto z = None(int);
|
||||||
|
y = z.take();
|
||||||
|
assert(x == None(int), "Unexpected value");
|
||||||
|
assert(y == None(int), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option take_if", [](){
|
||||||
|
auto fn = [](int n) {
|
||||||
|
return n % 2 == 0;
|
||||||
|
};
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = x.take_if(fn);
|
||||||
|
|
||||||
|
assert(x == None(int), "Unexpected value");
|
||||||
|
assert(y == Some(2), "Unexpected value");
|
||||||
|
|
||||||
|
auto z = Some(3);
|
||||||
|
y = z.take_if(fn);
|
||||||
|
assert(z == Some(3), "Unexpected value");
|
||||||
|
assert(y == None(int), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option unwrap_or", [](){
|
||||||
|
assert(Some(2).unwrap_or(4) == 2, "Unexpected value");
|
||||||
|
assert(None(int).unwrap_or(4) == 4, "Unexpected value");
|
||||||
|
|
||||||
|
assert(None(Error).unwrap_or(Error("Hello")) == Error("Hello"), "Unexpected value");
|
||||||
|
|
||||||
|
});
|
||||||
|
test("Option unwrap_or_else", [](){
|
||||||
|
assert(Some(2).unwrap_or_else([](){ return 4; }) == 2, "Unexpected value");
|
||||||
|
assert(None(int).unwrap_or_else([](){ return 4; }) == 4, "Unexpected value");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Option zip", [](){
|
||||||
|
auto x = Some(2);
|
||||||
|
auto y = Some(string("Hello"));
|
||||||
|
auto z = None(int);
|
||||||
|
|
||||||
|
assert(x.zip(y).unwrap() == std::tuple(2, string("Hello")), "Unexpected value");
|
||||||
|
|
||||||
|
assert(x.zip(z).is_none(), "Unexpected value");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
test("Test Result", []{
|
test("Test Result", []{
|
||||||
Result<string, Error> ret = ERR("Error");
|
Result<string, Error> ret = ERR("Error");
|
||||||
assert(ret.is_err(), "Object should containe error object");
|
assert(ret.is_err(), "Object should containe error object");
|
||||||
@ -132,7 +283,7 @@ int main(int argc, char const *argv[])
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test("Result map err", [](){
|
test("Result map_err", [](){
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return "Hello";
|
return "Hello";
|
||||||
};
|
};
|
||||||
@ -145,7 +296,7 @@ int main(int argc, char const *argv[])
|
|||||||
assert(ret1.err().unwrap() == "Hello", "Value mistmatch");
|
assert(ret1.err().unwrap() == "Hello", "Value mistmatch");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Result map or", [](){
|
test("Result map_or", [](){
|
||||||
auto fn = [](int x){
|
auto fn = [](int x){
|
||||||
return ++x;
|
return ++x;
|
||||||
};
|
};
|
||||||
@ -159,4 +310,91 @@ int main(int argc, char const *argv[])
|
|||||||
assert(v == 3, "Value mismatch %d",v);
|
assert(v == 3, "Value mismatch %d",v);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Result AND", [](){
|
||||||
|
Result<int, Error> x = 2;
|
||||||
|
Result<int, Error> y = Error("Hello");
|
||||||
|
assert((x&y) == Error("Hello"), "Value mismatch");
|
||||||
|
|
||||||
|
x = Error("Error1");
|
||||||
|
y = 10;
|
||||||
|
assert((x&y) == Error("Error1"), "Value mismatch");
|
||||||
|
|
||||||
|
x = Error("Error1");
|
||||||
|
y = Error("Error2");
|
||||||
|
assert((x&y) == Error("Error1"), "Value mismatch");
|
||||||
|
|
||||||
|
x = 1;
|
||||||
|
y = 10;
|
||||||
|
assert((x&y) == 10, "Value mismatch");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result OR", [](){
|
||||||
|
Result<int, Error> x = 2;
|
||||||
|
Result<int, Error> y = Error("Hello");
|
||||||
|
assert((x|y) == 2, "Value mismatch");
|
||||||
|
|
||||||
|
x = Error("Error1");
|
||||||
|
y = 10;
|
||||||
|
assert((x|y) == 10, "Value mismatch");
|
||||||
|
|
||||||
|
x = Error("Error1");
|
||||||
|
y = Error("Error2");
|
||||||
|
assert((x|y) == Error("Error2"), "Value mismatch");
|
||||||
|
|
||||||
|
x = 1;
|
||||||
|
y = 10;
|
||||||
|
assert((x|y) == 1, "Value mismatch");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result and_then", [](){
|
||||||
|
auto fn = [](int x){return string("Hello");};
|
||||||
|
|
||||||
|
Result<int, Error> x = 2;
|
||||||
|
auto test = Result<string,Error>(string("Hello"));
|
||||||
|
assert(x.and_then<string>(fn) == string("Hello"), "Unexpected value");
|
||||||
|
x = Error("Error");
|
||||||
|
assert(x.and_then<string>(fn) == Error("Error"), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result or_else", [](){
|
||||||
|
auto sq = [](int x){return x*x;};
|
||||||
|
auto err = [](int x){return x;};
|
||||||
|
Result<double, int> x(2.0);
|
||||||
|
auto ret = x.or_else<int>(sq).or_else<int>(sq);
|
||||||
|
assert(ret == 2.0, "Unexpected value");
|
||||||
|
ret = x.or_else<int>(err).or_else<int>(sq);
|
||||||
|
assert(ret == 2.0, "Unexpected value");
|
||||||
|
|
||||||
|
x = 3;
|
||||||
|
ret = x.or_else<int>(sq).or_else<int>(err);
|
||||||
|
assert(ret == 9, "Unexpected value");
|
||||||
|
|
||||||
|
ret = x.or_else<int>(err).or_else<int>(err);
|
||||||
|
assert(ret == 3, "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result unwrap_err", [](){
|
||||||
|
Result<int, Error> x = Error("Hello");
|
||||||
|
assert(x.unwrap_err() == Error("Hello"), "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result unwrap_or", [](){
|
||||||
|
Result<int, Error> x = 2;
|
||||||
|
assert(x.unwrap_or(10) == 2, "Unexpected value");
|
||||||
|
|
||||||
|
x = ERR("Error");
|
||||||
|
assert(x.unwrap_or(10) == 10, "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Result unwrap_or_else", [](){
|
||||||
|
auto fn = [](const Error& x){return strlen(x.what());};
|
||||||
|
Result<int, Error> x = 2;
|
||||||
|
assert(x.unwrap_or_else(fn) == 2, "Unexpected value");
|
||||||
|
|
||||||
|
x = Error("HELLO");
|
||||||
|
assert(x.unwrap_or_else(fn) == 5, "Unexpected value");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
cout << "REPORT: " << g_stat.passed << " tests passed / " << g_stat.total << " tests." << endl;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user