-
Notifications
You must be signed in to change notification settings - Fork 1
/
unpack.hpp
182 lines (161 loc) · 7.3 KB
/
unpack.hpp
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
///////////////////////////////////////////////////////////////////////////////
// unpack.hpp
// Make action work with unpacking patterns.
//
// Copyright 2012 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROTO_ACTION_UNPACK_HPP_INCLUDED
#define BOOST_PROTO_ACTION_UNPACK_HPP_INCLUDED
#include <cstddef>
#include <utility>
#include <boost/proto/proto_fwd.hpp>
#include <boost/proto/action/action.hpp>
#include <boost/proto/utility.hpp>
namespace boost
{
namespace proto
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////
// expand_pattern_2_
template<std::size_t I, typename BasicAction>
struct expand_pattern_2_
{
typedef BasicAction type;
};
template<std::size_t I, typename Action>
struct expand_pattern_2_<I, pack(Action)>
{
typedef proto::_child<I> type(Action);
};
template<typename Action>
struct expand_pattern_2_<(std::size_t)-1, pack(Action)>
{
typedef proto::_value type(Action);
};
template<std::size_t I, typename Ret, typename ...Actions>
struct expand_pattern_2_<I, Ret(Actions...)>
{
typedef Ret type(typename expand_pattern_2_<I, Actions>::type...);
};
template<std::size_t I, typename Ret, typename ...Actions>
struct expand_pattern_2_<I, Ret(*)(Actions...)>
: expand_pattern_2_<I, Ret(Actions...)>
{};
////////////////////////////////////////////////////////////////////////////////////////
// expand_pattern_1_
template<typename Indices, typename Actions>
struct expand_pattern_1_;
template<std::size_t ...I, typename Ret, typename ...Actions>
struct expand_pattern_1_<utility::indices<I...>, Ret(Actions......)>
: utility::concat<
typename utility::pop_back<Ret(Actions...)>::type
, void(
typename expand_pattern_2_<
I
, typename utility::result_of::back<Actions...>::type
>::type...
)
>
{};
////////////////////////////////////////////////////////////////////////////////////////
// collect_pack_actions_
template<typename UnpackingPattern, typename Actions = void()>
struct collect_pack_actions_
{
typedef Actions type;
};
// Note: Do *NOT* recurse into vararg functions. Those are nested pack actions,
// which should not be considered together with this one.
template<typename Ret, typename Head, typename ...Tail, typename Actions>
struct collect_pack_actions_<Ret(Head, Tail...), Actions>
: collect_pack_actions_<
Ret(Tail...)
, typename collect_pack_actions_<Head, Actions>::type
>
{};
template<typename Ret, typename Head, typename ...Tail, typename Actions>
struct collect_pack_actions_<Ret(*)(Head, Tail...), Actions>
: collect_pack_actions_<Ret(Head, Tail...), Actions>
{};
template<typename Action, typename ...Actions>
struct collect_pack_actions_<pack(Action), void(Actions...)>
{
typedef void type(Actions..., action<Action>);
};
////////////////////////////////////////////////////////////////////////////////////////
// compute_indices_2_
template<std::size_t Arity0, std::size_t Arity1 = Arity0>
struct compute_indices_2_
: std::conditional<
Arity0 == 0
, utility::indices<(std::size_t)-1>
, utility::make_indices<Arity0>
>
{
static_assert(
Arity0 == Arity1
, "Two pack expressions in unpacking pattern have different arities"
);
};
////////////////////////////////////////////////////////////////////////////////////////
// compute_indices_1_
template<typename Actions, typename ...Args>
struct compute_indices_1_
{
static_assert(
utility::never<Actions>::value
, "No pack expression found in unpacking pattern. Use proto::pack(<basic_action>) "
"to designate an action that returns the expression you want to unpack; "
"e.g., proto::pack(_) unpacks the current expression."
);
};
template<typename Head, typename...Tail, typename ...Args>
struct compute_indices_1_<void(Head, Tail...), Args...>
{
typedef arity_of<decltype(Head()(std::declval<Args>()...))> arity;
typedef compute_indices_1_<void(Tail...), Args...> tail;
typedef typename compute_indices_2_<arity::value, tail::arity::value>::type type;
};
template<typename Head, typename ...Args>
struct compute_indices_1_<void(Head), Args...>
{
typedef arity_of<decltype(Head()(std::declval<Args>()...))> arity;
typedef typename compute_indices_2_<arity::value>::type type;
};
////////////////////////////////////////////////////////////////////////////////////////
// _unpack
template<typename Ret, typename ...Actions>
struct _unpack
: basic_action<_unpack<Ret, Actions...>>
// TODO: move implementation into _unpack_impl that is parameterized on result of
// collect_pack_actions_, and specialized on void(action<_>) to have a more
// optimal implementation.
{
typedef
typename collect_pack_actions_<
typename utility::result_of::back<Actions...>::type
>::type
actions_type;
template<typename ...Args>
auto operator()(Args &&... args) const
BOOST_PROTO_AUTO_RETURN(
action<
typename expand_pattern_1_<
typename compute_indices_1_<actions_type, Args...>::type
, Ret(Actions......)
>::type
>()(static_cast<Args &&>(args)...)
)
};
}
// Handle actions with pack expansions
template<typename Ret, typename ...Actions>
struct action<Ret(Actions......), typename std::enable_if<!is_tag<Ret>::value>::type>
: detail::_unpack<Ret, Actions...>
{};
}
}
#endif