-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunctional.h
130 lines (98 loc) · 3.4 KB
/
functional.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/** \file functional.h
* \author Andrej Leban
* \date 10/2019
*/
#ifndef CFUNCTIONAL_H
#define CFUNCTIONAL_H
#include <any>
#include <functional>
#include <utility>
namespace cm
{
// A modified implementation of std::accumulate which avoids
// unnecessary copies – whenever it calls the folding function,
// it moves the previously accumulated value into it instead
// of passing a copy
// Copyright I. Čukić, Functional programming in C++
//! \brief A std::accumulate that makes use of move semantics.
//! \param first iterator to first element
//! \param last iterator to last element
//! \param init initial value
//! \param folding_function
//! \return the accumulated values
template <typename BeginIt, typename EndIt, typename T, typename F>
T moving_accumulate(BeginIt first, const EndIt & last, T init, F folding_function);
//! \brief Wrapper around std::any for std::functions.
// Adapted from c.f.: https://stackoverflow.com/questions/45715219/store-functions-with-different-signatures-in-a-map/
// WARNING: Had trouble compiling with libc++ 9.0 on Linux.
template <typename Ret>
struct AnyCallable
{
AnyCallable() = default;
template <typename F>
AnyCallable(F && fun);
template <typename... Args>
AnyCallable(std::function<Ret(Args...)> fun);
template <typename... Args>
Ret operator()(Args &&... args);
std::any m_any;
};
// Specialization for void callables
template <>
struct AnyCallable<void>
{
AnyCallable() = default;
template <typename F>
AnyCallable(F && fun);
template <typename... Args>
AnyCallable(std::function<void(Args...)> fun);
template <typename ... Args>
void operator()(Args &&... args);
std::any m_any;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename BeginIt, typename EndIt, typename T, typename F>
T moving_accumulate(BeginIt first, const EndIt & last, T init, F folding_function)
{
for (; first != last; ++first)
{
// When passing the accumulated value to
// the folding function, move from it.
// This might make problems for types that
// do not support assignment to moved-from values,
// but it will work for most types without problems.
init = folding_function(std::move(init), *first);
}
return init;
}
// AnyCallable
template <typename Ret>
template <typename F>
AnyCallable<Ret>::AnyCallable(F && fun) : AnyCallable(std::function(fun))
{}
template <typename Ret>
template <typename... Args>
AnyCallable<Ret>::AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun)
{}
template <typename Ret>
template <typename... Args>
Ret AnyCallable<Ret>::operator()(Args &&... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
template <typename F>
AnyCallable<void>::AnyCallable(F && fun) : AnyCallable(std::function(fun))
{}
template <typename... Args>
AnyCallable<void>::AnyCallable(std::function<void(Args...)> fun)
: m_any(fun)
{}
template <typename... Args>
void AnyCallable<void>::operator()(Args &&... args)
{
std::invoke(std::any_cast<std::function<void(Args...)>>(m_any), std::forward<Args>(args)...);
}
} // namespace cm
#endif // CFUNCTIONAL_H