-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtransrangers.hpp
303 lines (260 loc) · 6.58 KB
/
transrangers.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/* Transrangers: an efficient, composable design pattern for range processing.
*
* Copyright 2021 Joaquin M Lopez Munoz.
* 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)
*
* See https://github.com/joaquintides/transrangers for project home page.
*/
#ifndef JOAQUINTIDES_TRANSRANGERS_HPP
#define JOAQUINTIDES_TRANSRANGERS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <iterator>
#include <optional>
#include <tuple>
#include <type_traits>
#include <utility>
#if defined(__clang__)
#define TRANSRANGERS_HOT __attribute__((flatten))
#define TRANSRANGERS_HOT_MUTABLE __attribute__((flatten)) mutable
#elif defined(__GNUC__)
#define TRANSRANGERS_HOT __attribute__((flatten))
#define TRANSRANGERS_HOT_MUTABLE mutable __attribute__((flatten))
#else
#define TRANSRANGERS_HOT [[msvc::forceinline]]
#define TRANSRANGERS_HOT_MUTABLE mutable [[msvc::forceinline]]
#endif
namespace transrangers{
template<typename Cursor,typename F>
struct ranger_class:F
{
using cursor=Cursor;
};
template<typename Cursor,typename F>
auto ranger(F f)
{
return ranger_class<Cursor,F>{f};
}
template<typename Range>
auto all(Range&& rng)
{
using std::begin;
using std::end;
using cursor=decltype(begin(rng));
return ranger<cursor>(
[first=begin(rng),last=end(rng)](auto dst) TRANSRANGERS_HOT_MUTABLE {
auto it=first;
while(it!=last)if(!dst(it++)){first=it;return false;}
return true;
});
}
template<typename Range>
struct all_copy
{
using ranger=decltype(all(std::declval<Range&>()));
using cursor=typename ranger::cursor;
auto operator()(const auto& p){return rgr(p);}
Range rng;
ranger rgr=all(rng);
};
template<typename Range>
auto all(Range&& rng) requires(std::is_rvalue_reference_v<Range&&>)
{
return all_copy<Range>{std::move(rng)};
}
template<typename Pred>
auto pred_box(Pred pred)
{
return [=](auto&&... x)->int{
return pred(std::forward<decltype(x)>(x)...);
};
}
template<typename Pred,typename Ranger>
auto filter(Pred pred_,Ranger rgr)
{
using cursor=typename Ranger::cursor;
return ranger<cursor>(
[=,pred=pred_box(pred_)](auto dst) TRANSRANGERS_HOT_MUTABLE {
return rgr([&](const auto& p) TRANSRANGERS_HOT {
return pred(*p)?dst(p):true;
});
});
}
template<typename Cursor,typename F,typename=void>
struct deref_fun
{
decltype(auto) operator*()const{return (*pf)(*p);}
Cursor p;
F* pf;
};
template<typename Cursor,typename F>
struct deref_fun<
Cursor,F,
std::enable_if_t<
std::is_trivially_default_constructible_v<F>&&std::is_empty_v<F>
>
>
{
deref_fun(Cursor p={},F* =nullptr):p{p}{}
decltype(auto) operator*()const{return F()(*p);}
Cursor p;
};
template<typename F,typename Ranger>
auto transform(F f,Ranger rgr)
{
using cursor=deref_fun<typename Ranger::cursor,F>;
return ranger<cursor>([=](auto dst) TRANSRANGERS_HOT_MUTABLE {
return rgr([&](const auto& p) TRANSRANGERS_HOT {
return dst(cursor{p,&f});
});
});
}
template<typename Ranger>
auto take(int n,Ranger rgr)
{
using cursor=typename Ranger::cursor;
return ranger<cursor>([=](auto dst) TRANSRANGERS_HOT_MUTABLE {
if(n)return rgr([&](const auto& p) TRANSRANGERS_HOT {
--n;
return dst(p)&&(n!=0);
})||(n==0);
else return true;
});
}
template<typename Ranger>
auto concat(Ranger rgr)
{
return rgr;
}
template<typename Ranger,typename... Rangers>
auto concat(Ranger rgr,Rangers... rgrs)
{
using cursor=typename Ranger::cursor;
return ranger<cursor>(
[=,cont=false,next=concat(rgrs...)]
(auto dst) TRANSRANGERS_HOT_MUTABLE {
if(!cont){
if(!(cont=rgr(dst)))return false;
}
return next(dst);
}
);
}
template<typename Ranger>
auto unique(Ranger rgr)
{
using cursor=typename Ranger::cursor;
return ranger<cursor>(
[=,start=true,p=cursor{}](auto dst) TRANSRANGERS_HOT_MUTABLE {
if(start){
start=false;
if(rgr([&](const auto& q) TRANSRANGERS_HOT {
p=q;
return false;
}))return true;
if(!dst(p))return false;
}
return rgr([&,prev=p](const auto& q) TRANSRANGERS_HOT_MUTABLE {
if((*prev==*q)||dst(q)){prev=q;return true;}
else{p=q;return false;}
});
});
}
struct identity_adaption
{
static decltype(auto) adapt(auto&& srgr){
return std::forward<decltype(srgr)>(srgr);
};
};
template<typename Ranger,typename Adaption=identity_adaption>
auto join(Ranger rgr)
{
using cursor=typename Ranger::cursor;
using subranger=std::remove_cvref_t<
decltype(Adaption::adapt(*std::declval<const cursor&>()))>;
using subranger_cursor=typename subranger::cursor;
return ranger<subranger_cursor>(
[=,osrgr=std::optional<subranger>{}]
(auto dst) TRANSRANGERS_HOT_MUTABLE {
if(osrgr){
if(!(*osrgr)(dst))return false;
}
return rgr([&](const auto& p) TRANSRANGERS_HOT {
auto srgr=Adaption::adapt(*p);
if(!srgr(dst)){
osrgr.emplace(std::move(srgr));
return false;
}
else return true;
});
});
}
struct all_adaption
{
static auto adapt(auto&& srgn){
return all(std::forward<decltype(srgn)>(srgn));
};
};
template<typename Ranger>
auto ranger_join(Ranger rgr)
{
return join<Ranger,all_adaption>(std::move(rgr));
}
template<typename... Rangers>
struct zip_cursor
{
auto operator*()const
{
return std::apply([](const auto&... ps){
return std::tuple<decltype(*ps)...>{*ps...};
},ps);
}
std::tuple<typename Rangers::cursor...> ps;
};
template<typename Ranger,typename... Rangers>
auto zip(Ranger rgr,Rangers... rgrs)
{
using cursor=zip_cursor<Ranger,Rangers...>;
return ranger<cursor>(
[=,zp=cursor{}](auto dst) TRANSRANGERS_HOT_MUTABLE {
bool finished=false;
return rgr([&](const auto& p) TRANSRANGERS_HOT {
std::get<0>(zp.ps)=p;
if([&]<std::size_t... I>(std::index_sequence<I...>
#ifdef _MSC_VER
,auto&... rgrs
#endif
) TRANSRANGERS_HOT {
return (rgrs([&](const auto& p) TRANSRANGERS_HOT {
std::get<I+1>(zp.ps)=p;
return false;
})||...);
}(std::index_sequence_for<Rangers...>{}
#ifdef _MSC_VER
,rgrs...
#endif
)){
finished=true;
return false;
}
return dst(zp);
})||finished;
}
);
}
template<typename Ranger,typename T>
T accumulate(Ranger rgr,T init)
{
rgr([&](const auto& p) TRANSRANGERS_HOT{
init=std::move(init)+*p;
return true;
});
return init;
}
} /* transrangers */
#undef TRANSRANGERS_HOT_MUTABLE
#undef TRANSRANGERS_HOT
#endif