Last active
August 7, 2019 09:25
-
-
Save whanhee/6432970 to your computer and use it in GitHub Desktop.
Type class: mappable, intro. For explanation, see: http://functionalcpp.wordpress.com/2013/09/04/type-class-mappable-intro/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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> | |
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 associative_container_traits<std::unordered_multiset<Args...>> | |
{}; | |
template<class... Args> | |
struct container_traits<std::unordered_set<Args...>> : public associative_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...>> | |
{}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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> | |
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 "container_traits.h" | |
#include "eval.h" | |
#include "mappable.h" | |
namespace | |
{ | |
template<int X> | |
int increment_by(int n){return n+X;} | |
} | |
int main() | |
{ | |
// function | |
std::string words = "hello, world!"; | |
auto string_length_plus_one = mappable<char(const std::string&)>::map(&increment_by<1>,&std::string::size); | |
std::cout << "size + 1: " << string_length_plus_one(words) << "\n"; | |
// function with convenience function | |
std::cout << "1 plus 2: " << map(&increment_by<1>,&increment_by<1>)(1) << "\n"; | |
// container | |
std::vector<int> numbers{0,1,2,3,4}; | |
std::cout << "increment by 10: "; | |
for (int n : map(&increment_by<10>,numbers)) | |
std::cout << n << " "; | |
std::cout << "\n"; | |
// container with convenience function | |
auto shout = [](char c){return std::toupper(c,std::locale::classic());}; | |
std::cout << "shout: " << map(shout,words) << "\n"; | |
// container to different container | |
std::cout << "characters used: "; | |
for (char c : mappable<std::set<char>>::map([](char a){return a;},words)) | |
std::cout << "(" << c << ") "; | |
std::cout << "\n"; | |
// shared_ptr | |
std::shared_ptr<int> p_num = std::make_shared<int>(10); | |
std::cout << "increment by 5: " << *mappable<std::shared_ptr<int>>::map(&increment_by<5>,p_num) << "\n"; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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" | |
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> | |
auto map(F&& f, const T& in) | |
{ | |
return mappable<T>::map(std::forward<F>(f),in); | |
} | |
// Function instances | |
template<class Result,class... Params> | |
struct mappable<Result(Params...)> | |
{ | |
// Type value_type | |
using value_type = Result; | |
// mappable<R> map(R(A),mappable<A>) | |
template<class F,class A> | |
static auto map(F&& f, const A& in) | |
{ | |
return [=](Params... params) | |
{ | |
return eval(f,eval(in,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),mappable<A>) | |
template<class F,class A> | |
static auto map(F&& f, const std::shared_ptr<A>& in) -> typename std::shared_ptr<decltype(eval(f,*in))> | |
{ | |
if (!in) | |
return std::shared_ptr<decltype(eval(f,*in))>(); | |
return std::make_shared<decltype(eval(f,*in))>(std::move(eval(std::forward<F>(f),*in))); | |
} | |
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),mappable<A>) | |
template<class F,class A> | |
static auto map(F&& f, const A& in) | |
-> typename container_traits<T>::template rebind< | |
decltype(eval(f,std::declval<typename container_traits<A>::value_type>()))> | |
{ | |
using B = decltype(eval(f,std::declval<typename container_traits<A>::value_type>())); | |
using T_B = typename container_traits<T>::template rebind<B>; | |
T_B out; | |
for (auto& a : in) | |
container_traits<T_B>::add_element(out,eval(std::forward<F>(f),a)); | |
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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment