Skip to content

Instantly share code, notes, and snippets.

@whanhee
Created September 18, 2013 05:18
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save whanhee/6604848 to your computer and use it in GitHub Desktop.
Type class: foldable. For explanation, see: http://functionalcpp.wordpress.com/2013/09/18/type-class-foldable/
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <deque>
#include <list>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
namespace fc
{
template <class C>
struct container_traits
{
// Type value_type
// void add_element(C&,T)
// void concat(C&,C)
// Type rebind<U>
};
template<class C>
struct sequence_container_traits;
template<template<class,class> class C, class T, class A>
struct sequence_container_traits<C<T,A>>
{
using value_type = T;
static void add_element(C<T,A>& c, const T& t)
{
c.push_back(t);
}
static void concat(C<T,A>& lhs, const C<T,A>& rhs)
{
lhs.insert(lhs.end(),rhs.begin(),rhs.end());
}
template<class U>
using rebind = C<U,typename A::template rebind<U>::other>;
};
template<class... Args>
struct container_traits<std::deque<Args...>> : public sequence_container_traits<std::deque<Args...>>
{};
template<class... Args>
struct container_traits<std::list<Args...>> : public sequence_container_traits<std::list<Args...>>
{};
template<class... Args>
struct container_traits<std::vector<Args...>> : public sequence_container_traits<std::vector<Args...>>
{};
template<class C>
struct associative_container_traits;
template<template<class,class,class> class C, class T, template<class> class O, class A>
struct associative_container_traits<C<T,O<T>,A>>
{
using value_type = T;
static void add_element(C<T,O<T>,A>& c, const T& t)
{
c.insert(t);
}
static void concat(C<T,O<T>,A>& lhs, const C<T,O<T>,A>& rhs)
{
lhs.insert(rhs.begin(),rhs.end());
}
template<class U>
using rebind = C<U,O<U>,typename A::template rebind<U>::other>;
};
template<class... Args>
struct container_traits<std::multiset<Args...>> : public associative_container_traits<std::multiset<Args...>>
{};
template<class... Args>
struct container_traits<std::set<Args...>> : public associative_container_traits<std::set<Args...>>
{};
template<class C>
struct hash_container_traits;
template<template<class,class,class,class> class C, class T, template<class> class H, template<class> class O, class A>
struct hash_container_traits<C<T,H<T>,O<T>,A>>
{
using value_type = T;
static void add_element(C<T,H<T>,O<T>,A>& c, const T& t)
{
c.insert(t);
}
static void concat(C<T,H<T>,O<T>,A>& lhs, const C<T,H<T>,O<T>,A>& rhs)
{
lhs.insert(rhs.begin(),rhs.end());
}
template<class U>
using rebind = C<U,H<U>,O<U>,typename A::template rebind<U>::other>;
};
template<class... Args>
struct container_traits<std::unordered_multiset<Args...>> : public hash_container_traits<std::unordered_multiset<Args...>>
{};
template<class... Args>
struct container_traits<std::unordered_set<Args...>> : public hash_container_traits<std::unordered_set<Args...>>
{};
// basic_string
template<class C>
struct string_container_traits;
template<template<class,class,class> class C, class T, template<class> class K, class A>
struct string_container_traits<C<T,K<T>,A>>
{
using value_type = T;
static void add_element(C<T,K<T>,A>& c, const T& t)
{
c.push_back(t);
}
static void concat(C<T,K<T>,A>& lhs, const C<T,K<T>,A>& rhs)
{
lhs+=rhs;
}
template<class U>
using rebind = C<U,K<U>,typename A::template rebind<U>::other>;
};
template<class... Args>
struct container_traits<std::basic_string<Args...>> : public string_container_traits<std::basic_string<Args...>>
{};
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <type_traits>
#include <utility>
namespace fc
{
template<
class F, class... Args,
class = typename std::enable_if<!std::is_member_function_pointer<F>::value>::type,
class = typename std::enable_if<!std::is_member_object_pointer<F>::value>::type
>
auto eval(F&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...))
{
return f(std::forward<Args>(args)...);
}
template<class R, class C, class... Args>
auto eval(R(C::*f)() const, const C& c, Args&&... args) -> R
{
return (c.*f)(std::forward<Args>(args)...);
}
template<class R, class C, class... Args>
auto eval(R(C::*f)() const, C& c, Args&&... args) -> R
{
return (c.*f)(std::forward<Args>(args)...);
}
template<class R, class C, class... Args>
auto eval(R(C::*f)(), C& c, Args&&... args) -> R
{
return (c.*f)(std::forward<Args>(args)...);
}
template<class R, class C>
auto eval(R(C::*m), const C& c) -> const R&
{
return c.*m;
}
template<class R, class C>
auto eval(R(C::*m), C& c) -> R&
{
return c.*m;
}
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <memory>
#include "container_traits.h"
#include "eval.h"
#include "monoid.h"
namespace fc
{
template<class T>
struct foldable
{
// Type value_type
// A fold(foldable<A>) requires monoid<A>
// B lfold(B(B,A),B,foldable<A>)
static constexpr bool is_instance = false;
};
// Convenience functions
template<class T>
auto fold(const T& in)
{
return foldable<T>::fold(in);
}
template<class F, class B, class T>
auto lfold(F&& f, B&& b, const T& in)
{
return foldable<T>::lfold(std::forward<F>(f),std::forward<B>(b),in);
}
// shared_ptr instance
template<class T>
struct foldable<std::shared_ptr<T>>
{
// Type value_type
using value_type = T;
// A fold(foldable<A>) requires monoid<A>
template<
class T_,
class = typename std::enable_if<std::is_same<T,T_>::value>,
class = typename std::enable_if<monoid<T>::is_instance>::type>
static auto fold(const T_& in)
{
if (in)
return monoid<T>::append(monoid<T>::empty(),*in);
return monoid<T>::empty();
}
// B lfold(B(B,A),B,foldable<A>)
template<class F, class B>
static auto lfold(F&& f, B b, const std::shared_ptr<T>& in) -> B
{
if (in)
b = eval(f,b,*in);
return b;
}
static constexpr bool is_instance = true;
};
// container instances
template<class T>
struct default_container_foldable
{
// Type value_type
using value_type = typename container_traits<T>::value_type;
// A fold(foldable<A>) requires monoid<A>
template<
class T_,
class = typename std::enable_if<std::is_same<T,T_>::value>,
class = typename std::enable_if<monoid<typename container_traits<T_>::value_type>::is_instance>::type>
static auto fold(const T_& in)
{
using A = typename container_traits<T_>::value_type;
return lfold(monoid<A>::append,monoid<A>::empty(),in);
}
// B lfold(B(B,A),B,foldable<A>)
template<class F, class B>
static auto lfold(F&& f, B b, const T& in) -> B
{
for (auto& a : in)
b = eval(f,b,a);
return b;
}
static constexpr bool is_instance = true;
};
#define FC_DEFAULT_CONTAINER_FOLDABLE(T)\
template<class... Args>\
struct foldable<T<Args...>> : public default_container_foldable<T<Args...>>\
{};
FC_DEFAULT_CONTAINER_FOLDABLE(std::deque);
FC_DEFAULT_CONTAINER_FOLDABLE(std::list);
FC_DEFAULT_CONTAINER_FOLDABLE(std::multiset);
FC_DEFAULT_CONTAINER_FOLDABLE(std::set);
FC_DEFAULT_CONTAINER_FOLDABLE(std::basic_string);
FC_DEFAULT_CONTAINER_FOLDABLE(std::unordered_multiset);
FC_DEFAULT_CONTAINER_FOLDABLE(std::unordered_set);
FC_DEFAULT_CONTAINER_FOLDABLE(std::vector);
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
// Build using -std=gnu++1y
#include <iostream>
#include <functional>
#include <locale>
#include "foldable.h"
#include "mappable.h"
#include "monoid.h"
#include "zip.h"
namespace
{
struct thing
{
int n;
};
struct person
{
std::string name;
};
}
int main()
{
// fold container
std::unordered_set<int> numbers{0,1,2,3,4,5,6,7,8,9,10};
std::cout << fc::fold(numbers) << "\n";
// map fold
std::vector<person> people{{"Robb"},{"Jon"},{"Sansa"},{"Brandon"},{"Arya"},{"Rickon"}};
auto list_strings = [](const std::string& lhs,const std::string& rhs)
{
if (lhs.empty()) return rhs;
return lhs + ", " + rhs;
};
std::cout << fc::lfold(list_strings,std::string(),fc::map(&person::name,people)) << "\n";
// lfold container
std::vector<char> characters{'h','e','l','l','o',',',' ','w','o','r','l','d','!'};
std::cout << fc::lfold(fc::plus(),std::string(),characters) << "\n";
// same thing but using map fold
auto ctos = [](char c){return std::string(1,c);};
std::cout << fc::fold(fc::map(ctos,characters)) << "\n";
// fold shared_ptr
std::shared_ptr<int> a_number = std::make_shared<int>(1);
std::cout << fc::fold(a_number) << "\n";
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <memory>
#include "container_traits.h"
#include "tuple.h"
#include "tuple_eval.h"
namespace fc
{
// remove const, volatile and references
template<class T>
using remove_cv_ref = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<class T>
struct mappable
{
// Type value_type
// mappable<R> map(R(A),mappable<A>)
static constexpr bool is_instance = false;
};
// Convenience functions
template<class F, class T, class... Args>
auto map(F&& f, const T& in, const Args&... args)
{
return mappable<T>::map(std::forward<F>(f),in,args...);
}
// Function instances
template<class Result,class... Params>
struct mappable<Result(Params...)>
{
// Type value_type
using value_type = Result;
// mappable<R> map(R(A,Args...),mappable<A>,mappable<Args>...)
template<class F,class A,class... Args>
static auto map(F&& f, const A& in, const Args&... args)
{
auto t_funcs = std::make_tuple(in,args...);
return [f,t_funcs](Params... params)
{
return tuple_eval(f,
multi_tuple_eval(t_funcs,std::forward_as_tuple(params...))
);
};
}
static constexpr bool is_instance = true;
};
// const member function
template<class Result, class Class, class... Params>
struct mappable<Result(Class::*)(Params...) const> :
public mappable<Result(const Class&,Params...)>
{};
// member function
template<class Result, class Class, class... Params>
struct mappable<Result(Class::*)(Params...)> :
public mappable<Result(Class&,Params...)>
{};
// member object
template<class Result, class Class>
struct mappable<Result(Class::*)> :
public mappable<Result(const Class&)>
{};
// free function
template<class Result, class... Params>
struct mappable<Result(*)(Params...)> :
public mappable<Result(Params...)>
{};
// shared_ptr instance
template<class T>
struct mappable<std::shared_ptr<T>>
{
// Type value_type
using value_type = T;
// mappable<R> map(R(A,Args...),mappable<A>,mappable<Args>...)
template<class F,class A,class... Args>
static auto map(F&& f, const std::shared_ptr<A>& in, const std::shared_ptr<Args>&... args)
-> std::shared_ptr<remove_cv_ref<decltype(eval(f,*in,(*args)...))>>
{
if (!tuple_all_valid(std::forward_as_tuple(in,args...)))
return std::shared_ptr<remove_cv_ref<decltype(eval(f,*in,(*args)...))>>();
return std::make_shared<remove_cv_ref<decltype(eval(f,*in,(*args)...))>>(
std::move(eval(std::forward<F>(f),*in,(*args)...)));
}
static constexpr bool is_instance = true;
};
// container instances
template<class T>
struct default_container_mappable
{
// Type value_type
using value_type = typename container_traits<T>::value_type;
// mappable<R> map(R(A,Args...),mappable<A>,mappable<Args>...)
template<class F,class A,class... Args>
static auto map(F&& f, const A& in, const Args&... args)
-> typename container_traits<T>::template rebind<
remove_cv_ref<decltype(eval(f,
std::declval<typename container_traits<A>::value_type>(),
std::declval<typename container_traits<Args>::value_type>()...
))>>
{
using B = remove_cv_ref<decltype(eval(f,
std::declval<typename container_traits<A>::value_type>(),
std::declval<typename container_traits<Args>::value_type>()...
))>;
using T_B = typename container_traits<T>::template rebind<B>;
T_B out;
const auto ends = std::make_tuple(in.end(),(args.end())...);
for (auto iters = std::make_tuple(in.begin(),(args.begin())...);
!tuple_any_equal(iters,ends);
tuple_increment(iters))
{
container_traits<T_B>::add_element(out,tuple_eval(std::forward<F>(f),tuple_dereference(iters)));
}
return out;
}
static constexpr bool is_instance = true;
};
#define FC_DEFAULT_CONTAINER_MAPPABLE(T)\
template<class... Args>\
struct mappable<T<Args...>> : public default_container_mappable<T<Args...>>\
{};
FC_DEFAULT_CONTAINER_MAPPABLE(std::deque);
FC_DEFAULT_CONTAINER_MAPPABLE(std::list);
FC_DEFAULT_CONTAINER_MAPPABLE(std::multiset);
FC_DEFAULT_CONTAINER_MAPPABLE(std::set);
FC_DEFAULT_CONTAINER_MAPPABLE(std::basic_string);
FC_DEFAULT_CONTAINER_MAPPABLE(std::unordered_multiset);
FC_DEFAULT_CONTAINER_MAPPABLE(std::unordered_set);
FC_DEFAULT_CONTAINER_MAPPABLE(std::vector);
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include "container_traits.h"
namespace fc
{
template<class T>
struct monoid
{
// T empty()
// T append(T,T)
static constexpr bool is_instance = false;
};
// Convenience functions
template<class T>
T append(const T& lhs, const T& rhs)
{
return monoid<T>::append(lhs,rhs);
}
// Fundamental type instances
template<class T>
struct default_fundamental_type_monoid
{
static T empty(){return T{};}
static T append(const T& lhs, const T& rhs){return lhs+rhs;}
static constexpr bool is_instance = true;
};
#define FUNDAMENTAL_TYPES\
X(bool)\
X(signed char)\
X(unsigned char)\
X(char)\
X(wchar_t)\
X(char16_t)\
X(char32_t)\
X(short)\
X(unsigned short)\
X(int)\
X(unsigned)\
X(long)\
X(unsigned long)\
X(long long)\
X(unsigned long long)
#define FC_DEFAULT_FUNDAMENTAL_TYPE_MONOID(T)\
template<>\
struct monoid<T> : public default_fundamental_type_monoid<T>\
{};
#define X FC_DEFAULT_FUNDAMENTAL_TYPE_MONOID
FUNDAMENTAL_TYPES;
#undef X
// Container instances
template<class T>
struct default_container_monoid
{
// T empty()
static T empty(){return T{};}
// T append(T,T)
static T append(T lhs, const T& rhs)
{
container_traits<T>::concat(lhs,rhs);
return lhs;
}
static constexpr bool is_instance = true;
};
#define FC_DEFAULT_CONTAINER_MONOID(T)\
template<class... Args>\
struct monoid<T<Args...>> : public default_container_monoid<T<Args...>>\
{};
FC_DEFAULT_CONTAINER_MONOID(std::deque);
FC_DEFAULT_CONTAINER_MONOID(std::list);
FC_DEFAULT_CONTAINER_MONOID(std::multiset);
FC_DEFAULT_CONTAINER_MONOID(std::set);
FC_DEFAULT_CONTAINER_MONOID(std::basic_string);
FC_DEFAULT_CONTAINER_MONOID(std::unordered_multiset);
FC_DEFAULT_CONTAINER_MONOID(std::unordered_set);
FC_DEFAULT_CONTAINER_MONOID(std::vector);
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <tuple>
namespace fc
{
template<size_t index>
struct tuple_helper
{
template<class... Args>
static bool any_equal(const std::tuple<Args...>& lhs, const std::tuple<Args...>& rhs)
{
if (std::get<index>(lhs) == std::get<index>(rhs))
return true;
return tuple_helper<index-1>::any_equal(lhs,rhs);
}
template<class... Args>
static void increment(std::tuple<Args...>& a)
{
tuple_helper<index-1>::increment(a);
std::get<index>(a)++;
}
template<class Tuple,class... Args>
static auto dereference(Tuple&& t, Args&&... args)
{
return tuple_helper<index-1>::dereference(
std::forward<Tuple>(t),
std::get<index>(std::forward<Tuple>(t)),
std::forward<Args>(args)...
);
}
template<class... Args>
static bool all_valid(const std::tuple<Args...>& a)
{
return bool(std::get<index>(a)) && tuple_helper<index-1>::all_valid(a);
}
};
template<>
struct tuple_helper<0>
{
template<class... Args>
static bool any_equal(const std::tuple<Args...>& lhs, const std::tuple<Args...>& rhs)
{
return std::get<0>(lhs) == std::get<0>(rhs);
}
template<class... Args>
static void increment(std::tuple<Args...>& a)
{
std::get<0>(a)++;
}
template<class Tuple,class... Args>
static auto dereference(Tuple&& t, Args&&... args)
{
return std::tuple<decltype(*std::get<0>(t)),decltype(*args)...>(*std::get<0>(t),(*args)...);
}
template<class... Args>
static bool all_valid(const std::tuple<Args...>& a)
{
return bool(std::get<0>(a));
}
};
template<class A,class... Args>
bool tuple_any_equal(const std::tuple<A,Args...>& lhs, const std::tuple<A,Args...>& rhs)
{
return tuple_helper<sizeof...(Args)>::any_equal(lhs,rhs);
}
template<class A,class... Args>
void tuple_increment(std::tuple<A,Args...>& a)
{
tuple_helper<sizeof...(Args)>::increment(a);
}
template<class Tuple>
auto tuple_dereference(Tuple&& t)
{
return tuple_helper<std::tuple_size<typename std::remove_reference<Tuple>::type>::value-1>::dereference(std::forward<Tuple>(t));
}
template<class A,class... Args>
bool tuple_all_valid(const std::tuple<A,Args...>& a)
{
return tuple_helper<sizeof...(Args)>::all_valid(a);
}
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <tuple>
#include "eval.h"
namespace fc
{
template<size_t index>
struct tuple_eval_helper
{
template<class Func,class TArgs,class... Args>
static auto evaluate(Func&& f, TArgs&& t_args, Args&&... args)
-> decltype(tuple_eval_helper<index-1>::evaluate(
std::forward<Func>(f),
std::forward<TArgs>(t_args),
std::get<index>(std::forward<TArgs>(t_args)),
std::forward<Args>(args)...
))
{
return tuple_eval_helper<index-1>::evaluate(
std::forward<Func>(f),
std::forward<TArgs>(t_args),
std::get<index>(std::forward<TArgs>(t_args)),
std::forward<Args>(args)...
);
}
};
template<>
struct tuple_eval_helper<0>
{
template<class Func,class TArgs,class... Args>
static auto evaluate(Func&& f, TArgs&& t_args, Args&&... args)
-> decltype(eval(
std::forward<Func>(f),
std::get<0>(std::forward<TArgs>(t_args)),
std::forward<Args>(args)...
))
{
return eval(
std::forward<Func>(f),
std::get<0>(std::forward<TArgs>(t_args)),
std::forward<Args>(args)...
);
}
};
template<class Func,class TArgs>
auto tuple_eval(Func&& f, TArgs&& t_args)
-> decltype(tuple_eval_helper<std::tuple_size<
typename std::remove_reference<TArgs>::type>::value-1>::evaluate(
std::forward<Func>(f),
std::forward<TArgs>(t_args)
))
{
return tuple_eval_helper<std::tuple_size<
typename std::remove_reference<TArgs>::type>::value-1>::evaluate(
std::forward<Func>(f),
std::forward<TArgs>(t_args)
);
}
template<size_t index>
struct multi_tuple_eval_helper
{
template<class TFuncs,class TArgs,class... Results>
static auto evaluate(TFuncs&& t_funcs, TArgs&& t_args, Results&&... results)
-> decltype(multi_tuple_eval_helper<index-1>::evaluate(
std::forward<TFuncs>(t_funcs),
std::forward<TArgs>(t_args),
tuple_eval(std::get<index>(t_funcs),t_args),
std::forward<Results>(results)...
))
{
return multi_tuple_eval_helper<index-1>::evaluate(
std::forward<TFuncs>(t_funcs),
std::forward<TArgs>(t_args),
tuple_eval(std::get<index>(t_funcs),t_args),
std::forward<Results>(results)...
);
}
};
template<>
struct multi_tuple_eval_helper<0>
{
template<class TFuncs,class TArgs,class... Results>
static auto evaluate(TFuncs&& t_funcs, TArgs&& t_args, Results&&... results)
-> decltype(std::tuple<decltype(tuple_eval(std::get<0>(t_funcs),t_args)),Results...>(
tuple_eval(std::get<0>(t_funcs),t_args),
std::forward<Results>(results)...
))
{
return std::tuple<decltype(tuple_eval(std::get<0>(t_funcs),t_args)),Results...>(
tuple_eval(std::get<0>(t_funcs),t_args),
std::forward<Results>(results)...
);
}
};
template<class TFuncs,class TArgs>
auto multi_tuple_eval(TFuncs&& t_funcs, TArgs&& t_args)
-> decltype(multi_tuple_eval_helper<std::tuple_size<
typename std::remove_reference<TFuncs>::type>::value-1>::evaluate(
std::forward<TFuncs>(t_funcs),
std::forward<TArgs>(t_args)
))
{
return multi_tuple_eval_helper<std::tuple_size<
typename std::remove_reference<TFuncs>::type>::value-1>::evaluate(
std::forward<TFuncs>(t_funcs),
std::forward<TArgs>(t_args)
);
}
}
/*
* Copyright (c) 2013, Daniel Park
* All rights reserved.
*
* Permission to modify and redistribute this software is granted to
* anyone provided the above copyright notice, this condition and the
* following disclaimer are retained.
*
* This software is provided "as is", without and express or implied
* warranty. In no event shall the author be liable for damages arising
* from the use of this software.
*/
#pragma once
#include <type_traits>
#include <tuple>
namespace fc
{
struct zipper
{
template<class... Args>
auto operator()(Args&&... args)
{
return std::make_tuple(std::forward<Args>(args)...);
}
};
struct pairer
{
template<class L,class R>
auto operator()(L&& l, R&& r)
{
return std::make_pair(std::forward<L>(l),std::forward<R>(r));
}
};
template<class... Args>
struct zipper_t
{
template<class... Args_>
auto operator()(Args_&&... args)
{
return std::tuple<Args...>(std::forward<Args_>(args)...);
}
};
template<class L,class R>
struct pairer_t
{
template<class L_,class R_>
auto operator()(L_&& l, R_&& r)
{
return std::pair<L,R>(std::forward<L_>(l),std::forward<R_>(r));
}
};
template<class T>
struct make
{
template<class... Args>
auto operator()(Args&&... args)
{
return T(std::forward<Args...>(args...));
}
};
#define FC_BINARY_OPERATORS\
X(plus,+)\
X(minus,-)\
X(multiplies,*)\
X(divides,/)\
X(modulus,%)\
X(equal_to,==)\
X(not_equal_to,!=)\
X(greater,>)\
X(less,<)\
X(greater_equal,>=)\
X(less_equal,<=)\
X(logical_and,&&)\
X(logical_or,||)\
X(bit_and,&)\
X(bit_or,|)\
X(bit_xor,^)
#define X(name,symbol)\
struct name\
{\
template<class L,class R>\
auto operator()(L&& l, R&& r)\
{\
return l symbol r;\
}\
};
FC_BINARY_OPERATORS
#undef X
template<class L,class R>
auto unpair(std::vector<std::pair<L,R>>&& v)
{
std::pair<std::vector<L>,std::vector<R>> out;
for (auto& p : v)
{
out.first.push_back(p.first);
out.second.push_back(p.second);
}
return out;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment