forked from I2P_Developers/i2p.i2p
A functional programming "library" (some headers with some magic love found in scala)
This commit is contained in:
264
launchers/macosx/obj-cpp/include/neither/either.hpp
Normal file
264
launchers/macosx/obj-cpp/include/neither/either.hpp
Normal file
@@ -0,0 +1,264 @@
|
||||
#ifndef NEITHER_EITHER_HPP
|
||||
#define NEITHER_EITHER_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "traits.hpp"
|
||||
#include "maybe.hpp"
|
||||
|
||||
#include "traits.hpp"
|
||||
#include "maybe.hpp"
|
||||
|
||||
namespace neither {
|
||||
|
||||
template<class T>
|
||||
constexpr T max(T x, T y) {
|
||||
return x>y ? x : y;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct Left {
|
||||
T value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr Left<T> left(T const& x) {
|
||||
return {x};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Left<T> left(T&& x) {
|
||||
return { std::move(x) };
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct Right {
|
||||
T value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr Right<T> right(T const& x) {
|
||||
return {x};
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
Right<T> right(T&& x) {
|
||||
return { std::move(x) };
|
||||
}
|
||||
|
||||
template<class L, class R>
|
||||
struct Either {
|
||||
|
||||
union {
|
||||
L leftValue;
|
||||
R rightValue;
|
||||
};
|
||||
|
||||
bool const isLeft = 0;
|
||||
|
||||
constexpr Either( Left<L> const& l )
|
||||
: leftValue{l.value}
|
||||
, isLeft(1)
|
||||
{}
|
||||
|
||||
constexpr Either( Right<R> const& r )
|
||||
: rightValue{r.value}
|
||||
, isLeft(0)
|
||||
{}
|
||||
|
||||
Either(Left<L> && l )
|
||||
: leftValue{std::move(l.value)}
|
||||
, isLeft(1)
|
||||
{}
|
||||
|
||||
Either( Right<R> && r )
|
||||
: rightValue{std::move(r.value)}
|
||||
, isLeft(0)
|
||||
{}
|
||||
|
||||
constexpr Either( Either<L, R> const& e )
|
||||
: isLeft(e.isLeft) {
|
||||
if (isLeft) {
|
||||
new (&leftValue)L(e.leftValue);
|
||||
} else {
|
||||
new (&rightValue)R(e.rightValue);
|
||||
}
|
||||
}
|
||||
|
||||
Either( Either<L, R>&& e )
|
||||
: isLeft(e.isLeft) {
|
||||
if (isLeft) {
|
||||
new (&leftValue)L(std::move(e.leftValue));
|
||||
} else {
|
||||
new (&rightValue)R(std::move(e.rightValue));
|
||||
}
|
||||
}
|
||||
|
||||
~Either() {
|
||||
if (isLeft) {
|
||||
leftValue.~L();
|
||||
} else {
|
||||
rightValue.~R();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto left() const -> Maybe<L> {
|
||||
return isLeft ?
|
||||
maybe(leftValue) :
|
||||
maybe();
|
||||
}
|
||||
|
||||
constexpr auto right() const -> Maybe<R> {
|
||||
return isLeft ?
|
||||
maybe() :
|
||||
maybe(rightValue);
|
||||
}
|
||||
|
||||
static constexpr auto leftOf( L const& l ) {
|
||||
return Either<L, R>{ neither::left(l) };
|
||||
}
|
||||
|
||||
static constexpr auto rightOf( R const& r ) {
|
||||
return Either<L, R>{ neither::right(r) };
|
||||
}
|
||||
|
||||
static constexpr auto leftOf( L && l ) {
|
||||
return Either<L, R>{ neither::left(std::move(l)) };
|
||||
}
|
||||
|
||||
static constexpr auto rightOf( R && r ) {
|
||||
return Either<L, R>{ neither::right(std::move(r)) };
|
||||
}
|
||||
|
||||
template<
|
||||
class L2 = L,
|
||||
class R2 = R>
|
||||
constexpr auto join() const
|
||||
-> decltype(
|
||||
isCopyable((L2)leftValue, (R2)rightValue),
|
||||
std::declval<std::common_type_t<L2, R2>>()
|
||||
) {
|
||||
return isLeft ? leftValue : rightValue;
|
||||
}
|
||||
|
||||
template<
|
||||
class L2 = L,
|
||||
class R2 = R>
|
||||
auto join()&&
|
||||
-> std::common_type_t<L2, R2> {
|
||||
return isLeft ? std::move(leftValue) : std::move(rightValue);
|
||||
}
|
||||
|
||||
template<class LeftF, class RightF>
|
||||
constexpr auto join(LeftF const& leftCase, RightF const& rightCase) const
|
||||
-> decltype( isLeft? leftCase( leftValue ) : rightCase( rightValue ) ) {
|
||||
return isLeft ? leftCase( leftValue ) : rightCase( rightValue );
|
||||
}
|
||||
|
||||
template<class F, class L2=L, class R2=R>
|
||||
constexpr auto leftMap(F const& leftCase) const&
|
||||
-> Either<decltype(leftCase( isCopyable((L2)leftValue, (R2)rightValue) )), R2> {
|
||||
using NextEither = Either<decltype(leftCase(leftValue)), R2>;
|
||||
return isLeft ?
|
||||
NextEither::leftOf( leftCase( leftValue ) ) :
|
||||
NextEither::rightOf( rightValue );
|
||||
}
|
||||
|
||||
template<class F, class L2=L, class R2=R>
|
||||
auto leftMap(F const& leftCase)&& -> Either<decltype(leftCase(std::move(leftValue))), R2> {
|
||||
using NextEither = Either<decltype(leftCase(std::move(leftValue))), R2>;
|
||||
return isLeft ?
|
||||
NextEither::leftOf(leftCase(std::move(leftValue))) :
|
||||
NextEither::rightOf( std::move(rightValue) );
|
||||
}
|
||||
|
||||
template<class F, class L2=L, class R2=R>
|
||||
constexpr auto rightMap(F const& rightCase) const& -> Either<L, decltype(rightCase(isCopyable((R2)rightValue, (L2)leftValue)))> {
|
||||
using NextEither = Either<L, decltype(rightCase(rightValue))>;
|
||||
return isLeft ?
|
||||
NextEither::leftOf( leftValue ) :
|
||||
NextEither::rightOf( rightCase( rightValue ) );
|
||||
}
|
||||
|
||||
template<class F, class L2=L, class R2=R>
|
||||
auto rightMap(F const& rightCase)&& -> Either<L2, decltype(rightCase(std::move((R2)rightValue)))> {
|
||||
using NextEither = Either<L, decltype(rightCase(std::move(rightValue)))>;
|
||||
return isLeft ?
|
||||
NextEither::leftOf( std::move(leftValue) ) :
|
||||
NextEither::rightOf( rightCase( std::move(rightValue) ) );
|
||||
}
|
||||
|
||||
template<class LeftCase, class L2=L, class R2=R>
|
||||
constexpr auto leftFlatMap(LeftCase const& leftCase) const&
|
||||
-> decltype( ensureEitherRight(leftCase(isCopyable((L2)leftValue)), isCopyable((R2)rightValue))) {
|
||||
using NextEither = decltype(leftCase(leftValue));
|
||||
|
||||
if (!*this) {
|
||||
return leftCase( leftValue );
|
||||
}
|
||||
|
||||
return NextEither::rightOf(rightValue);
|
||||
}
|
||||
|
||||
template<class RightCase, class L2 = L, class R2 = R>
|
||||
constexpr auto rightFlatMap(RightCase const& rightCase) const&
|
||||
-> decltype( ensureEitherLeft(rightCase(isCopyable((R2)rightValue)), isCopyable((L2)leftValue))) {
|
||||
using NextEither = decltype(rightCase(rightValue));
|
||||
|
||||
if (*this) {
|
||||
return rightCase( rightValue );
|
||||
}
|
||||
|
||||
return NextEither::leftOf(leftValue);
|
||||
}
|
||||
|
||||
template<class LeftCase, class L2 = L, class R2 = R>
|
||||
auto leftFlatMap(LeftCase const& leftCase)&&
|
||||
-> decltype( ensureEitherRight(leftCase(std::move(leftValue)), std::move(rightValue))) {
|
||||
using NextEither = decltype(leftCase(std::move(leftValue)));
|
||||
|
||||
if (!*this) {
|
||||
return leftCase( std::move(leftValue) );
|
||||
}
|
||||
|
||||
return NextEither::rightOf(std::move(rightValue));
|
||||
}
|
||||
|
||||
template<class RightCase, class L2=L, class R2=R>
|
||||
auto rightFlatMap(RightCase const& rightCase)&&
|
||||
-> decltype( ensureEitherLeft(rightCase(std::move(rightValue)), std::move(leftValue))) {
|
||||
using NextEither = decltype(rightCase(std::move(rightValue)));
|
||||
|
||||
if (*this) {
|
||||
return rightCase(std::move(rightValue));
|
||||
}
|
||||
|
||||
return NextEither::leftOf(std::move(leftValue));
|
||||
}
|
||||
|
||||
constexpr operator bool()const { return !isLeft; }
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
bool operator == (Either<L, R> const& a, Either<L, R> const& b) {
|
||||
if (a.isLeft) {
|
||||
if (b.isLeft) {
|
||||
return a.left() == b.left();
|
||||
}
|
||||
} else {
|
||||
if (!b.isLeft) {
|
||||
return a.right() == b.right();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename L, typename R>
|
||||
bool operator != (Either<L, R> const& a, Either<L, R> const& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
60
launchers/macosx/obj-cpp/include/neither/lift.hpp
Normal file
60
launchers/macosx/obj-cpp/include/neither/lift.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "either.hpp"
|
||||
|
||||
namespace neither {
|
||||
|
||||
template<class L, class R>
|
||||
constexpr bool hasValue(Either<L,R> const& e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
constexpr bool hasValue(Maybe<T> const& m) {
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr bool hasValue(T) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class L, class R>
|
||||
constexpr R unpack(Either<L, R> const& e) {
|
||||
return e.rightValue;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
constexpr T unpack(Maybe<T> const& m) {
|
||||
return m.value;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr T unpack(T const& x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
constexpr auto allTrue(bool x=true, bool y=true) {
|
||||
return x && y;
|
||||
}
|
||||
|
||||
|
||||
template<class X, class...Xs>
|
||||
auto allTrue(X x, Xs...xs) {
|
||||
return allTrue(x, allTrue(xs...));
|
||||
}
|
||||
|
||||
template<class F>
|
||||
auto lift(F const& f) {
|
||||
return [f](auto...x) -> decltype(maybe(f(unpack(x)...))) {
|
||||
if ( allTrue(hasValue(x)...) ) {
|
||||
return f(unpack(x)...);
|
||||
}
|
||||
|
||||
return maybe();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
117
launchers/macosx/obj-cpp/include/neither/maybe.hpp
Normal file
117
launchers/macosx/obj-cpp/include/neither/maybe.hpp
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifndef NEITHER_MAYBE_HPP
|
||||
#define NEITHER_MAYBE_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace neither {
|
||||
|
||||
template <class T> struct Maybe;
|
||||
|
||||
template <> struct Maybe<void> {};
|
||||
|
||||
template <class T> struct Maybe {
|
||||
|
||||
union {
|
||||
T value;
|
||||
};
|
||||
|
||||
bool const hasValue = 0;
|
||||
|
||||
constexpr Maybe() : hasValue{0} {}
|
||||
|
||||
constexpr Maybe(T const& value) : value{value}, hasValue{1} {}
|
||||
constexpr Maybe(T&& value) : value{std::move(value)}, hasValue{1} {}
|
||||
|
||||
constexpr Maybe(Maybe<void>) : hasValue{0} {}
|
||||
|
||||
constexpr Maybe(Maybe<T> const &o) : hasValue{o.hasValue} {
|
||||
if (o.hasValue) {
|
||||
new (&value)T(o.value);
|
||||
}
|
||||
}
|
||||
|
||||
~Maybe() {
|
||||
if (hasValue) {
|
||||
value.~T();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr T get(T defaultValue) {
|
||||
return hasValue ? value : defaultValue;
|
||||
}
|
||||
|
||||
constexpr T unsafeGet() {
|
||||
assert(hasValue && "unsafeGet must not be called on an empty Maybe");
|
||||
return value;
|
||||
}
|
||||
|
||||
template<class F>
|
||||
constexpr auto map(F const &f) const&
|
||||
-> Maybe<decltype(f(isCopyable(value)))> {
|
||||
using ReturnType = decltype(f(value));
|
||||
if (!hasValue) {
|
||||
return Maybe<ReturnType>();
|
||||
}
|
||||
return Maybe<ReturnType>(f(value));
|
||||
}
|
||||
|
||||
|
||||
template<class F>
|
||||
auto map(F const& f)&&
|
||||
-> Maybe<decltype(f(std::move(value)))> {
|
||||
using ReturnType = decltype(f(std::move(value)));
|
||||
if (!hasValue) {
|
||||
return Maybe<ReturnType>();
|
||||
}
|
||||
return Maybe<ReturnType>(f(std::move(value)));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
constexpr auto flatMap(F const& f) const&
|
||||
-> decltype(ensureMaybe(f(value))) {
|
||||
using ReturnType = decltype(f(value));
|
||||
if (!hasValue) {
|
||||
return ReturnType();
|
||||
}
|
||||
|
||||
return f(value);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
constexpr auto flatMap(F const& f)&&
|
||||
-> decltype(ensureMaybe(f(std::move(value)))) {
|
||||
using ReturnType = decltype(f(std::move(value)));
|
||||
if (!hasValue) {
|
||||
return ReturnType();
|
||||
}
|
||||
|
||||
return f(std::move(value));
|
||||
}
|
||||
|
||||
constexpr operator bool() const { return hasValue; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto maybe(T value) -> Maybe<T> { return {value}; }
|
||||
|
||||
template <typename T = void>
|
||||
auto maybe() -> Maybe<T> { return {}; }
|
||||
|
||||
template <typename T>
|
||||
bool operator == (Maybe<T> const& a, Maybe<T> const& b) {
|
||||
if (a.hasValue) {
|
||||
return b.hasValue && a.value == b.value;
|
||||
}
|
||||
return !b.hasValue;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator != (Maybe<T> const& a, Maybe<T> const& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
10
launchers/macosx/obj-cpp/include/neither/neither.hpp
Normal file
10
launchers/macosx/obj-cpp/include/neither/neither.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef NEITHER_NEITHER_HPP
|
||||
#define NEITHER_NEITHER_HPP
|
||||
|
||||
#include "either.hpp"
|
||||
#include "lift.hpp"
|
||||
#include "maybe.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "try.hpp"
|
||||
|
||||
#endif
|
20
launchers/macosx/obj-cpp/include/neither/try.hpp
Normal file
20
launchers/macosx/obj-cpp/include/neither/try.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef NEITHER_TRY_HPP
|
||||
#define NEITHER_TRY_HPP
|
||||
|
||||
#include <functional>
|
||||
#include "either.hpp"
|
||||
|
||||
namespace neither {
|
||||
|
||||
template <class E, class F, class... X>
|
||||
auto Try(F const &f, X &&... x)
|
||||
-> Either<E, decltype(f(std::forward<X>(x)...))> {
|
||||
try {
|
||||
return right(f(std::forward<X>(x)...));
|
||||
} catch (E const &e) {
|
||||
return left(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
1066
launchers/macosx/obj-cpp/include/optional.hpp
Normal file
1066
launchers/macosx/obj-cpp/include/optional.hpp
Normal file
File diff suppressed because it is too large
Load Diff
57
launchers/macosx/obj-cpp/include/traits.hpp
Normal file
57
launchers/macosx/obj-cpp/include/traits.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef NEITHER_TRAITS_HPP
|
||||
#define NEITHER_TRAITS_HPP
|
||||
|
||||
namespace neither {
|
||||
|
||||
template<class L, class R>
|
||||
struct Either;
|
||||
|
||||
template<class T>
|
||||
struct Maybe;
|
||||
|
||||
template<class L,class...Xs>
|
||||
auto isCopyable (L l, Xs...) -> L {
|
||||
return l;
|
||||
}
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEither ( Either<L,R> const& e) -> Either<L,R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEither ( Either<L,R> && e) -> Either<L,R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEitherRight ( Either<L,R> const& e, R) -> Either<L, R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEitherRight ( Either<L,R>&& e, R&&) -> Either<L, R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEitherLeft ( Either<L,R> const& e, L) -> Either<L, R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
template<class L, class R>
|
||||
auto ensureEitherLeft ( Either<L,R>&& e, L&& ) -> Either<L, R> {
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
auto ensureMaybe ( Maybe<T> const& e) -> Maybe<T> {
|
||||
return e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user