1 #pragma once
2
3 //
4 // fplus.hpp
5 //
6
7 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
8 // https://github.com/Dobiasd/FunctionalPlus
9 // Distributed under the Boost Software License, Version 1.0.
10 // (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13
14
15 //
16 // compare.hpp
17 //
18
19 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
20 // https://github.com/Dobiasd/FunctionalPlus
21 // Distributed under the Boost Software License, Version 1.0.
22 // (See accompanying file LICENSE_1_0.txt or copy at
23 // http://www.boost.org/LICENSE_1_0.txt)
24
25
26
27 //
28 // function_traits.hpp
29 //
30
31 //--------------------------------------
32 // utils/traits: Additional type traits
33 //--------------------------------------
34 //
35 // Copyright kennytm (auraHT Ltd.) 2011.
36 // Distributed under the Boost Software License, Version 1.0.
37 // (See accompanying file LICENSE_1_0.txt or copy at
38 // http://www.boost.org/LICENSE_1_0.txt)
39
40 /**
41
42 ``<utils/traits.hpp>`` --- Additional type traits
43 =================================================
44
45 This module provides additional type traits and related functions, missing from
46 the standard library.
47
48 */
49
50 #ifndef TRAITS_HPP_9ALQFEFX7TO
51 #define TRAITS_HPP_9ALQFEFX7TO 1
52
53 #include <cstdlib>
54 #include <tuple>
55 #include <functional>
56 #include <type_traits>
57
58
59 //
60 // internal/meta.hpp
61 //
62
63 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
64 // https://github.com/Dobiasd/FunctionalPlus
65 // Distributed under the Boost Software License, Version 1.0.
66 // (See accompanying file LICENSE_1_0.txt or copy at
67 // http://www.boost.org/LICENSE_1_0.txt)
68
69
70 #include <type_traits>
71
72 namespace fplus
73 {
74 namespace internal
75 {
76 // C++14 compatible void_t (http://en.cppreference.com/w/cpp/types/void_t)
77 template <typename... Ts>
78 struct make_void
79 {
80 using type = void;
81 };
82
83 template <typename... Ts>
84 using void_t = typename make_void<Ts...>::type;
85
86 // Sometimes you don't want to use std::decay_t, and the temptation of short
87 // writing can be huge...
88 template <typename T>
89 using uncvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
90
91 // disjunction/conjunction/negation, useful to short circuit SFINAE checks
92 // Use with parsimony, MSVC 2015 can have ICEs quite easily
93 template <typename...>
94 struct disjunction : std::false_type
95 {
96 };
97
98 template <typename B1>
99 struct disjunction<B1> : B1
100 {
101 };
102
103 template <typename B1, typename... Bn>
104 struct disjunction<B1, Bn...>
105 : std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type
106 {
107 };
108
109 template <typename...>
110 struct conjunction : std::true_type
111 {
112 };
113
114 template <typename B1>
115 struct conjunction<B1> : B1
116 {
117 };
118
119 template <typename B1, typename... Bn>
120 struct conjunction<B1, Bn...>
121 : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type
122 {
123 };
124
125 template <typename B>
126 struct negation : std::integral_constant<bool, !bool(B::value)>
127 {
128 };
129
130 // non short-circuiting meta functions
131 // source: https://stackoverflow.com/a/27221517/4116453
132 template <bool...>
133 struct bool_pack;
134
135 template <bool... Values>
136 struct all_of
137 : std::is_same<bool_pack<Values..., true>, bool_pack<true, Values...>>
138 {
139 };
140
141 // there seems to be a bug in libc++'s std::is_function
142 // provide our own (cppreference one)
143 // (the MSVC implementation seems correct)
144 #ifndef _MSC_VER
145 #define PROVIDE_IS_FUNCTION_POLYFILL
146 #endif
147
148 #ifndef PROVIDE_IS_FUNCTION_POLYFILL
149 template<class... Any>
150 using is_function = std::is_function<Any...>;
151 #else //PROVIDE_IS_FUNCTION_POLYFILL
152 // primary template
153 template<class>
154 struct is_function : std::false_type { };
155
156 // specialization for regular functions
157 template<class Ret, class... Args>
158 struct is_function<Ret(Args...)> : std::true_type {};
159
160 // specialization for variadic functions such as std::printf
161 template<class Ret, class... Args>
162 struct is_function<Ret(Args...,...)> : std::true_type {};
163
164 // specialization for function types that have cv-qualifiers
165 template<class Ret, class... Args>
166 struct is_function<Ret(Args...) const> : std::true_type {};
167 template<class Ret, class... Args>
168 struct is_function<Ret(Args...) volatile> : std::true_type {};
169 template<class Ret, class... Args>
170 struct is_function<Ret(Args...) const volatile> : std::true_type {};
171 template<class Ret, class... Args>
172 struct is_function<Ret(Args...,...) const> : std::true_type {};
173 template<class Ret, class... Args>
174 struct is_function<Ret(Args...,...) volatile> : std::true_type {};
175 template<class Ret, class... Args>
176 struct is_function<Ret(Args...,...) const volatile> : std::true_type {};
177
178 // specialization for function types that have ref-qualifiers
179 template<class Ret, class... Args>
180 struct is_function<Ret(Args...) &> : std::true_type {};
181 template<class Ret, class... Args>
182 struct is_function<Ret(Args...) const &> : std::true_type {};
183 template<class Ret, class... Args>
184 struct is_function<Ret(Args...) volatile &> : std::true_type {};
185 template<class Ret, class... Args>
186 struct is_function<Ret(Args...) const volatile &> : std::true_type {};
187 template<class Ret, class... Args>
188 struct is_function<Ret(Args...,...) &> : std::true_type {};
189 template<class Ret, class... Args>
190 struct is_function<Ret(Args...,...) const &> : std::true_type {};
191 template<class Ret, class... Args>
192 struct is_function<Ret(Args...,...) volatile &> : std::true_type {};
193 template<class Ret, class... Args>
194 struct is_function<Ret(Args...,...) const volatile &> : std::true_type {};
195 template<class Ret, class... Args>
196 struct is_function<Ret(Args...) &&> : std::true_type {};
197 template<class Ret, class... Args>
198 struct is_function<Ret(Args...) const &&> : std::true_type {};
199 template<class Ret, class... Args>
200 struct is_function<Ret(Args...) volatile &&> : std::true_type {};
201 template<class Ret, class... Args>
202 struct is_function<Ret(Args...) const volatile &&> : std::true_type {};
203 template<class Ret, class... Args>
204 struct is_function<Ret(Args...,...) &&> : std::true_type {};
205 template<class Ret, class... Args>
206 struct is_function<Ret(Args...,...) const &&> : std::true_type {};
207 template<class Ret, class... Args>
208 struct is_function<Ret(Args...,...) volatile &&> : std::true_type {};
209 template<class Ret, class... Args>
210 struct is_function<Ret(Args...,...) const volatile &&> : std::true_type {};
211 #endif //PROVIDE_IS_FUNCTION_POLYFILL
212
213 template <typename>
214 struct reverse_integer_sequence_impl;
215
216 template <typename T>
217 struct reverse_integer_sequence_impl<std::integer_sequence<T>>
218 : std::integer_sequence<T>
219 {
220 };
221
222 template <typename T, T... Ints>
223 struct reverse_integer_sequence_impl<std::integer_sequence<T, Ints...>>
224 : std::integer_sequence<T, sizeof...(Ints) - 1 - Ints...>
225 {
226 };
227
228 template <typename Seq>
229 using reverse_integer_sequence = reverse_integer_sequence_impl<Seq>;
230
231 template <typename T, T N>
232 using make_reverse_integer_sequence =
233 reverse_integer_sequence<std::make_integer_sequence<T, N>>;
234
235 template <std::size_t... Idx>
236 using reverse_index_sequence =
237 reverse_integer_sequence<std::index_sequence<Idx...>>;
238
239 template <std::size_t N>
240 using make_reverse_index_sequence =
241 make_reverse_integer_sequence<std::size_t, N>;
242 }
243 }
244
245 namespace fplus {
246
247 // source: https://github.com/kennytm/utils
248 namespace utils {
249
250 #ifdef __GNUC__
251 #pragma GCC diagnostic push
252 #pragma GCC diagnostic ignored "-Weffc++"
253 #endif
254
255 /**
256 .. macro:: DECLARE_HAS_TYPE_MEMBER(member_name)
257
258 This macro declares a template ``has_member_name`` which will check whether
259 a type member ``member_name`` exists in a particular type.
260
261 Example::
262
263 DECLARE_HAS_TYPE_MEMBER(result_type)
264
265 ...
266
267 printf("%d\n", has_result_type< std::plus<int> >::value);
268 // ^ prints '1' (true)
269 printf("%d\n", has_result_type< double(*)() >::value);
270 // ^ prints '0' (false)
271 */
272 #define DECLARE_HAS_TYPE_MEMBER(member_name) \
273 template <typename, typename = void> \
274 struct has_##member_name \
275 { enum { value = false }; }; \
276 template <typename T> \
277 struct has_##member_name<T, typename std::enable_if<sizeof(typename T::member_name)||true>::type> \
278 { enum { value = true }; };
279
280 /**
281 .. type:: struct utils::function_traits<F>
282
283 Obtain compile-time information about a function object *F*.
284
285 This template currently supports the following types:
286
287 * Normal function types (``R(T...)``), function pointers (``R(*)(T...)``)
288 and function references (``R(&)(T...)`` and ``R(&&)(T...)``).
289 * Member functions (``R(C::*)(T...)``)
290 * ``std::function<F>``
291 * Type of lambda functions, and any other types that has a unique
292 ``operator()``.
293 * Type of ``std::mem_fn`` (only for GCC's libstdc++ and LLVM's libc++).
294 Following the C++ spec, the first argument will be a raw pointer.
295 */
296 template <typename T>
297 struct function_traits
298 : public function_traits<decltype(&T::operator())>
299 {};
300
301 namespace xx_impl
302 {
303 template <typename C, typename R, typename... A>
304 struct memfn_type
305 {
306 typedef typename std::conditional<
307 std::is_const<C>::value,
308 typename std::conditional<
309 std::is_volatile<C>::value,
310 R (C::*)(A...) const volatile,
311 R (C::*)(A...) const
312 >::type,
313 typename std::conditional<
314 std::is_volatile<C>::value,
315 R (C::*)(A...) volatile,
316 R (C::*)(A...)
317 >::type
318 >::type type;
319 };
320 }
321
322 template <typename ReturnType, typename... Args>
323 struct function_traits<ReturnType(Args...)>
324 {
325 /**
326 .. type:: type result_type
327
328 The type returned by calling an instance of the function object type *F*.
329 */
330 typedef ReturnType result_type;
331
332 /**
333 .. type:: type function_type
334
335 The function type (``R(T...)``).
336 */
337 typedef ReturnType function_type(Args...);
338
339 /**
340 .. type:: type member_function_type<OwnerType>
341
342 The member function type for an *OwnerType* (``R(OwnerType::*)(T...)``).
343 */
344 template <typename OwnerType>
345 using member_function_type = typename xx_impl::memfn_type<
346 typename std::remove_pointer<typename std::remove_reference<OwnerType>::type>::type,
347 ReturnType, Args...
348 >::type;
349
350 /**
351 .. data:: static const size_t arity
352
353 Number of arguments the function object will take.
354 */
355 enum { arity = sizeof...(Args) };
356
357 /**
358 .. type:: type arg<n>::type
359
360 The type of the *n*-th argument.
361 */
362 template <size_t i>
363 struct arg
364 {
365 typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
366 };
367 };
368
369 template <typename ReturnType, typename... Args>
370 struct function_traits<ReturnType(*)(Args...)>
371 : public function_traits<ReturnType(Args...)>
372 {};
373
374 template <typename ClassType, typename ReturnType, typename... Args>
375 struct function_traits<ReturnType(ClassType::*)(Args...)>
376 : public function_traits<ReturnType(Args...)>
377 {
378 typedef ClassType& owner_type;
379 };
380
381 template <typename ClassType, typename ReturnType, typename... Args>
382 struct function_traits<ReturnType(ClassType::*)(Args...) const>
383 : public function_traits<ReturnType(Args...)>
384 {
385 typedef const ClassType& owner_type;
386 };
387
388 template <typename ClassType, typename ReturnType, typename... Args>
389 struct function_traits<ReturnType(ClassType::*)(Args...) volatile>
390 : public function_traits<ReturnType(Args...)>
391 {
392 typedef volatile ClassType& owner_type;
393 };
394
395 template <typename ClassType, typename ReturnType, typename... Args>
396 struct function_traits<ReturnType(ClassType::*)(Args...) const volatile>
397 : public function_traits<ReturnType(Args...)>
398 {
399 typedef const volatile ClassType& owner_type;
400 };
401
402 template <typename FunctionType>
403 struct function_traits<std::function<FunctionType>>
404 : public function_traits<FunctionType>
405 {};
406
407 #if defined(_GLIBCXX_FUNCTIONAL)
408 #define MEM_FN_SYMBOL_XX0SL7G4Z0J std::_Mem_fn
409 #elif defined(_LIBCPP_FUNCTIONAL)
410 #define MEM_FN_SYMBOL_XX0SL7G4Z0J std::__mem_fn
411 #endif
412
413 #ifdef MEM_FN_SYMBOL_XX0SL7G4Z0J
414
415 template <typename R, typename C>
416 struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R C::*>>
417 : public function_traits<R(C*)>
418 {};
419 template <typename R, typename C, typename... A>
420 struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...)>>
421 : public function_traits<R(C*, A...)>
422 {};
423 template <typename R, typename C, typename... A>
424 struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const>>
425 : public function_traits<R(const C*, A...)>
426 {};
427 template <typename R, typename C, typename... A>
428 struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) volatile>>
429 : public function_traits<R(volatile C*, A...)>
430 {};
431 template <typename R, typename C, typename... A>
432 struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const volatile>>
433 : public function_traits<R(const volatile C*, A...)>
434 {};
435
436 #undef MEM_FN_SYMBOL_XX0SL7G4Z0J
437 #endif
438
439 template <typename T>
440 struct function_traits<T&> : public function_traits<T> {};
441 template <typename T>
442 struct function_traits<const T&> : public function_traits<T> {};
443 template <typename T>
444 struct function_traits<volatile T&> : public function_traits<T> {};
445 template <typename T>
446 struct function_traits<const volatile T&> : public function_traits<T> {};
447 template <typename T>
448 struct function_traits<T&&> : public function_traits<T> {};
449 template <typename T>
450 struct function_traits<const T&&> : public function_traits<T> {};
451 template <typename T>
452 struct function_traits<volatile T&&> : public function_traits<T> {};
453 template <typename T>
454 struct function_traits<const volatile T&&> : public function_traits<T> {};
455
456
457 #define FORWARD_RES_8QR485JMSBT \
458 typename std::conditional< \
459 std::is_lvalue_reference<R>::value, \
460 T&, \
461 typename std::remove_reference<T>::type&& \
462 >::type
463
464 /**
465 .. function:: auto utils::forward_like<Like, T>(T&& t) noexcept
466
467 Forward the reference *t* like the type of *Like*. That means, if *Like* is
468 an lvalue (reference), this function will return an lvalue reference of *t*.
469 Otherwise, if *Like* is an rvalue, this function will return an rvalue
470 reference of *t*.
471
472 This is mainly used to propagate the expression category (lvalue/rvalue) of
473 a member of *Like*, generalizing ``std::forward``.
474 */
475 template <typename R, typename T>
forward_like(T && input)476 FORWARD_RES_8QR485JMSBT forward_like(T&& input) noexcept
477 {
478 return static_cast<FORWARD_RES_8QR485JMSBT>(input);
479 }
480
481 #undef FORWARD_RES_8QR485JMSBT
482
483 /**
484 .. type:: struct utils::copy_cv<From, To>
485
486 Copy the CV qualifier between the two types. For example,
487 ``utils::copy_cv<const int, double>::type`` will become ``const double``.
488 */
489 template <typename From, typename To>
490 struct copy_cv
491 {
492 private:
493 typedef typename std::remove_cv<To>::type raw_To;
494 typedef typename std::conditional<std::is_const<From>::value,
495 const raw_To, raw_To>::type const_raw_To;
496 public:
497 /**
498 .. type:: type type
499
500 Result of cv-copying.
501 */
502 typedef typename std::conditional<std::is_volatile<From>::value,
503 volatile const_raw_To, const_raw_To>::type type;
504 };
505
506 /**
507 .. type:: struct utils::pointee<T>
508
509 Returns the type by derefering an instance of *T*. This is a generalization
510 of ``std::remove_pointer``, that it also works with iterators.
511 */
512 template <typename T>
513 struct pointee
514 {
515 /**
516 .. type:: type type
517
518 Result of dereferencing.
519 */
520 typedef typename std::remove_reference<decltype(*std::declval<T>())>::type type;
521 };
522
523 /**
524 .. function:: std::add_rvalue_reference<T>::type utils::rt_val<T>() noexcept
525
526 Returns a value of type *T*. It is guaranteed to do nothing and will not
527 throw a compile-time error, but using the returned result will cause
528 undefined behavior.
529 */
530 template <typename T>
rt_val()531 typename std::add_rvalue_reference<T>::type rt_val() noexcept
532 {
533 return std::move(*static_cast<T*>(nullptr));
534 }
535
536 #ifdef __GNUC__
537 #pragma GCC diagnostic pop
538 #endif
539
540 }
541 }
542
543 namespace fplus
544 {
545 namespace internal
546 {
547 template <typename>
548 struct is_std_function : std::false_type
549 {
550 };
551
552 template <typename T>
553 struct is_std_function<std::function<T>> : std::true_type
554 {
555 };
556
557 // Those traits are needed to not perform arity checks on a generic-lambd
558 // or a templated/overloaded operator()
559 template <typename T, typename = void>
560 struct has_function_traits : std::false_type
561 {
562 };
563
564 // There is a bug with GCC 7 when a std::function is passed as T.
565 // It produces an ambiguous call between this one and the std::function overload
566 // It's related to our void_t implementation, the C++14 compatible version does not
567 // work, whereas the C++17 one does...
568 //
569 // So, help GCC a bit with is_std_function
570 template <typename T>
571 struct has_function_traits<T,
572 std::enable_if_t<!is_std_function<T>::value,
573 void_t<decltype(&T::operator())>>>
574 : std::true_type
575 {
576 };
577
578 template <typename ReturnType, typename... Args>
579 struct has_function_traits<ReturnType(Args...)> : std::true_type
580 {
581 };
582
583 template <typename ReturnType, typename... Args>
584 struct has_function_traits<ReturnType (*)(Args...)> : std::true_type
585 {
586 };
587
588 template <typename ReturnType, typename ClassType, typename... Args>
589 struct has_function_traits<ReturnType (ClassType::*)(Args...)> : std::true_type
590 {
591 };
592
593 template <typename ReturnType, typename ClassType, typename... Args>
594 struct has_function_traits<ReturnType (ClassType::*)(Args...) const>
595 : std::true_type
596 {
597 };
598
599 template <typename ReturnType, typename ClassType, typename... Args>
600 struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile>
601 : std::true_type
602 {
603 };
604
605 template <typename ReturnType, typename ClassType, typename... Args>
606 struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile>
607 : std::true_type
608 {
609 };
610
611 template <typename ReturnType, typename ClassType, typename... Args>
612 struct has_function_traits<ReturnType (ClassType::*)(Args...)&> : std::true_type
613 {
614 };
615
616 template <typename ReturnType, typename ClassType, typename... Args>
617 struct has_function_traits<ReturnType (ClassType::*)(Args...) const &>
618 : std::true_type
619 {
620 };
621
622 template <typename ReturnType, typename ClassType, typename... Args>
623 struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile&>
624 : std::true_type
625 {
626 };
627
628 template <typename ReturnType, typename ClassType, typename... Args>
629 struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile&>
630 : std::true_type
631 {
632 };
633
634 template <typename ReturnType, typename ClassType, typename... Args>
635 struct has_function_traits<ReturnType (ClassType::*)(Args...) &&>
636 : std::true_type
637 {
638 };
639
640 template <typename ReturnType, typename ClassType, typename... Args>
641 struct has_function_traits<ReturnType (ClassType::*)(Args...) const &&>
642 : std::true_type
643 {
644 };
645
646 template <typename ReturnType, typename ClassType, typename... Args>
647 struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile&&>
648 : std::true_type
649 {
650 };
651
652 template <typename ReturnType, typename ClassType, typename... Args>
653 struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile&&>
654 : std::true_type
655 {
656 };
657
658 template <typename FunctionType>
659 struct has_function_traits<std::function<FunctionType>> : std::true_type
660 {
661 };
662 }
663 }
664
665 #endif
666
667 //
668 // composition.hpp
669 //
670
671 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
672 // https://github.com/Dobiasd/FunctionalPlus
673 // Distributed under the Boost Software License, Version 1.0.
674 // (See accompanying file LICENSE_1_0.txt or copy at
675 // http://www.boost.org/LICENSE_1_0.txt)
676
677
678
679 //
680 // internal/apply.hpp
681 //
682
683 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
684 // https://github.com/Dobiasd/FunctionalPlus
685 // Distributed under the Boost Software License, Version 1.0.
686 // (See accompanying file LICENSE_1_0.txt or copy at
687 // http://www.boost.org/LICENSE_1_0.txt)
688
689
690 #include <tuple>
691 #include <type_traits>
692 #include <utility>
693
694
695 //
696 // internal/invoke.hpp
697 //
698
699 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
700 // https://github.com/Dobiasd/FunctionalPlus
701 // Distributed under the Boost Software License, Version 1.0.
702 // (See accompanying file LICENSE_1_0.txt or copy at
703 // http://www.boost.org/LICENSE_1_0.txt)
704
705
706 #include <functional>
707 #include <type_traits>
708 #include <utility>
709
710
711 // borrowed to libc++
712 #define FPLUS_INVOKE_RETURN(...) \
713 ->decltype(__VA_ARGS__) \
714 { \
715 return __VA_ARGS__; \
716 }
717
718 namespace fplus
719 {
720 namespace internal
721 {
722 // We need std::invoke to detect callable objects
723 //
724 // source:
725 // http://en.cppreference.com/mwiki/index.php?title=cpp/utility/functional/invoke&oldid=82514
726 template <typename U>
727 static std::true_type is_refwrap_test(const std::reference_wrapper<U>&);
728
729 template <typename U>
730 static std::false_type is_refwrap_test(const U&);
731
732 template <typename T>
733 struct is_reference_wrapper : decltype(is_refwrap_test(std::declval<T>()))
734 {
735 };
736
737 template <typename T, typename U = typename std::decay<T>::type>
738 struct unwrap_reference_wrapper
739 {
740 using type = T;
741 };
742
743 template <typename T, typename U>
744 struct unwrap_reference_wrapper<T, std::reference_wrapper<U>>
745 {
746 using type = U&;
747 };
748
749 template <typename T>
750 using unwrap_reference_wrapper_t = typename unwrap_reference_wrapper<T>::type;
751
752 // note: clang only triggers the second static_assert
753 // - static_assert(is_invocable<&base_class::non_const_method, const derived_class&>::value, "");
754 // - static_assert(is_invocable<&base_class::non_const_method, const base_class&>::value, "");
755 // GCC triggers both. To workaround this clang bug, we have to manage cv correctness ourselves
756
757 template <typename T>
758 struct is_const_member_function : std::false_type
759 {
760 };
761
762 // decay doesn't add pointer to abominable functions, don't bother writing them
763 template <typename R, typename... Args>
764 struct is_const_member_function<R(Args...) const> : std::true_type
765 {
766 };
767
768 template <typename R, typename... Args>
769 struct is_const_member_function<R(Args...) const&> : std::true_type
770 {
771 };
772
773 template <typename R, typename... Args>
774 struct is_const_member_function<R(Args...) const&&> : std::true_type
775 {
776 };
777
778 template <typename R, typename... Args>
779 struct is_const_member_function<R(Args...) const volatile> : std::true_type
780 {
781 };
782
783 template <typename R, typename... Args>
784 struct is_const_member_function<R(Args...) const volatile&> : std::true_type
785 {
786 };
787
788 template <typename R, typename... Args>
789 struct is_const_member_function<R(Args...) const volatile&&> : std::true_type
790 {
791 };
792
793 template <typename T>
794 struct is_volatile_member_function : std::false_type
795 {
796 };
797
798 // decay doesn't add pointer to abominable functions, don't bother writing them
799 template <typename R, typename... Args>
800 struct is_volatile_member_function<R(Args...) volatile> : std::true_type
801 {
802 };
803
804 template <typename R, typename... Args>
805 struct is_volatile_member_function<R(Args...) volatile&> : std::true_type
806 {
807 };
808
809 template <typename R, typename... Args>
810 struct is_volatile_member_function<R(Args...) volatile&&> : std::true_type
811 {
812 };
813
814 template <typename R, typename... Args>
815 struct is_volatile_member_function<R(Args...) const volatile> : std::true_type
816 {
817 };
818
819 template <typename R, typename... Args>
820 struct is_volatile_member_function<R(Args...) const volatile&> : std::true_type
821 {
822 };
823
824 template <typename R, typename... Args>
825 struct is_volatile_member_function<R(Args...) const volatile&&> : std::true_type
826 {
827 };
828
829 template <typename Object, typename Signature>
830 struct has_correct_cv
831 {
832 // if object has no cv, every method can be called
833 // else the method must have the same cv than the object
834 static constexpr bool value =
835 std::is_same<typename std::remove_cv<Object>::type, Object>::value ||
836 ((is_volatile_member_function<Signature>::value ==
837 std::is_volatile<Object>::value) &&
838 (is_const_member_function<Signature>::value ==
839 std::is_const<Object>::value));
840 };
841
842 // pointer to member function - reference to object
843 template <
844 typename Base,
845 typename T,
846 typename Derived,
847 typename... Args,
848 typename Unwrapped = unwrap_reference_wrapper_t<Derived>,
849 typename std::enable_if<
850 is_function<T>::value &&
851 has_correct_cv<typename std::remove_reference<Unwrapped>::type, T>::value &&
852 std::is_base_of<Base, typename std::decay<Unwrapped>::type>::value,
853 int>::type = 0>
854 inline auto invoke_impl(T Base::*pmf, Derived&& ref, Args&&... args)
855 FPLUS_INVOKE_RETURN((std::forward<Unwrapped>(ref).*
856 pmf)(std::forward<Args>(args)...))
857
858 // pointer to member function - pointer to object
859 template <
860 typename Base,
861 typename T,
862 typename Pointer,
863 typename... Args,
864 typename std::enable_if<
865 is_function<T>::value &&
866 has_correct_cv<typename std::remove_pointer<
867 typename std::decay<Pointer>::type>::type,
868 T>::value &&
869 !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
870 int>::type = 0>
871 inline auto invoke_impl(T Base::*pmf, Pointer&& ptr, Args&&... args)
872 FPLUS_INVOKE_RETURN(((*std::forward<Pointer>(ptr)).*
873 pmf)(std::forward<Args>(args)...))
874
875 // pointer to non-static data member - reference to object
876 template <
877 typename Base,
878 typename T,
879 typename Derived,
880 typename Unwrapped = unwrap_reference_wrapper_t<Derived>,
881 typename std::enable_if<
882 !is_function<T>::value &&
883 std::is_base_of<Base, typename std::decay<Unwrapped>::type>::value,
884 int>::type = 0>
885 inline auto invoke_impl(T Base::*pmd, Derived&& ref)
886 FPLUS_INVOKE_RETURN((std::forward<Unwrapped>(ref).*pmd))
887
888 // pointer to non-static data member - pointer to object
889 template <
890 typename Base,
891 typename T,
892 typename Pointer,
893 typename std::enable_if<
894 !is_function<T>::value &&
895 !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
896 int>::type = 0>
897 inline auto invoke_impl(T Base::*pmd, Pointer&& ptr)
898 FPLUS_INVOKE_RETURN((*std::forward<Pointer>(ptr)).*pmd)
899
900 // normal case - functions, lambdas, function objects
901 template <typename F,
902 typename... Args,
903 typename std::enable_if<
904 !std::is_member_pointer<typename std::decay<F>::type>::value,
905 int>::type = 0>
906 inline auto invoke_impl(F&& f, Args&&... args)
907 FPLUS_INVOKE_RETURN((std::forward<F>(f)(std::forward<Args>(args)...)))
908
909 template <typename AlwaysVoid, typename, typename...>
910 struct invoke_result_impl
911 {
912 };
913
914 template <typename F, typename... Args>
915 struct invoke_result_impl<decltype(void(invoke_impl(std::declval<F>(),
916 std::declval<Args>()...))),
917 F,
918 Args...>
919 {
920 using type =
921 decltype(invoke_impl(std::declval<F>(), std::declval<Args>()...));
922 };
923
924 template <typename F, typename... ArgTypes>
925 struct invoke_result : invoke_result_impl<void, F, ArgTypes...>
926 {
927 };
928
929 template <typename F, typename... Args>
930 using invoke_result_t = typename invoke_result<F, Args...>::type;
931
932 // noexcept omitted on purpose, cannot be implemented without C++17.
933 // GCC 7.1 works with libstdc++, but clang fails, even with latest build,
934 // on both libstdc++/libc++, I suspect an internal compiler trait is at
935 // play to make GCC work.
936 //
937 // We could detect if C++17 is used and use std::invoke directly.
938 template <typename F, typename... ArgTypes>
invoke(F && f,ArgTypes &&...args)939 invoke_result_t<F, ArgTypes...> invoke(F&& f, ArgTypes&&... args)
940 {
941 return invoke_impl(std::forward<F>(f), std::forward<ArgTypes>(args)...);
942 }
943
944 // Invoke useful traits (libstdc++ 7.1.0's implementation, ugly-case removed)
945 template <typename Result, typename ReturnType, typename = void>
946 struct is_invocable_impl : std::false_type
947 {
948 };
949
950 template <typename Result, typename ReturnType>
951 struct is_invocable_impl<Result, ReturnType, void_t<typename Result::type>>
952 : disjunction<std::is_void<ReturnType>,
953 std::is_convertible<typename Result::type, ReturnType>>::type
954 {
955 };
956
957 template <typename F, typename... ArgTypes>
958 struct is_invocable
959 : is_invocable_impl<invoke_result<F, ArgTypes...>, void>::type
960 {
961 };
962
963 template <typename ReturnType, typename F, typename... ArgTypes>
964 struct is_invocable_r
965 : is_invocable_impl<invoke_result<F, ArgTypes...>, ReturnType>::type
966 {
967 };
968 }
969 }
970
971 #undef FPLUS_INVOKE_RETURN
972
973 namespace fplus
974 {
975 namespace internal
976 {
977 // C++17 std::apply (http://en.cppreference.com/w/cpp/utility/apply)
978 template <typename F, typename Tuple, std::size_t... I>
apply_impl(F && f,Tuple && t,std::index_sequence<I...>)979 constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
980 {
981 return internal::invoke(std::forward<F>(f),
982 std::get<I>(std::forward<Tuple>(t))...);
983 }
984
985 template <typename F, typename Tuple>
apply(F && f,Tuple && t)986 constexpr decltype(auto) apply(F&& f, Tuple&& t)
987 {
988 return internal::apply_impl(
989 std::forward<F>(f),
990 std::forward<Tuple>(t),
991 std::make_index_sequence<
992 std::tuple_size<std::decay_t<Tuple>>::value>{});
993 }
994 }
995 }
996
997 //
998 // internal/asserts/functions.hpp
999 //
1000
1001 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
1002 // https://github.com/Dobiasd/FunctionalPlus
1003 // Distributed under the Boost Software License, Version 1.0.
1004 // (See accompanying file LICENSE_1_0.txt or copy at
1005 // http://www.boost.org/LICENSE_1_0.txt)
1006
1007
1008
1009 //
1010 // internal/function_traits_asserts.hpp
1011 //
1012
1013 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
1014 // https://github.com/Dobiasd/FunctionalPlus
1015 // Distributed under the Boost Software License, Version 1.0.
1016 // (See accompanying file LICENSE_1_0.txt or copy at
1017 // http://www.boost.org/LICENSE_1_0.txt)
1018
1019
1020
1021 namespace fplus
1022 {
1023 namespace internal
1024 {
1025 template <typename T, typename...>
1026 struct function_traits_asserts;
1027
1028 template <
1029 typename,
1030 typename F,
1031 typename... Args,
1032 typename std::enable_if<is_invocable<F, Args...>::value, int>::type = 0>
trigger_static_asserts()1033 constexpr void trigger_static_asserts()
1034 {
1035 }
1036
1037 // Marks a variable as unused. Prevents the compiler warning
1038 // for set but unused variables.
1039 template<class T>
unused(T &&)1040 inline void unused(T&&) { }
1041
1042 template <typename Tag,
1043 typename F,
1044 typename... Args,
1045 typename std::enable_if<has_function_traits<F>::value &&
1046 !is_invocable<F, Args...>::value,
1047 int>::type = 0>
trigger_static_asserts()1048 constexpr void trigger_static_asserts()
1049 {
1050 // don't perform checks if function_traits<F> doesn't exist
1051 unused(function_traits_asserts<Tag, F, Args...>{});
1052 }
1053
1054 template <typename,
1055 typename F,
1056 typename... Args,
1057 typename std::enable_if<!has_function_traits<F>::value &&
1058 !is_invocable<F, Args...>::value,
1059 int>::type = 0>
trigger_static_asserts()1060 constexpr void trigger_static_asserts()
1061 {
1062 static_assert(sizeof(F) == 0,
1063 "F is not a Callable, or its definition is ill-formed");
1064 }
1065 }
1066 }
1067
1068 namespace fplus
1069 {
1070 namespace internal
1071 {
1072
1073 struct nullary_function_tag
1074 {
1075 };
1076
1077 struct unary_function_tag
1078 {
1079 };
1080
1081 struct binary_function_tag
1082 {
1083 };
1084
1085 struct binary_predicate_tag
1086 {
1087 };
1088
1089 struct check_arity_tag
1090 {
1091 };
1092
1093 template <typename F>
1094 struct function_traits_asserts<nullary_function_tag, F>
1095 {
1096 static_assert(utils::function_traits<F>::arity == 0,
1097 "Function must take no parameters.");
1098 };
1099
1100 template <typename F, typename X>
1101 struct function_traits_asserts<unary_function_tag, F, X>
1102 {
1103 static_assert(utils::function_traits<F>::arity == 1,
1104 "Function must take one parameter.");
1105 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1106 static_assert(std::is_convertible<X, FIn0>::value,
1107 "Invalid argument type for function");
1108 };
1109
1110 template <typename F>
1111 struct function_traits_asserts<binary_function_tag, F>
1112 {
1113 static_assert(utils::function_traits<F>::arity == 2,
1114 "Function must take two parameters.");
1115 };
1116
1117 template <typename F, typename X, typename Y>
1118 struct function_traits_asserts<binary_function_tag, F, X ,Y>
1119 {
1120 static_assert(utils::function_traits<F>::arity == 2,
1121 "Function must take two parameters.");
1122 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1123 static_assert(std::is_convertible<X, FIn0>::value,
1124 "Invalid first argument type for function");
1125 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1126 static_assert(std::is_convertible<Y, FIn1>::value,
1127 "Invalid second argument type for function");
1128 };
1129
1130 template <typename F>
1131 struct function_traits_asserts<binary_predicate_tag, F>
1132 {
1133 static_assert(utils::function_traits<F>::arity == 2,
1134 "Function must take two parameters.");
1135 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1136 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1137 static_assert(std::is_same<FIn0, FIn1>::value,
1138 "Both parameters must have the same type.");
1139 static_assert(std::is_same<std::decay_t<internal::invoke_result_t<F, FIn0, FIn1>>, bool>::value,
1140 "Predicate must return bool.");
1141 };
1142
1143 template <typename F, typename... Args>
1144 struct function_traits_asserts<check_arity_tag, F, Args...>
1145 {
1146 static_assert(utils::function_traits<F>::arity == sizeof...(Args),
1147 "Wrong arity.");
1148 };
1149
1150 }
1151 }
1152
1153 //
1154 // internal/asserts/composition.hpp
1155 //
1156
1157 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
1158 // https://github.com/Dobiasd/FunctionalPlus
1159 // Distributed under the Boost Software License, Version 1.0.
1160 // (See accompanying file LICENSE_1_0.txt or copy at
1161 // http://www.boost.org/LICENSE_1_0.txt)
1162
1163
1164
1165 namespace fplus
1166 {
1167 namespace internal
1168 {
1169
1170 struct bind_1st_of_2_tag
1171 {
1172 };
1173
1174 struct bind_2nd_of_2_tag
1175 {
1176 };
1177
1178 struct bind_1st_of_3_tag
1179 {
1180 };
1181
1182 struct bind_1st_and_2nd_of_3_tag
1183 {
1184 };
1185
1186 struct bind_2nd_and_3rd_of_3_tag
1187 {
1188 };
1189
1190 template <typename F, typename X, typename Y>
1191 struct function_traits_asserts<bind_1st_of_2_tag, F, X, Y>
1192 {
1193 static_assert(utils::function_traits<F>::arity == 2,
1194 "Function must take two parameters.");
1195 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1196 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1197 static_assert(std::is_convertible<X, FIn0>::value,
1198 "Function can not take bound parameter type");
1199 static_assert(std::is_convertible<Y, FIn1>::value,
1200 "Function can not take provided parameter type");
1201 };
1202
1203 template <typename F, typename X, typename Y>
1204 struct function_traits_asserts<bind_2nd_of_2_tag, F, X, Y>
1205 {
1206 static_assert(utils::function_traits<F>::arity == 2,
1207 "Function must take two parameters.");
1208 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1209 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1210 static_assert(std::is_convertible<X, FIn0>::value,
1211 "Function can not take provided parameter type");
1212 static_assert(std::is_convertible<Y, FIn1>::value,
1213 "Function can not take bound parameter type");
1214 };
1215
1216 template <typename F, typename X, typename Y, typename Z>
1217 struct function_traits_asserts<bind_1st_of_3_tag, F, X, Y, Z>
1218 {
1219 static_assert(utils::function_traits<F>::arity == 3,
1220 "Function must take three parameters.");
1221 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1222 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1223 typedef typename utils::function_traits<F>::template arg<2>::type FIn2;
1224 static_assert(std::is_convertible<X, FIn0>::value,
1225 "Function can not take bound parameter type");
1226 static_assert(std::is_convertible<Y, FIn1>::value,
1227 "Function can not take provided first parameter type");
1228 static_assert(std::is_convertible<Z, FIn2>::value,
1229 "Function can not take provided second parameter type");
1230 };
1231
1232 template <typename F, typename X, typename Y, typename Z>
1233 struct function_traits_asserts<bind_1st_and_2nd_of_3_tag, F, X, Y, Z>
1234 {
1235 static_assert(utils::function_traits<F>::arity == 3,
1236 "Function must take three parameters.");
1237 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1238 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1239 typedef typename utils::function_traits<F>::template arg<2>::type FIn2;
1240 static_assert(std::is_convertible<X, FIn0>::value,
1241 "Function can not take first bound parameter type");
1242 static_assert(std::is_convertible<Y, FIn1>::value,
1243 "Function can not take second bound parameter type");
1244 static_assert(std::is_convertible<Z, FIn2>::value,
1245 "Function can not take provided parameter type");
1246 };
1247
1248 template <typename F, typename X, typename Y, typename Z>
1249 struct function_traits_asserts<bind_2nd_and_3rd_of_3_tag, F, X, Y, Z>
1250 {
1251 static_assert(utils::function_traits<F>::arity == 3,
1252 "Function must take three parameters.");
1253 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
1254 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
1255 typedef typename utils::function_traits<F>::template arg<2>::type FIn2;
1256 static_assert(std::is_convertible<X, FIn0>::value,
1257 "Function can not take provided parameter type");
1258 static_assert(std::is_convertible<Y, FIn1>::value,
1259 "Function can not take second bound parameter type");
1260 static_assert(std::is_convertible<Z, FIn2>::value,
1261 "Function can not take first bound parameter type");
1262 };
1263
1264 }
1265 }
1266
1267 //
1268 // internal/composition.hpp
1269 //
1270
1271 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
1272 // https://github.com/Dobiasd/FunctionalPlus
1273 // Distributed under the Boost Software License, Version 1.0.
1274 // (See accompanying file LICENSE_1_0.txt or copy at
1275 // http://www.boost.org/LICENSE_1_0.txt)
1276
1277
1278 #include <tuple>
1279 #include <utility>
1280
1281
1282 namespace fplus
1283 {
1284 namespace internal
1285 {
1286 // source: https://codereview.stackexchange.com/a/63893
1287 // note: the code in the link above is called with the arguments in reverse order
1288 template <typename... Fs>
1289 class compose_impl
1290 {
1291 static constexpr std::size_t size = sizeof...(Fs);
1292 static_assert(size > 1,
1293 "Invalid number of functions to compose, minimum is two.");
1294
1295 public:
compose_impl(Fs &&...fs)1296 compose_impl(Fs&&... fs) : _functionTuple(std::forward<Fs>(fs)...)
1297 {
1298 }
1299
1300 template <typename... Ts>
operator ()(Ts &&...ts) const1301 auto operator()(Ts&&... ts) const
1302 {
1303 return _apply(std::integral_constant<std::size_t, 0>{},
1304 std::forward<Ts>(ts)...);
1305 }
1306
1307 private:
1308 template <std::size_t N, typename... Ts>
_apply(std::integral_constant<std::size_t,N>,Ts &&...ts) const1309 auto _apply(std::integral_constant<std::size_t, N>, Ts&&... ts) const
1310 {
1311 return _apply(std::integral_constant<std::size_t, N + 1>{},
1312 std::get<N>(_functionTuple)(std::forward<Ts>(ts)...));
1313 }
1314
1315 template <typename... Ts>
_apply(std::integral_constant<std::size_t,size-1>,Ts &&...ts) const1316 auto _apply(std::integral_constant<std::size_t, size - 1>, Ts&&... ts) const
1317 {
1318 return internal::invoke(std::get<size - 1>(_functionTuple),
1319 std::forward<Ts>(ts)...);
1320 }
1321
1322 std::tuple<Fs...> _functionTuple;
1323 };
1324
1325 // Is BinaryLift really correct?
1326 template <typename Tuple, typename BinaryLift>
compose_binary_lift_impl(std::integral_constant<std::size_t,1>,const Tuple & tup,const BinaryLift & lifter)1327 auto compose_binary_lift_impl(std::integral_constant<std::size_t, 1>,
1328 const Tuple& tup,
1329 const BinaryLift& lifter)
1330 {
1331 return lifter(std::get<0>(tup), std::get<1>(tup));
1332 }
1333
1334 template <std::size_t N, typename Tuple, typename BinaryLift>
compose_binary_lift_impl(std::integral_constant<std::size_t,N>,const Tuple & tup,const BinaryLift & lifter)1335 auto compose_binary_lift_impl(std::integral_constant<std::size_t, N>,
1336 const Tuple& tup,
1337 const BinaryLift& lifter)
1338 {
1339 return lifter(
1340 compose_binary_lift_impl(
1341 std::integral_constant<std::size_t, N - 1>{}, tup, lifter),
1342 std::get<N>(tup));
1343 }
1344
1345 template <typename BinaryLift, typename... Callables>
compose_binary_lift(const BinaryLift & lifter,Callables &&...args)1346 auto compose_binary_lift(const BinaryLift& lifter, Callables&&... args)
1347 {
1348 static_assert(sizeof...(Callables) > 1,
1349 "Invalid number of functions to compose, minimum is two.");
1350 const auto tup = std::forward_as_tuple(std::forward<Callables>(args)...);
1351 return compose_binary_lift_impl(
1352 std::integral_constant<std::size_t, sizeof...(Callables) - 1>{},
1353 tup,
1354 lifter);
1355 }
1356
1357 // concentrate asserts in this method. Lambda is provided by the library.
1358 template <typename Lambda, typename F, typename G>
logical_binary_op(Lambda op,F f,G g)1359 auto logical_binary_op(Lambda op, F f, G g)
1360 {
1361 // Perfect-forwarding might move twice, if we add a requirement on F and G,
1362 // that might not be an issue.
1363 return [op, f, g](auto x) {
1364 internal::trigger_static_asserts<internal::unary_function_tag,
1365 F,
1366 decltype(x)>();
1367 internal::trigger_static_asserts<internal::unary_function_tag,
1368 G,
1369 decltype(x)>();
1370 using FRes = std::decay_t<internal::invoke_result_t<F, decltype(x)>>;
1371 using GRes = std::decay_t<internal::invoke_result_t<G, decltype(x)>>;
1372 static_assert(std::is_same<FRes, bool>::value, "Must return bool.");
1373 static_assert(std::is_same<GRes, bool>::value, "Must return bool.");
1374
1375 return op(f, g, x);
1376 };
1377 }
1378 }
1379 }
1380
1381 #include <functional>
1382 #include <map>
1383 #include <memory>
1384 #include <type_traits>
1385 #include <unordered_map>
1386 #include <utility>
1387
1388 namespace fplus
1389 {
1390
1391 // API search type: bind_1st_of_2 : (((a, b) -> c), a) -> (b -> c)
1392 // Bind first parameter of binary function.
1393 template <typename F, typename T>
bind_1st_of_2(F f,T x)1394 auto bind_1st_of_2(F f, T x)
1395 {
1396 return [f, x](auto&& y) {
1397 internal::trigger_static_asserts<internal::bind_1st_of_2_tag,
1398 F,
1399 T,
1400 decltype(y)>();
1401 return internal::invoke(f, x, std::forward<decltype(y)>(y));
1402 };
1403 }
1404
1405 // API search type: bind_2nd_of_2 : (((a, b) -> c), b) -> (a -> c)
1406 // Bind second parameter of binary function.
1407 template <typename F, typename T>
bind_2nd_of_2(F f,T y)1408 auto bind_2nd_of_2(F f, T y)
1409 {
1410 return [f, y](auto&& x) {
1411 internal::trigger_static_asserts<internal::bind_2nd_of_2_tag,
1412 F,
1413 decltype(x),
1414 T>();
1415 return internal::invoke(f, std::forward<decltype(x)>(x), y);
1416 };
1417 }
1418
1419 // API search type: bind_1st_of_3 : (((a, b, c) -> d), a) -> ((b, c) -> d)
1420 // Bind first parameter of ternary function.
1421 template <typename F, typename X>
bind_1st_of_3(F f,X x)1422 auto bind_1st_of_3(F f, X x)
1423 {
1424 return [f, x](auto&& y, auto&& z) {
1425 internal::trigger_static_asserts<internal::bind_1st_of_3_tag,
1426 F,
1427 X,
1428 decltype(y),
1429 decltype(z)>();
1430 return internal::invoke(
1431 f, x, std::forward<decltype(y)>(y), std::forward<decltype(z)>(z));
1432 };
1433 }
1434
1435 // API search type: bind_1st_and_2nd_of_3 : (((a, b, c) -> d), a, b) -> (c -> d)
1436 // Bind first and second parameter of ternary function.
1437 template <typename F, typename X, typename Y>
bind_1st_and_2nd_of_3(F f,X x,Y y)1438 auto bind_1st_and_2nd_of_3(F f, X x, Y y)
1439 {
1440 return [f, x, y](auto&& z) {
1441 internal::trigger_static_asserts<internal::bind_1st_and_2nd_of_3_tag,
1442 F,
1443 X,
1444 Y,
1445 decltype(z)>();
1446 return internal::invoke(f, x, y, std::forward<decltype(z)>(z));
1447 };
1448 }
1449
1450 // API search type: bind_2nd_and_3rd_of_3 : (((a, b, c) -> d), b, c) -> (a -> d)
1451 // Bind first and second parameter of ternary function.
1452 template <typename F, typename Y, typename Z>
bind_2nd_and_3rd_of_3(F f,Y y,Z z)1453 auto bind_2nd_and_3rd_of_3(F f, Y y, Z z)
1454 {
1455 return [f, y, z](auto&& x) {
1456 internal::trigger_static_asserts<internal::bind_2nd_and_3rd_of_3_tag,
1457 F,
1458 decltype(x),
1459 Y,
1460 Z>();
1461 return internal::invoke(f, std::forward<decltype(x)>(x), y, z);
1462 };
1463 }
1464
1465 // API search type: flip : (a -> b) -> (b -> a)
1466 // Flips the arguments of a binary function
1467 // Note: The callable can take a variadic number of arguments
1468 template <typename F>
flip(F f)1469 auto flip(F f)
1470 {
1471 return [f](auto&&... args) {
1472 return internal::apply_impl(
1473 f,
1474 std::forward_as_tuple(std::forward<decltype(args)>(args)...),
1475 internal::make_reverse_index_sequence<sizeof...(args)>{});
1476 };
1477 }
1478
1479 // API search type: forward_apply : (a, (a -> b)) -> b
1480 // Forward application.
1481 // Returns the result of applying the function f to the value x.
1482 template <typename X, typename F>
forward_apply(X && x,F f)1483 auto forward_apply(X&& x, F f)
1484 {
1485 internal::trigger_static_asserts<internal::unary_function_tag, F, X>();
1486 return internal::invoke(f, std::forward<X>(x));
1487 }
1488
1489 // API search type: lazy : ((a -> b), a) -> (() -> b)
1490 // Lazy evaluation.
1491 // Returns a function evaluating f with the given arguments when called.
1492 // Also known as defer.
1493 // Note: f can take a variadic number of parameters
1494 template<typename F, typename... Args>
lazy(F f,Args...args)1495 auto lazy(F f, Args ... args)
1496 {
1497 return [f, args...] {
1498 internal::trigger_static_asserts<internal::check_arity_tag, F, Args...>();
1499 return internal::invoke(f, args...);
1500 };
1501 }
1502
1503 // API search type: fixed : a -> (() -> a)
1504 // Identity as a nullary function.
1505 // Returns a function returning x when called.
1506 // Like lazy with identity as f.
1507 template<typename T>
fixed(T x)1508 auto fixed(T x)
1509 {
1510 return [x]() -> T
1511 {
1512 return x;
1513 };
1514 }
1515
1516 // API search type: compose : ((a -> b), (b -> c)) -> (a -> c)
1517 // Forward function composition.
1518 // compose(f, g)(x) = g(f(x))
1519 // It is possible to compose a variadic number of callables.
1520 // The first callable can also take a variadic number of parameters.
1521 // compose(f, g, h)(x, y, z) = h(g(f(x, y, z)))
1522 template <typename... Fs>
compose(Fs &&...fs)1523 auto compose(Fs&&... fs)
1524 {
1525 return internal::compose_impl<Fs...>(std::forward<Fs>(fs)...);
1526 }
1527
1528 // API search type: logical_not : (a -> Bool) -> (a -> Bool)
1529 // Converts a predicate p into a new one,
1530 // always returning the exact opposite of p.
1531 // logical_not(f) = \x -> !x
1532 // Note: F can take a variadic number of parameters.
1533 // Equivalent to std::not_fn (C++17)
1534 template <typename Predicate>
logical_not(Predicate f)1535 auto logical_not(Predicate f)
1536 {
1537 return [f](auto&&... args) {
1538 internal::trigger_static_asserts<internal::unary_function_tag,
1539 Predicate,
1540 decltype(args)...>();
1541 using Res =
1542 std::decay_t<internal::invoke_result_t<Predicate, decltype(args)...>>;
1543 static_assert(std::is_same<Res, bool>::value, "Function must return bool.");
1544
1545 return !internal::invoke(f, std::forward<decltype(args)>(args)...);
1546 };
1547 }
1548
1549 // API search type: logical_or : ((a -> Bool), (a -> Bool)) -> (a -> Bool)
1550 // logical_or(f, g) = \x -> f(x) or g(x)
1551 // Combines to unary predicates into a single one
1552 // that holds true if at least one of the original predicated is true.
1553 template <typename UnaryPredicateF, typename UnaryPredicateG>
logical_or(UnaryPredicateF f,UnaryPredicateG g)1554 auto logical_or(UnaryPredicateF f, UnaryPredicateG g)
1555 {
1556 auto op = [](auto f1, auto f2, auto x) {
1557 return internal::invoke(f1, x) || internal::invoke(f2, x);
1558 };
1559
1560 return internal::logical_binary_op(op, f, g);
1561 }
1562
1563 // API search type: logical_and : ((a -> Bool), (a -> Bool)) -> (a -> Bool)
1564 // logical_and(f, g) = \x -> f(x) and g(x)
1565 // Combines to unary predicates into a single one
1566 // that holds true if both original predicated are true.
1567 template <typename UnaryPredicateF, typename UnaryPredicateG>
logical_and(UnaryPredicateF f,UnaryPredicateG g)1568 auto logical_and(UnaryPredicateF f, UnaryPredicateG g)
1569 {
1570 auto op = [](auto f1, auto f2, auto x) {
1571 return internal::invoke(f1, x) && internal::invoke(f2, x);
1572 };
1573
1574 return internal::logical_binary_op(op, f, g);
1575 }
1576
1577 // API search type: logical_xor : ((a -> Bool), (a -> Bool)) -> (a -> Bool)
1578 // logical_xor(f, g) = \x -> f(x) xor g(x)
1579 // Combines to unary predicates into a single one
1580 // that holds true if exactly one of the original predicated is true.
1581 template <typename UnaryPredicateF, typename UnaryPredicateG>
logical_xor(UnaryPredicateF f,UnaryPredicateG g)1582 auto logical_xor(UnaryPredicateF f, UnaryPredicateG g)
1583 {
1584 auto op = [](auto f1, auto f2, auto x) {
1585 return internal::invoke(f1, x) != internal::invoke(f2, x);
1586 };
1587
1588 return internal::logical_binary_op(op, f, g);
1589 }
1590
1591 // API search type: memoize : (a -> b) -> (a -> b)
1592 // Provides Memoization for a given (referentially transparent)
1593 // unary function.
1594 // Returns a closure mutating an internally held dictionary
1595 // mapping input values to output values.
1596 template <typename F,
1597 typename FIn = typename utils::function_traits<F>::template arg<0>::type,
1598 typename FOut = typename std::result_of<F(FIn)>::type,
1599 typename MemoMap = std::unordered_map<
1600 typename std::remove_reference<typename std::remove_const<FIn>::type>::type,
1601 FOut>>
memoize(F f)1602 std::function<FOut(FIn)> memoize(F f)
1603 {
1604 static_assert(utils::function_traits<F>::arity == 1, "Wrong arity.");
1605 MemoMap storage;
1606 return [=](FIn x) mutable -> FOut
1607 {
1608 const auto it = storage.find(x);
1609 if (it == storage.end())
1610 {
1611 return storage.emplace(x, internal::invoke(f, x)).first->second;
1612 }
1613 else
1614 {
1615 return it->second;
1616 }
1617 };
1618 }
1619
1620 namespace internal
1621 {
1622 template <typename F, typename Cache,
1623 typename FIn1 = typename utils::function_traits<F>::template arg<0>::type,
1624 typename FIn2 = typename utils::function_traits<F>::template arg<1>::type,
1625 typename FOut = typename std::result_of<F(FIn1, FIn2)>::type,
1626 typename ResultF = std::function<FOut(FIn2)>>
memoize_recursive_helper(const F f,std::shared_ptr<Cache> storage)1627 ResultF memoize_recursive_helper(const F f, std::shared_ptr<Cache> storage)
1628 {
1629 return [f, storage](FIn2 x)
1630 {
1631 const auto it = storage->find(x);
1632 if (it == storage->end())
1633 {
1634 const auto g = memoize_recursive_helper(f, storage);
1635 (*storage)[x] = f(g, x);
1636 }
1637 return (*storage)[x];
1638 };
1639 }
1640 } // namespace internal
1641
1642 // API search type: memoize_recursive : (a -> b) -> (a -> b)
1643 // Provides Memoization for a given (referentially transparent)
1644 // recursive binary function that takes a continuation as first argument.
1645 // e.g.
1646 // uint64_t fibo_cont(const std::function<uint64_t(uint64_t)>& cont, uint64_t n)
1647 // {
1648 // if (n < 2) return n;
1649 // else return cont(n-1) + cont(n-2);
1650 // }
1651 // Returns a closure mutating an internally held dictionary
1652 // mapping input values to output values.
1653 template <typename F,
1654 typename FIn1 = typename utils::function_traits<F>::template arg<0>::type,
1655 typename FIn2 = typename utils::function_traits<F>::template arg<1>::type,
1656 typename FOut = typename std::result_of<F(FIn1, FIn2)>::type,
1657 typename MemoMap = std::unordered_map<
1658 typename std::remove_reference<typename std::remove_const<FIn2>::type>::type,
1659 FOut>>
memoize_recursive(F f)1660 std::function<FOut(FIn2)> memoize_recursive(F f)
1661 {
1662 std::shared_ptr<MemoMap> storage = std::make_shared<MemoMap>();
1663 return internal::memoize_recursive_helper(f, storage);
1664 }
1665
1666 // API search type: memoize_binary : ((a, b) -> c) -> ((a, b) -> c)
1667 // Provides Memoization for a given (referentially transparent)
1668 // binary function.
1669 // Returns a closure mutating an internally held dictionary
1670 // mapping input values to output values.
1671 template <typename F,
1672 typename FIn1 = typename utils::function_traits<F>::template arg<0>::type,
1673 typename FIn2 = typename utils::function_traits<F>::template arg<1>::type,
1674 typename FOut = typename std::result_of<F(FIn1, FIn2)>::type,
1675 typename ParamPair = std::pair<
1676 typename std::remove_reference<typename std::remove_const<FIn1>::type>::type,
1677 typename std::remove_reference<typename std::remove_const<FIn2>::type>::type>,
1678 typename MemoMap = std::unordered_map<ParamPair, FOut>>
memoize_binary(F f)1679 std::function<FOut(FIn1, FIn2)> memoize_binary(F f)
1680 {
1681 const auto unary_f = [f](const ParamPair& params) -> FOut
1682 {
1683 return internal::invoke(f, params.first, params.second);
1684 };
1685 auto unary_f_memoized = memoize<decltype(unary_f),
1686 ParamPair, FOut, std::map<ParamPair, FOut>>(unary_f);
1687 return [unary_f_memoized](FIn1 a, FIn2 b) mutable -> FOut
1688 {
1689 return unary_f_memoized(std::make_pair(a, b));
1690 };
1691 }
1692
1693 // API search type: constructor_as_function : a -> b
1694 // struct foo
1695 // {
1696 // foo(int a, int b) : a_(a), b_(2*b) {}
1697 // int a_;
1698 // int b_;
1699 // };
1700 // const auto create_foo = constructor_as_function<foo, int, int>;
1701 // create_foo(1,2) == foo(1, 2);
1702 template <typename T, class ... Types>
1703 T constructor_as_function(Types ... args)
1704 {
1705 return T(args...);
1706 }
1707
1708 } // namespace fplus
1709
1710 #define fplus_get_mem(fplus_get_mem_name) \
1711 [](const auto& fplus_get_mem_x) \
1712 { \
1713 return fplus_get_mem_x.fplus_get_mem_name; \
1714 }
1715
1716 #define fplus_get_ptr_mem(fplus_get_ptr_mem_name) \
1717 [](const auto& fplus_get_ptr_mem_x) \
1718 { \
1719 return fplus_get_ptr_mem_x->fplus_get_ptr_mem_name; \
1720 }
1721
1722 #define fplus_get_c_mem_t(fplus_get_c_mem_t_c, fplus_get_c_mem_t_name, fplus_get_c_mem_t_t) \
1723 [](const fplus_get_c_mem_t_c& fplus_get_c_mem_t_x) -> fplus_get_c_mem_t_t \
1724 { \
1725 return fplus_get_c_mem_t_x.fplus_get_c_mem_t_name; \
1726 }
1727
1728 #define fplus_get_c_ptr_mem_t(fplus_get_c_ptr_mem_t_c, fplus_get_c_ptr_mem_t_name, fplus_get_c_ptr_mem_t_t) \
1729 [](const fplus_get_c_ptr_mem_t_c& fplus_get_c_ptr_mem_t_x) -> fplus_get_c_ptr_mem_t_t \
1730 { \
1731 return fplus_get_c_ptr_mem_t_x->fplus_get_c_ptr_mem_t_name; \
1732 }
1733
1734 #define fplus_mem_fn(fplus_mem_fn_name) \
1735 [](const auto& fplus_mem_fn_x) \
1736 { \
1737 return fplus_mem_fn_x.fplus_mem_fn_name(); \
1738 }
1739
1740 #define fplus_ptr_mem_fn(fplus_ptr_mem_fn_name) \
1741 [](const auto& fplus_ptr_mem_fn_x) \
1742 { \
1743 return fplus_ptr_mem_fn_x->fplus_ptr_mem_fn_name(); \
1744 }
1745
1746 #define fplus_c_mem_fn_t(fplus_c_mem_fn_t_c, fplus_c_mem_fn_t_name, fplus_c_mem_fn_t_t) \
1747 [](const fplus_c_mem_fn_t_c& fplus_c_mem_fn_t_x) -> fplus_c_mem_fn_t_t \
1748 { \
1749 return fplus_c_mem_fn_t_x.fplus_c_mem_fn_t_name(); \
1750 }
1751
1752 #define fplus_c_ptr_mem_fn_t(fplus_c_ptr_mem_fn_t_c, fplus_c_ptr_mem_fn_t_name, fplus_c_ptr_mem_fn_t_t) \
1753 [](const fplus_c_ptr_mem_fn_t_c& fplus_c_ptr_mem_fn_t_x) -> fplus_c_ptr_mem_fn_t_t \
1754 { \
1755 return fplus_c_ptr_mem_fn_t_x->fplus_c_ptr_mem_fn_t_name(); \
1756 }
1757
1758
1759 //
1760 // internal/compare.hpp
1761 //
1762
1763 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
1764 // https://github.com/Dobiasd/FunctionalPlus
1765 // Distributed under the Boost Software License, Version 1.0.
1766 // (See accompanying file LICENSE_1_0.txt or copy at
1767 // http://www.boost.org/LICENSE_1_0.txt)
1768
1769
1770 #include <type_traits>
1771
1772
1773 namespace fplus
1774 {
1775 namespace internal
1776 {
1777 template <typename Compare>
ord_to_impl(Compare comp)1778 auto ord_to_impl(Compare comp)
1779 {
1780 return [comp](auto x, auto y)
1781 {
1782 static_assert(std::is_same<decltype(x), decltype(y)>::value,
1783 "Argument types must be the same");
1784 using In = decltype(x);
1785 internal::trigger_static_asserts<internal::binary_predicate_tag, Compare, In, In>();
1786
1787 using CompareOut = std::decay_t<internal::invoke_result_t<Compare, In, In>>;
1788 static_assert(std::is_same<CompareOut, bool>::value,
1789 "Function must return bool.");
1790 return std::make_pair(internal::invoke(comp, x, y),
1791 internal::invoke(comp, y, x));
1792 };
1793 }
1794 }
1795 }
1796
1797 namespace fplus
1798 {
1799
1800 namespace internal
1801 {
1802 template <typename UnaryPredicate, typename T>
check_unary_predicate_for_type()1803 void check_unary_predicate_for_type()
1804 {
1805 internal::trigger_static_asserts<internal::unary_function_tag, UnaryPredicate, T>();
1806 static_assert(std::is_convertible<
1807 internal::invoke_result_t<UnaryPredicate, T>, bool>::value,
1808 "Predicate must return bool.");
1809 }
1810 template <typename F, typename G, typename X, typename Y>
check_compare_preprocessors_for_types()1811 void check_compare_preprocessors_for_types()
1812 {
1813 internal::trigger_static_asserts<internal::unary_function_tag, F, X>();
1814 internal::trigger_static_asserts<internal::unary_function_tag, G, Y>();
1815 static_assert(std::is_same<
1816 std::decay_t<internal::invoke_result_t<F, X>>,
1817 std::decay_t<internal::invoke_result_t<G, Y>>>::value,
1818 "Both functions must return the same type.");
1819 }
1820 } // namespace internal
1821
1822 // API search type: identity : a -> a
1823 // fwd bind count: 0
1824 // identity(x) == x
1825 template <typename T>
identity(const T & x)1826 T identity(const T& x)
1827 {
1828 return x;
1829 }
1830
1831 // API search type: is_equal : (a, a) -> Bool
1832 // fwd bind count: 1
1833 // x == y
1834 // Equality check.
1835 template <typename T>
is_equal(const T & x,const T & y)1836 bool is_equal(const T& x, const T& y)
1837 {
1838 return x == y;
1839 }
1840
1841 // API search type: always : a -> (b -> a)
1842 // always(x)(y) == x
1843 template <typename X>
always(const X & x)1844 auto always(const X& x)
1845 {
1846 return [x](const auto&) { return x; };
1847 }
1848
1849 // API search type: always_arg_1_of_2 : (a, b) -> a
1850 // always_arg_1_of_2(x, y) == x
1851 template <typename X, typename Y>
1852 X always_arg_1_of_2(const X& x, const Y&)
1853 {
1854 return x;
1855 }
1856
1857 // API search type: always_arg_2_of_2 : (a, b) -> a
1858 // always_arg_2_of_2(x, y) == x
1859 template <typename X, typename Y>
always_arg_2_of_2(const X &,const Y & y)1860 Y always_arg_2_of_2(const X&, const Y& y)
1861 {
1862 return y;
1863 }
1864
1865 // API search type: is_equal_by_and_by : ((a -> b), (c -> b)) -> ((a, c) -> Bool)
1866 // f(x) == g(y)
1867 // Provides an equality check of two values
1868 // after applying a transformation function each.
1869 template <typename F, typename G>
is_equal_by_and_by(F f,G g)1870 auto is_equal_by_and_by(F f, G g)
1871 {
1872 return [f, g](const auto& x, const auto& y) {
1873 internal::trigger_static_asserts<internal::unary_function_tag,
1874 F,
1875 decltype(x)>();
1876 internal::trigger_static_asserts<internal::unary_function_tag,
1877 G,
1878 decltype(y)>();
1879 return is_equal(internal::invoke(f, x), internal::invoke(g, y));
1880 };
1881 }
1882
1883 // API search type: is_equal_by : (a -> b) -> (a -> Bool)
1884 // f(x) == f(y)
1885 // Provides an equality check of two values
1886 // after applying the same transformation function to both.
1887 template <typename F>
is_equal_by(F f)1888 auto is_equal_by(F f)
1889 {
1890 return is_equal_by_and_by(f, f);
1891 }
1892
1893 // API search type: is_equal_by_to : ((b -> a), a) -> (b -> Bool)
1894 // f(y) == x
1895 // Provides an equality check to a fixed value
1896 // after applying a transformation function.
1897 template <typename F, typename X>
is_equal_by_to(F f,const X & x)1898 auto is_equal_by_to(F f, const X& x)
1899 {
1900 return [f, x](const auto& y)
1901 {
1902 internal::trigger_static_asserts<internal::unary_function_tag,
1903 F,
1904 decltype(y)>();
1905 return is_equal(internal::invoke(f, y), x);
1906 };
1907 }
1908
1909 // API search type: is_equal_to : a -> (a -> Bool)
1910 // x == y
1911 // curried version of is_equal
1912 // Provides an equality check with a fixed value.
1913 template <typename X>
is_equal_to(const X & x)1914 auto is_equal_to(const X& x)
1915 {
1916 return is_equal_by_to(identity<X>, x);
1917 }
1918
1919 // API search type: is_not_equal : (a, a) -> Bool
1920 // fwd bind count: 1
1921 // x != y
1922 // Unequally check.
1923 template <typename T>
is_not_equal(const T & x,const T & y)1924 bool is_not_equal(const T& x, const T& y)
1925 {
1926 return x != y;
1927 }
1928
1929 // API search type: is_not_equal_by_and_by : ((a -> c), (b -> c)) -> ((a, b) -> Bool)
1930 // f(x) != g(y)
1931 // Provides an unequality check of two values
1932 // after applying a transformation function eac
1933 template <typename F, typename G>
is_not_equal_by_and_by(F f,G g)1934 auto is_not_equal_by_and_by(F f, G g)
1935 {
1936 return [f, g](const auto& x, const auto& y) {
1937 internal::trigger_static_asserts<internal::unary_function_tag,
1938 F,
1939 decltype(x)>();
1940 internal::trigger_static_asserts<internal::unary_function_tag,
1941 G,
1942 decltype(y)>();
1943 using FOut = std::decay_t<internal::invoke_result_t<F, decltype(x)>>;
1944 using GOut = std::decay_t<internal::invoke_result_t<G, decltype(y)>>;
1945 static_assert(std::is_same<FOut, GOut>::value,
1946 "Functions must return the same type.");
1947 return is_not_equal(internal::invoke(f, x), internal::invoke(g, y));
1948 };
1949 }
1950
1951 // API search type: is_not_equal_by : (a -> b) -> ((a, a) -> Bool)
1952 // f(x) != f(y)
1953 // Provides an unequality check of two values
1954 // after applying the same transformation function to both.
1955 template <typename F>
is_not_equal_by(F f)1956 auto is_not_equal_by(F f)
1957 {
1958 return is_not_equal_by_and_by(f, f);
1959 }
1960
1961 // API search type: is_not_equal_by_to : ((a -> b), b) -> (a -> Bool)
1962 // f(y) != x
1963 // Provides an unequality check to a fixed value
1964 // after applying a transformation function.
1965 template <typename F, typename X>
is_not_equal_by_to(F f,const X & x)1966 auto is_not_equal_by_to(F f, const X& x)
1967 {
1968 return [f, x](const auto& y) {
1969 internal::trigger_static_asserts<internal::unary_function_tag,
1970 F,
1971 decltype(y)>();
1972 return is_not_equal(internal::invoke(f, y), x);
1973 };
1974 }
1975
1976 // API search type: is_not_equal_to : a -> (a -> Bool)
1977 // y != x
1978 // curried version of is_not_equal
1979 // Provides an unequality check with a fixed value.
1980 template <typename X>
is_not_equal_to(const X & x)1981 auto is_not_equal_to(const X& x)
1982 {
1983 return is_not_equal_by_to(identity<X>, x);
1984 }
1985
1986 // API search type: is_less : (a, a) -> Bool
1987 // fwd bind count: 1
1988 // x < y
1989 // Less check.
1990 template <typename T>
is_less(const T & x,const T & y)1991 bool is_less(const T& x, const T& y)
1992 {
1993 return x < y;
1994 }
1995
1996 // API search type: is_less_by_and_by : ((a -> c), (b -> c)) -> ((a, b) -> Bool)
1997 // f(x) < g(y)
1998 // Provides a less check of two values
1999 // after applying a transformation function each.
2000 template <typename F, typename G>
is_less_by_and_by(F f,G g)2001 auto is_less_by_and_by(F f, G g)
2002 {
2003 return [f, g](const auto& x, const auto& y)
2004 {
2005 internal::trigger_static_asserts<internal::unary_function_tag,
2006 F,
2007 decltype(x)>();
2008 internal::trigger_static_asserts<internal::unary_function_tag,
2009 G,
2010 decltype(y)>();
2011 using FOut = std::decay_t<internal::invoke_result_t<F, decltype(x)>>;
2012 using GOut = std::decay_t<internal::invoke_result_t<G, decltype(y)>>;
2013 static_assert(std::is_same<FOut, GOut>::value,
2014 "Functions must return the same type.");
2015 return is_less(internal::invoke(f, x), internal::invoke(g, y));
2016 };
2017 }
2018
2019 // API search type: is_less_by : (a -> b) -> ((a, a) -> Bool)
2020 // f(x) < f(y)
2021 // Provides a less check of two values
2022 // after applying the same transformation function to both.
2023 template <typename F>
is_less_by(F f)2024 auto is_less_by(F f)
2025 {
2026 return is_less_by_and_by(f, f);
2027 }
2028
2029 // API search type: is_less_by_than : ((a -> b), b) -> (a -> Bool)
2030 // f(y) < x
2031 // Provides a less check to a fixed value
2032 // after applying a transformation function.
2033 template <typename F, typename X>
is_less_by_than(F f,const X & x)2034 auto is_less_by_than(F f, const X& x)
2035 {
2036 return [f, x](const auto& y)
2037 {
2038 internal::trigger_static_asserts<internal::unary_function_tag,
2039 F,
2040 decltype(y)>();
2041 return is_less(internal::invoke(f, y), x);
2042 };
2043 }
2044
2045 // API search type: is_less_than : a -> (a -> Bool)
2046 // y < x
2047 // curried version of is_less
2048 // Provides a less check with a fixed value.
2049 template <typename X>
is_less_than(const X & x)2050 auto is_less_than(const X& x)
2051 {
2052 return is_less_by_than(identity<X>, x);
2053 }
2054
2055 // API search type: is_less_or_equal : (a, a) -> Bool
2056 // fwd bind count: 1
2057 // x <= y
2058 // Less-or-equal check.
2059 template <typename T>
is_less_or_equal(const T & x,const T & y)2060 bool is_less_or_equal(const T& x, const T& y)
2061 {
2062 return x <= y;
2063 }
2064
2065 // API search type: is_less_or_equal_by_and_by : ((a -> c), (b -> c)) -> ((a, b) -> Bool)
2066 // f(x) <= g(y)
2067 // Provides a less-or-equal check of two values
2068 // after applying a transformation function each.
2069 template <typename F, typename G>
is_less_or_equal_by_and_by(F f,G g)2070 auto is_less_or_equal_by_and_by(F f, G g)
2071 {
2072 return [f, g](const auto& x, const auto& y)
2073 {
2074 using FIn = decltype(x);
2075 using GIn = decltype(y);
2076 internal::check_compare_preprocessors_for_types<F, G, FIn, GIn>();
2077 return is_less_or_equal(internal::invoke(f, x), internal::invoke(g, y));
2078 };
2079 }
2080
2081 // API search type: is_less_or_equal_by : (a -> b) -> ((a, a) -> Bool)
2082 // f(x) <= f(y)
2083 // Provides a less-or-equal check of two values
2084 // after applying the same transformation function to both.
2085 template <typename F>
is_less_or_equal_by(F f)2086 auto is_less_or_equal_by(F f)
2087 {
2088 return is_less_or_equal_by_and_by(f, f);
2089 }
2090
2091 // API search type: is_less_or_equal_by_than : ((a -> b), b) -> (a -> Bool)
2092 // f(y) <= x
2093 // Provides a less-or-equal check to a fixed value
2094 // after applying a transformation function.
2095 template <typename F, typename X>
is_less_or_equal_by_than(F f,const X & x)2096 auto is_less_or_equal_by_than(F f, const X& x)
2097 {
2098 return [f, x](const auto& y)
2099 {
2100 internal::
2101 trigger_static_asserts<internal::unary_function_tag, F, decltype(y)>();
2102 return is_less_or_equal(internal::invoke(f, y), x);
2103 };
2104 }
2105
2106 // API search type: is_less_or_equal_than : a -> (a -> Bool)
2107 // y <= x
2108 // curried version of is_less_or_equal
2109 // Provides a less-or-equal check with a fixed value
2110 template <typename X>
is_less_or_equal_than(const X & x)2111 auto is_less_or_equal_than(const X& x)
2112 {
2113 return is_less_or_equal_by_than(identity<X>, x);
2114 }
2115
2116 // API search type: is_greater : a -> a -> Bool
2117 // fwd bind count: 1
2118 // x > y
2119 // Greater check.
2120 template <typename T>
is_greater(const T & x,const T & y)2121 bool is_greater(const T& x, const T& y)
2122 {
2123 return x > y;
2124 }
2125
2126 // API search type: is_greater_by_and_by : ((a -> c), (b -> c)) -> ((a, b) -> Bool)
2127 // f(x) > g(y)
2128 // Provides a greater check of two values
2129 // after applying a transformation function each.
2130 template <typename F, typename G>
is_greater_by_and_by(F f,G g)2131 auto is_greater_by_and_by(F f, G g)
2132 {
2133 return [f, g](const auto& x, const auto& y)
2134 {
2135 using FIn = decltype(x);
2136 using GIn = decltype(y);
2137
2138 internal::check_compare_preprocessors_for_types<F, G, FIn, GIn>();
2139 return is_greater(internal::invoke(f, x), internal::invoke(g, y));
2140 };
2141 }
2142
2143 // API search type: is_greater_by : (a -> b) -> ((a, a) -> Bool)
2144 // f(x) > f(y)
2145 // Provides a greater check of two values
2146 // after applying the same transformation function to both.
2147 template <typename F>
is_greater_by(F f)2148 auto is_greater_by(F f)
2149 {
2150 return is_greater_by_and_by(f, f);
2151 }
2152
2153 // API search type: is_greater_by_than : ((a -> b), b) -> (a -> Bool)
2154 // f(y) > x
2155 // Provides a greater check to a fixed value
2156 // after applying a transformation function.
2157 template <typename F, typename X>
is_greater_by_than(F f,const X & x)2158 auto is_greater_by_than(F f, const X& x)
2159 {
2160 return [f, x](const auto& y)
2161 {
2162 return is_greater(internal::invoke(f, y), x);
2163 };
2164 }
2165
2166 // API search type: is_greater_than : a -> (a -> Bool)
2167 // y > x
2168 // curried version of is_greater
2169 // Provides a greater check with a fixed value.
2170 template <typename X>
is_greater_than(const X & x)2171 auto is_greater_than(const X& x)
2172 {
2173 return is_greater_by_than(identity<X>, x);
2174 }
2175
2176 // API search type: is_greater_or_equal : (a, a) -> Bool
2177 // fwd bind count: 1
2178 // x >= y
2179 // Greater-or-equal check.
2180 template <typename T>
is_greater_or_equal(const T & x,const T & y)2181 bool is_greater_or_equal(const T& x, const T& y)
2182 {
2183 return x >= y;
2184 }
2185
2186 // API search type: is_greater_or_equal_by_and_by : ((a -> c), (b -> c)) -> ((a, b) -> Bool)
2187 // f(x) >= g(y)
2188 // Provides a greater-or-equal check of two values
2189 // after applying a transformation function each.
2190 template <typename F, typename G>
is_greater_or_equal_by_and_by(F f,G g)2191 auto is_greater_or_equal_by_and_by(F f, G g)
2192 {
2193 return [f, g](const auto& x, const auto& y)
2194 {
2195 using FIn = decltype(x);
2196 using GIn = decltype(y);
2197 internal::check_compare_preprocessors_for_types<F, G, FIn, GIn>();
2198 return is_greater_or_equal(internal::invoke(f, x), internal::invoke(g, y));
2199 };
2200 }
2201
2202 // API search type: is_greater_or_equal_by : (a -> b) -> ((a, a) -> Bool)
2203 // f(x) >= f(y)
2204 // Provides a greater-or-equal check of two values
2205 // after applying the same transformation function to both.
2206 template <typename F>
is_greater_or_equal_by(F f)2207 auto is_greater_or_equal_by(F f)
2208 {
2209 return is_greater_or_equal_by_and_by(f, f);
2210 }
2211
2212 // API search type: is_greater_or_equal_by_than : ((a -> b), b) -> (a -> Bool)
2213 // f(y) >= x
2214 // Provides a greater-or-equal check to a fixed value
2215 // after applying a transformation function.
2216 template <typename F, typename X>
is_greater_or_equal_by_than(F f,const X & x)2217 auto is_greater_or_equal_by_than(F f, const X& x)
2218 {
2219 return [f, x](const auto& y)
2220 {
2221 internal::trigger_static_asserts<internal::unary_function_tag, F, decltype(y)>();
2222 return is_greater_or_equal(internal::invoke(f, y), x);
2223 };
2224 }
2225
2226 // API search type: is_greater_or_equal_than : a -> (a -> Bool)
2227 // y >= x
2228 // curried version of is_less_or_equal
2229 // Provides a greater-or-equal check with a fixed valu
2230 template <typename X>
is_greater_or_equal_than(const X & x)2231 auto is_greater_or_equal_than(const X& x)
2232 {
2233 return is_greater_or_equal_by_than(identity<X>, x);
2234 }
2235
2236 // API search type: xor_bools : (Bool, Bool) -> Bool
2237 // fwd bind count: 1
2238 // Exclusive or.
2239 template <typename T>
xor_bools(const T & x,const T & y)2240 bool xor_bools(const T& x, const T& y)
2241 {
2242 static_assert(std::is_convertible<T, bool>::value,
2243 "Type must be convertible to bool.");
2244 return (x && !y) || (!x && y);
2245 }
2246
2247 // API search type: ord_to_eq : ((a, a) -> Bool) -> ((a, a) -> Bool)
2248 // ord_to_eq((<)) == (==)
2249 // Takes a less-than function and converts it
2250 // into an equality check function
2251 // which considers two values as equal if none are lesser than the other one.
2252 template <typename Compare>
ord_to_eq(Compare comp)2253 auto ord_to_eq(Compare comp)
2254 {
2255 return [comp](auto x, auto y)
2256 {
2257 static_assert(std::is_same<decltype(x), decltype(y)>::value,
2258 "Argument types must be the same");
2259 auto p = internal::ord_to_impl(comp)(x, y);
2260 return !p.first && !p.second;
2261 };
2262 }
2263
2264 // API search type: ord_to_not_eq : ((a, a) -> Bool) -> ((a, a) -> Bool)
2265 // ord_to_not_eq((<)) == (!=)
2266 // Takes a less-than function and converts it
2267 // into an inequality check function
2268 // which considers to values as unequal if one is less than the other one.
2269 template <typename Compare>
ord_to_not_eq(Compare comp)2270 auto ord_to_not_eq(Compare comp)
2271 {
2272 return logical_not(ord_to_eq(comp));
2273 }
2274
2275 // API search type: ord_eq_to_eq : ((a, a) -> Bool) -> ((a, a) -> Bool)
2276 // ord_eq_to_eq((<=)) == (==)
2277 // ord_to_eq((<)) == (==)
2278 // Takes a less-or-equal-than function and converts it
2279 // into an equality check function
2280 // which considers to values as equal if a <= b and b <= a.
2281 template <typename Compare>
ord_eq_to_eq(Compare comp)2282 auto ord_eq_to_eq(Compare comp)
2283 {
2284 return [comp](auto x, auto y)
2285 {
2286 static_assert(std::is_same<decltype(x), decltype(y)>::value,
2287 "Argument types must be the same");
2288 auto p = internal::ord_to_impl(comp)(x, y);
2289 return p.first && p.second;
2290 };
2291 }
2292
2293 // API search type: ord_eq_to_not_eq : ((a, a) -> Bool) -> ((a, a) -> Bool)
2294 // ord_eq_to_not_eq((<=)) == (!=)
2295 // Takes a less-or-equal-than function and converts it
2296 // into an inequality check function
2297 // which considers to values as equal if not a <= b and not b <= a.
2298 template <typename Compare>
ord_eq_to_not_eq(Compare comp)2299 auto ord_eq_to_not_eq(Compare comp)
2300 {
2301 return logical_not(ord_eq_to_eq(comp));
2302 }
2303
2304 } // namespace fplus
2305
2306 //
2307 // container_common.hpp
2308 //
2309
2310 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2311 // https://github.com/Dobiasd/FunctionalPlus
2312 // Distributed under the Boost Software License, Version 1.0.
2313 // (See accompanying file LICENSE_1_0.txt or copy at
2314 // http://www.boost.org/LICENSE_1_0.txt)
2315
2316
2317
2318 //
2319 // container_traits.hpp
2320 //
2321
2322 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2323 // https://github.com/Dobiasd/FunctionalPlus
2324 // Distributed under the Boost Software License, Version 1.0.
2325 // (See accompanying file LICENSE_1_0.txt or copy at
2326 // http://www.boost.org/LICENSE_1_0.txt)
2327
2328
2329 #include <array>
2330 #include <deque>
2331 #include <forward_list>
2332 #include <list>
2333 #include <map>
2334 #include <limits>
2335 #include <unordered_map>
2336 #include <unordered_set>
2337 #include <queue>
2338 #include <set>
2339 #include <stack>
2340 #include <string>
2341 #include <vector>
2342
2343
2344 namespace fplus
2345 {
2346
2347 namespace internal
2348 {
2349
2350 #ifdef __GNUC__
2351 #pragma GCC diagnostic push
2352 #pragma GCC diagnostic ignored "-Weffc++"
2353 #endif
2354
2355 template<class T> struct has_order : public std::false_type {};
2356 template<class T, std::size_t N> struct has_order<std::array<T, N>> : public std::true_type {};
2357 template<class T, class Alloc> struct has_order<std::vector<T, Alloc>> : public std::true_type {};
2358 template<class T, class Alloc> struct has_order<std::deque<T, Alloc>> : public std::true_type {};
2359 template<class T, class Alloc> struct has_order<std::forward_list<T, Alloc>> : public std::true_type {};
2360 template<class T, class Alloc> struct has_order<std::list<T, Alloc>> : public std::true_type {};
2361 template<class T, class Alloc> struct has_order<std::set<T, Alloc>> : public std::false_type {};
2362 template<class T, class Container> struct has_order<std::stack<T, Container>> : public std::true_type {};
2363 template<class T, class Container> struct has_order<std::queue<T, Container>> : public std::true_type {};
2364 template<class T, class Container, class Compare> struct has_order<std::priority_queue<T, Container, Compare>> : public std::false_type {};
2365 template<class CharT, class Traits, class Alloc> struct has_order<std::basic_string<CharT, Traits, Alloc>> : public std::true_type {};
2366
2367 // http://stackoverflow.com/a/33828321/1866775
2368 template<class Cont, class NewT, int SizeOffset = std::numeric_limits<int>::lowest()> struct same_cont_new_t : public std::false_type{};
2369 template<class T, std::size_t N, class NewT, int SizeOffset> struct same_cont_new_t<std::array<T, N>, NewT, SizeOffset>
2370 {
2371 static_assert(SizeOffset != std::numeric_limits<int>::lowest(), "Size of std::array must be known at compile-time.");
2372 typedef typename std::array<NewT, static_cast<std::size_t>(static_cast<int>(N) + SizeOffset)> type;
2373 };
2374 template<class T, template<class> class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::vector<T, Alloc<T>>, NewT, SizeOffset> { typedef typename std::vector<NewT, Alloc<NewT>> type; };
2375 template<class T, template<class> class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::deque<T, Alloc<T>>, NewT, SizeOffset> { typedef typename std::deque<NewT, Alloc<NewT>> type; };
2376 template<class T, template<class> class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::forward_list<T, Alloc<T>>, NewT, SizeOffset> { typedef typename std::forward_list<NewT, Alloc<NewT>> type; };
2377 template<class T, template<class> class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::list<T, Alloc<T>>, NewT, SizeOffset> { typedef typename std::list<NewT, Alloc<NewT>> type; };
2378 template<class T, template<class> class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::set<T, Alloc<T>>, NewT, SizeOffset> { typedef typename std::set<NewT, Alloc<NewT>> type; };
2379 template<class T, class Container, class NewT, int SizeOffset> struct same_cont_new_t<std::stack<T, Container>, NewT, SizeOffset> { typedef typename std::stack<NewT, Container> type; };
2380 template<class T, class Container, class NewT, int SizeOffset> struct same_cont_new_t<std::queue<T, Container>, NewT, SizeOffset> { typedef typename std::queue<NewT, Container> type; };
2381 template<class T, class Container, class Compare, class NewT, int SizeOffset> struct same_cont_new_t<std::priority_queue<T, Container, Compare>, NewT, SizeOffset> { typedef typename std::priority_queue<NewT, Container, Compare> type; };
2382 template<class CharT, class Traits, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::basic_string<CharT, Traits, Alloc>, NewT, SizeOffset> { typedef typename std::basic_string<NewT, Traits, Alloc> type; };
2383
2384 // For aligned allocators.
2385 template<class T, template<class, std::size_t> class Alloc, class NewT, int SizeOffset, std::size_t N> struct same_cont_new_t<std::vector<T, Alloc<T, N>>, NewT, SizeOffset> { typedef typename std::vector<NewT, Alloc<NewT, N>> type; };
2386 template<class T, template<class, std::size_t> class Alloc, class NewT, int SizeOffset, std::size_t N> struct same_cont_new_t<std::deque<T, Alloc<T, N>>, NewT, SizeOffset> { typedef typename std::deque<NewT, Alloc<NewT, N>> type; };
2387
2388 template<class Cont, class NewKey, class NewVal> struct SameMapTypeNewTypes : public std::false_type {};
2389 template<class Key, class T, class Compare, class Alloc, class NewKey, class NewVal> struct SameMapTypeNewTypes<std::map<Key, T, Compare, Alloc>, NewKey, NewVal> { typedef typename std::map<NewKey, NewVal> type; };
2390 template<class Key, class T, class Compare, class Alloc, class NewKey, class NewVal> struct SameMapTypeNewTypes<std::unordered_map<Key, T, Compare, Alloc>, NewKey, NewVal> { typedef typename std::unordered_map<NewKey, NewVal> type; };
2391
2392 #ifdef __GNUC__
2393 #pragma GCC diagnostic pop
2394 #endif
2395
2396 template<
2397 typename ContIn,
2398 typename F,
2399 int SizeOffset = std::numeric_limits<int>::lowest(),
2400 typename T = typename ContIn::value_type,
2401 typename ContOut = typename same_cont_new_t<ContIn, std::decay_t<internal::invoke_result_t<F, T>>, SizeOffset>::type>
2402 struct same_cont_new_t_from_unary_f
2403 {
2404 typedef ContOut type;
2405 };
2406
2407 template<
2408 typename ContIn,
2409 typename F,
2410 typename T1,
2411 typename T2,
2412 int SizeOffset = std::numeric_limits<int>::lowest(),
2413 typename ContOut = typename same_cont_new_t<ContIn, std::decay_t<internal::invoke_result_t<F, T1, T2>>, SizeOffset>::type>
2414 struct same_cont_new_t_from_binary_f
2415 {
2416 typedef ContOut type;
2417 };
2418
2419
2420
2421 // https://stackoverflow.com/a/44549820/1866775
2422
2423 template<class T>
2424 struct can_self_assign {
2425 using type = std::is_assignable<T&, T>;
2426 };
2427
2428 template<typename T>
2429 using can_self_assign_t = typename can_self_assign<T>::type;
2430
2431 template<typename T0, typename T1>
2432 struct can_self_assign<std::pair<T0, T1>>
2433 {
2434 enum { t0 = can_self_assign_t<T0>::value, t1 = can_self_assign_t<T1>::value, x = t0&&t1 };
2435 using type = std::integral_constant<bool, x>;
2436 };
2437
2438 template<>
2439 struct can_self_assign<std::tuple<>>
2440 {
2441 using type = std::integral_constant<bool, true>;
2442 };
2443 template<typename T0, typename...Ts>
2444 struct can_self_assign<std::tuple<T0, Ts...>>
2445 {
2446 using type = std::integral_constant<bool, can_self_assign_t<T0>::value && can_self_assign_t<std::tuple<Ts...>>::value >;
2447 };
2448
2449 template<class T, T v>
2450 struct reuse_container_bool_t {
2451 };
2452 using create_new_container_t = reuse_container_bool_t<bool, false>;
2453 using reuse_container_t = reuse_container_bool_t<bool, true>;
2454
2455 template <typename Container>
2456 struct can_reuse
2457 {
2458 using dContainer = typename std::decay<Container>::type;
2459 using can_assign = can_self_assign_t<typename dContainer::value_type>;
2460 using cannot_reuse = std::is_lvalue_reference<Container>;
2461 using value = reuse_container_bool_t<bool, can_assign::value && !cannot_reuse::value>;
2462 };
2463
2464 template<typename Container>
2465 using can_reuse_v = typename can_reuse<Container>::value;
2466
2467 template <typename T>
2468 struct remove_const_and_ref
2469 {
2470 using type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
2471 };
2472
2473 template<typename T>
2474 using remove_const_and_ref_t = typename remove_const_and_ref<T>::type;
2475
2476
2477 } // namespace internal
2478
2479 } // namespace fplus
2480
2481 //
2482 // maybe.hpp
2483 //
2484
2485 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2486 // https://github.com/Dobiasd/FunctionalPlus
2487 // Distributed under the Boost Software License, Version 1.0.
2488 // (See accompanying file LICENSE_1_0.txt or copy at
2489 // http://www.boost.org/LICENSE_1_0.txt)
2490
2491
2492
2493 #include <cassert>
2494 #include <exception>
2495 #include <functional>
2496 #include <memory>
2497
2498 namespace fplus
2499 {
2500
2501 // Can hold a value of type T or nothing.
2502 template <typename T>
2503 class maybe
2504 {
2505 public:
is_just() const2506 bool is_just() const { return is_present_; }
is_nothing() const2507 bool is_nothing() const { return !is_just(); }
unsafe_get_just() const2508 const T& unsafe_get_just() const
2509 {
2510 assert(is_just());
2511 return *reinterpret_cast<const T*>(&value_);
2512 }
unsafe_get_just()2513 T& unsafe_get_just()
2514 {
2515 assert(is_just());
2516 return *reinterpret_cast<T*>(&value_);
2517 }
2518 typedef T type;
maybe()2519 maybe() : is_present_(false), value_() {};
~maybe()2520 ~maybe()
2521 {
2522 destruct_content();
2523 }
maybe(const T & val_just)2524 maybe(const T& val_just) : is_present_(true), value_()
2525 {
2526 new (&value_) T(val_just);
2527 }
maybe(T && val_just)2528 maybe(T&& val_just) : is_present_(true), value_() {
2529 new (&value_) T(std::move(val_just));
2530 }
maybe(const maybe<T> & other)2531 maybe(const maybe<T>& other) : is_present_(other.is_just()), value_()
2532 {
2533 if (is_present_)
2534 {
2535 new (&value_) T(other.unsafe_get_just());
2536 }
2537 }
maybe(maybe<T> && other)2538 maybe(maybe<T>&& other) : is_present_(std::move(other.is_present_)), value_()
2539 {
2540 if (is_present_)
2541 {
2542 new (&value_) T(std::move(other.unsafe_get_just()));
2543 }
2544 }
operator =(const T & other)2545 maybe<T>& operator = (const T& other)
2546 {
2547 destruct_content();
2548 is_present_ = true;
2549 new (&value_) T(other);
2550 return *this;
2551 }
operator =(T && other)2552 maybe& operator = (T&& other) {
2553 destruct_content();
2554 is_present_ = true;
2555 new (&value_) T(std::move(other));
2556 return *this;
2557 }
operator =(const maybe<T> & other)2558 maybe<T>& operator = (const maybe<T>& other)
2559 {
2560 destruct_content();
2561 if (other.is_just())
2562 {
2563 is_present_ = true;
2564 new (&value_) T(other.unsafe_get_just());
2565 }
2566 return *this;
2567 }
operator =(maybe<T> && other)2568 maybe& operator = (maybe<T>&& other) {
2569 destruct_content();
2570 is_present_ = std::move(other.is_present_);
2571 if (is_present_)
2572 {
2573 new (&value_) T(std::move(other.unsafe_get_just()));
2574 }
2575 return *this;
2576 }
2577 private:
destruct_content()2578 void destruct_content()
2579 {
2580 if (is_present_)
2581 {
2582 is_present_ = false;
2583 (*reinterpret_cast<const T*>(&value_)).~T();
2584 }
2585 }
2586 bool is_present_;
2587 typename std::aligned_storage<sizeof(T), alignof(T)>::type value_;
2588 };
2589
2590 namespace internal
2591 {
2592 template <typename>
2593 struct is_maybe : std::false_type
2594 {
2595 };
2596
2597 template <typename T>
2598 struct is_maybe<maybe<T>> : std::true_type
2599 {
2600 };
2601 }
2602
2603 // API search type: is_just : Maybe a -> Bool
2604 // fwd bind count: 0
2605 // Is not nothing?
2606 template <typename T>
is_just(const maybe<T> & maybe)2607 bool is_just(const maybe<T>& maybe)
2608 {
2609 return maybe.is_just();
2610 }
2611
2612 // API search type: is_nothing : Maybe a -> Bool
2613 // fwd bind count: 0
2614 // Has no value?
2615 template <typename T>
is_nothing(const maybe<T> & maybe)2616 bool is_nothing(const maybe<T>& maybe)
2617 {
2618 return !is_just(maybe);
2619 }
2620
2621 // API search type: unsafe_get_just : Maybe a -> a
2622 // fwd bind count: 0
2623 // Crashes if maybe is nothing!
2624 template <typename T>
unsafe_get_just(const maybe<T> & maybe)2625 T unsafe_get_just(const maybe<T>& maybe)
2626 {
2627 return maybe.unsafe_get_just();
2628 }
2629
2630 // API search type: just_with_default : (a, Maybe a) -> a
2631 // fwd bind count: 0
2632 // Get the value from a maybe or the default in case it is nothing.
2633 template <typename T>
just_with_default(const T & defaultValue,const maybe<T> & maybe)2634 T just_with_default(const T& defaultValue, const maybe<T>& maybe)
2635 {
2636 if (is_just(maybe))
2637 return unsafe_get_just(maybe);
2638 return defaultValue;
2639 }
2640
2641 // API search type: throw_on_nothing : (e, Maybe a) -> a
2642 // fwd bind count: 1
2643 // Throw exception if nothing. Return value if just.
2644 template <typename E, typename T>
throw_on_nothing(const E & e,const maybe<T> & maybe)2645 T throw_on_nothing(const E& e, const maybe<T>& maybe)
2646 {
2647 if (is_nothing(maybe))
2648 throw e;
2649 return unsafe_get_just(maybe);
2650 }
2651
2652 // API search type: just : a -> Maybe a
2653 // fwd bind count: 0
2654 // Wrap a value in a Maybe as a Just.
2655 template <typename T>
just(const T & val)2656 maybe<T> just(const T& val)
2657 {
2658 return val;
2659 }
2660
2661 // API search type: as_just_if : ((a -> bool), a) -> Maybe a
2662 // fwd bind count: 1
2663 // Wrap a value in a Maybe as a Just if the given predicate is fulfilled.
2664 // Otherwise a nothing is returned.
2665 template <typename Pred, typename T>
as_just_if(Pred pred,const T & val)2666 maybe<T> as_just_if(Pred pred, const T& val)
2667 {
2668 internal::check_unary_predicate_for_type<Pred, T>();
2669 if (pred(val))
2670 return val;
2671 else
2672 return {};
2673 }
2674
2675 // API search type: maybe_to_seq : Maybe a -> [a]
2676 // fwd bind count: 0
2677 // Converts a maybe to a sequence.
2678 // singleton_seq(Just 3) == [3]
2679 // singleton_seq(Nothing) == []
2680 template <typename T, typename ContainerOut = std::vector<T>>
maybe_to_seq(const maybe<T> & maybe)2681 ContainerOut maybe_to_seq(const maybe<T>& maybe)
2682 {
2683 if (is_just(maybe))
2684 return ContainerOut(1, unsafe_get_just(maybe));
2685 return {};
2686 }
2687
2688 // API search type: singleton_seq_as_maybe : [a] -> Maybe a
2689 // fwd bind count: 0
2690 // Converts a sequence to a maybe.
2691 // singleton_seq([]) == Nothing
2692 // singleton_seq([3]) == Just 3
2693 // singleton_seq([3,4]) == Nothing
2694 template <typename Container>
2695 maybe<typename Container::value_type>
singleton_seq_as_maybe(const Container & xs)2696 singleton_seq_as_maybe(const Container& xs)
2697 {
2698 if (xs.size() == 1)
2699 return xs.front();
2700 return {};
2701 }
2702
2703 // API search type: nothing : () -> Maybe a
2704 // Construct a nothing of a certain Maybe type.
2705 template <typename T>
nothing()2706 maybe<T> nothing()
2707 {
2708 return {};
2709 }
2710
2711 // True if just values are the same or if both are nothing.
2712 template <typename T>
operator ==(const maybe<T> & x,const maybe<T> & y)2713 bool operator == (const maybe<T>& x, const maybe<T>& y)
2714 {
2715 if (is_just(x) && is_just(y))
2716 return unsafe_get_just(x) == unsafe_get_just(y);
2717 return is_just(x) == is_just(y);
2718 }
2719
2720 // False if just values are the same or if both are nothing.
2721 template <typename T>
operator !=(const maybe<T> & x,const maybe<T> & y)2722 bool operator != (const maybe<T>& x, const maybe<T>& y)
2723 {
2724 return !(x == y);
2725 }
2726
2727 // API search type: lift_maybe : ((a -> b), Maybe a) -> Maybe b
2728 // fwd bind count: 1
2729 // Lifts a function into the maybe functor.
2730 // A function that for example was able to convert and int into a string,
2731 // now can convert a Maybe<int> into a Maybe<string>.
2732 // A nothing remains a nothing, regardless of the conversion.
2733 template <typename F, typename A>
lift_maybe(F f,const maybe<A> & m)2734 auto lift_maybe(F f, const maybe<A>& m)
2735 {
2736 internal::trigger_static_asserts<internal::check_arity_tag, F, A>();
2737
2738 using B = std::decay_t<internal::invoke_result_t<F, A>>;
2739 if (is_just(m))
2740 return just<B>(internal::invoke(f, unsafe_get_just(m)));
2741 return nothing<B>();
2742 }
2743
2744 // API search type: lift_maybe_def : (b, (a -> b), Maybe a) -> b
2745 // fwd bind count: 2
2746 // lift_maybe_def takes a default value and a function.
2747 // It returns a function taking a Maybe value.
2748 // This function returns the default value if the Maybe value is nothing.
2749 // Otherwise it applies the function to the value inside the Just
2750 // of the Maybe value and returns the result of this application.
2751 template <typename F, typename A, typename Default>
lift_maybe_def(const Default & def,F f,const maybe<A> & m)2752 auto lift_maybe_def(const Default& def, F f, const maybe<A>& m)
2753 {
2754 internal::trigger_static_asserts<internal::check_arity_tag, F, A>();
2755
2756 using B = std::decay_t<internal::invoke_result_t<F, A>>;
2757 static_assert(
2758 std::is_convertible<Default, B>::value,
2759 "Default value must be convertible to Function's return type");
2760 if (is_just(m))
2761 return B(internal::invoke(f, unsafe_get_just(m)));
2762 return B(def);
2763 }
2764
2765 // API search type: lift_maybe_2 : (((a, b) -> c), Maybe a, Maybe b) -> Maybe c
2766 // fwd bind count: 2
2767 // Lifts a binary function into the maybe functor.
2768 // Applies the function only if both arguments are justs.
2769 // Otherwise returns a nothing.
2770 template <typename F, typename A, typename B>
lift_maybe_2(F f,const maybe<A> & m_a,const maybe<B> & m_b)2771 auto lift_maybe_2(F f, const maybe<A>& m_a, const maybe<B>& m_b)
2772 {
2773 internal::trigger_static_asserts<internal::check_arity_tag, F, A, B>();
2774
2775 using FOut = std::decay_t<internal::invoke_result_t<F, A, B>>;
2776 if (is_just(m_a) && is_just(m_b))
2777 {
2778 return just<FOut>(
2779 internal::invoke(f, unsafe_get_just(m_a), unsafe_get_just(m_b)));
2780 }
2781 return nothing<FOut>();
2782 }
2783
2784 // API search type: lift_maybe_2_def : (c, ((a, b) -> c), Maybe a, Maybe b) -> c
2785 // fwd bind count: 3
2786 // lift_maybe_2_def takes a default value and a binary function.
2787 // It returns a function taking a two Maybe values.
2788 // This function returns the default value at least one of the
2789 // Maybe values is nothing.
2790 // Otherwise it applies the function to the two values inside the Justs
2791 // and returns the result of this application.
2792 template <typename F, typename A, typename B, typename Default>
lift_maybe_2_def(const Default & def,F f,const maybe<A> & m_a,const maybe<B> & m_b)2793 auto lift_maybe_2_def(const Default& def,
2794 F f,
2795 const maybe<A>& m_a,
2796 const maybe<B>& m_b)
2797 {
2798 internal::trigger_static_asserts<internal::check_arity_tag, F, A, B>();
2799
2800 using C = std::decay_t<internal::invoke_result_t<F, A, B>>;
2801 static_assert(
2802 std::is_convertible<Default, C>::value,
2803 "Default value must be convertible to Function's return type");
2804 if (is_just(m_a) && is_just(m_b))
2805 return C(internal::invoke(f, unsafe_get_just(m_a), unsafe_get_just(m_b)));
2806 return C(def);
2807 }
2808
2809 // API search type: join_maybe : Maybe Maybe a -> Maybe a
2810 // Flattens a nested maybe.
2811 // join_maybe(Just Just x) == Just x
2812 // join_maybe(Just Nothing) == Nothing
2813 // join_maybe(Nothing) == Nothing
2814 template <typename A>
join_maybe(const maybe<maybe<A>> & m)2815 maybe<A> join_maybe(const maybe<maybe<A>>& m)
2816 {
2817 if (is_just(m))
2818 return unsafe_get_just(m);
2819 else
2820 return nothing<A>();
2821 }
2822
2823 // API search type: and_then_maybe : ((a -> Maybe b), (Maybe a)) -> Maybe b
2824 // fwd bind count: 1
2825 // Monadic bind.
2826 // Returns nothing if the maybe already is nothing.
2827 // Otherwise return the result of applying
2828 // the function to the just value of the maybe.
2829 template <typename T, typename F>
and_then_maybe(F f,const maybe<T> & m)2830 auto and_then_maybe(F f, const maybe<T>& m)
2831 {
2832 internal::trigger_static_asserts<internal::check_arity_tag, F, T>();
2833 using FOut = std::decay_t<internal::invoke_result_t<F, T>>;
2834 static_assert(internal::is_maybe<FOut>::value,
2835 "Function must return a maybe<> type");
2836 if (is_just(m))
2837 return internal::invoke(f, unsafe_get_just(m));
2838 else
2839 return nothing<typename FOut::type>();
2840 }
2841
2842 // API search type: compose_maybe : ((a -> Maybe b), (b -> Maybe c)) -> (a -> Maybe c)
2843 // Left-to-right Kleisli composition of monads.
2844 // Composes multiple callables taking a value and returning Maybe.
2845 // If the first callable returns a just, the value from the just
2846 // is extracted and shoved into the next callable.
2847 // If the first callable returns a nothing, it remains a nothing.
2848 // The first callable can take a variadic number of parameters.
2849 template <typename... Callables>
compose_maybe(Callables &&...callables)2850 auto compose_maybe(Callables&&... callables)
2851 {
2852 auto bind_maybe = [](auto f, auto g) {
2853 // next step would be to perfectly forward callables, as shown here:
2854 // https://vittorioromeo.info/index/blog/capturing_perfectly_forwarded_objects_in_lambdas.html
2855 return [f = std::move(f), g = std::move(g)](auto&&... args)
2856 {
2857 using FOut = std::decay_t<
2858 internal::invoke_result_t<decltype(f), decltype(args)...>>;
2859 static_assert(internal::is_maybe<FOut>::value,
2860 "Functions must return a maybe<> type");
2861 using GOut = std::decay_t<
2862 internal::invoke_result_t<decltype(g), typename FOut::type>>;
2863 static_assert(internal::is_maybe<GOut>::value,
2864 "Functions must return a maybe<> type");
2865
2866 auto maybeB =
2867 internal::invoke(f, std::forward<decltype(args)>(args)...);
2868 if (is_just(maybeB))
2869 return internal::invoke(g, unsafe_get_just(maybeB));
2870 return GOut{};
2871 };
2872 };
2873
2874 return internal::compose_binary_lift(bind_maybe,
2875 std::forward<Callables>(callables)...);
2876 }
2877
2878 // API search type: flatten_maybe : (Maybe (Maybe a)) -> Maybe a
2879 // fwd bind count: 0
2880 // Also known as join.
2881 template <typename T>
flatten_maybe(const maybe<maybe<T>> & maybe_maybe)2882 maybe<T> flatten_maybe(const maybe<maybe<T>>& maybe_maybe)
2883 {
2884 if (is_nothing(maybe_maybe))
2885 return nothing<T>();
2886 return unsafe_get_just(maybe_maybe);
2887 }
2888
2889 } // namespace fplus
2890
2891
2892 //
2893 // internal/container_common.hpp
2894 //
2895
2896 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2897 // https://github.com/Dobiasd/FunctionalPlus
2898 // Distributed under the Boost Software License, Version 1.0.
2899 // (See accompanying file LICENSE_1_0.txt or copy at
2900 // http://www.boost.org/LICENSE_1_0.txt)
2901
2902
2903 #include <numeric>
2904 #include <type_traits>
2905
2906
2907 namespace fplus
2908 {
2909 namespace internal
2910 {
2911
2912 template<class InputIt, class T>
accumulate(InputIt first,InputIt last,T init)2913 T accumulate(InputIt first, InputIt last, T init)
2914 {
2915 for (; first != last; ++first) {
2916 init = std::move(init) + *first;
2917 }
2918 return init;
2919 }
2920
2921 template<class InputIt, class T, class BinaryOperation>
2922 T accumulate(InputIt first, InputIt last, T init,
2923 BinaryOperation op)
2924 {
2925 for (; first != last; ++first) {
2926 init = op(std::move(init), *first);
2927 }
2928 return init;
2929 }
2930
2931 template <typename F,
2932 typename Acc,
2933 typename InputIterator,
2934 typename OutputIterator>
scan_impl(F f,const Acc & init,OutputIterator itOut,InputIterator begin,InputIterator end)2935 void scan_impl(F f,
2936 const Acc& init,
2937 OutputIterator itOut,
2938 InputIterator begin,
2939 InputIterator end)
2940 {
2941 *itOut = init;
2942
2943 auto g = [itOut, f](auto acc, auto x) mutable
2944 {
2945 acc = internal::invoke(f, acc, x);
2946 *itOut = acc;
2947 return acc;
2948 };
2949
2950 internal::accumulate(begin, end, init, g);
2951 }
2952 }
2953 }
2954
2955 #include <algorithm>
2956 #include <cassert>
2957 #include <cmath>
2958 #include <cstddef>
2959 #include <iterator>
2960 #include <numeric>
2961
2962 namespace fplus
2963 {
2964
2965 namespace internal
2966 {
2967 template <typename UnaryPredicate, typename Container>
check_unary_predicate_for_container()2968 void check_unary_predicate_for_container()
2969 {
2970 internal::check_unary_predicate_for_type<UnaryPredicate,
2971 typename Container::value_type>();
2972 }
2973
2974 template <typename F, typename Container>
check_index_with_type_predicate_for_container()2975 void check_index_with_type_predicate_for_container()
2976 {
2977 typedef typename Container::value_type T;
2978 internal::trigger_static_asserts<internal::binary_function_tag, F, std::size_t, T>();
2979 static_assert(std::is_convertible<
2980 internal::invoke_result_t<F, std::size_t, T>, bool>::value,
2981 "Function must return bool.");
2982 }
2983
2984 template <typename Compare, typename Container>
check_compare_for_container()2985 void check_compare_for_container()
2986 {
2987 typedef typename Container::value_type T;
2988 internal::trigger_static_asserts<internal::binary_predicate_tag, Compare, T, T>();
2989 }
2990
2991 template <typename BinaryPredicate, typename Container>
check_binary_predicate_for_container()2992 void check_binary_predicate_for_container()
2993 {
2994 typedef typename Container::value_type T;
2995 internal::trigger_static_asserts<internal::binary_predicate_tag, BinaryPredicate, T, T>();
2996 }
2997
2998 // PrepareContainer and BackInserter are overloaded
2999 // to increase performance on std::vector and std::string
3000 // by using std::vector<T>::reserve
3001 // and std::back_inserter instead of std::back_inserter.
3002 // In VC2015, release mode, Celsius W520 Xeon
3003 // this leads to an increase in performance of about a factor of 3
3004 // for transform.
3005 template <typename C>
prepare_container(const std::basic_string<C,std::char_traits<C>,std::allocator<C>> & ys,std::size_t size)3006 void prepare_container(const std::basic_string<C, std::char_traits<C>,
3007 std::allocator<C>>& ys, std::size_t size)
3008 {
3009 ys.reserve(size);
3010 }
3011
3012 template <typename Y>
prepare_container(std::vector<Y> & ys,std::size_t size)3013 void prepare_container(std::vector<Y>& ys, std::size_t size)
3014 {
3015 ys.reserve(size);
3016 }
3017
3018 template <typename T, std::size_t N>
prepare_container(std::array<T,N> &,std::size_t size)3019 void prepare_container(std::array<T, N>&, std::size_t size)
3020 {
3021 assert(size == N);
3022 unused(size);
3023 }
3024
3025 template <typename Y>
prepare_container(std::unordered_set<Y> & ys,std::size_t size)3026 void prepare_container(std::unordered_set<Y>& ys, std::size_t size)
3027 {
3028 ys.reserve(size);
3029 }
3030
3031 template <typename Key, typename T>
prepare_container(std::unordered_map<Key,T> & ys,std::size_t size)3032 void prepare_container(std::unordered_map<Key, T>& ys, std::size_t size)
3033 {
3034 ys.reserve(size);
3035 }
3036
3037 template <typename Y>
prepare_container(std::unordered_multiset<Y> & ys,std::size_t size)3038 void prepare_container(std::unordered_multiset<Y>& ys, std::size_t size)
3039 {
3040 ys.reserve(size);
3041 }
3042
3043 template <typename Key, typename T>
prepare_container(std::unordered_multimap<Key,T> & ys,std::size_t size)3044 void prepare_container(std::unordered_multimap<Key, T>& ys, std::size_t size)
3045 {
3046 ys.reserve(size);
3047 }
3048
3049 template <typename Container>
prepare_container(Container &,std::size_t)3050 void prepare_container(Container&, std::size_t)
3051 {
3052 }
3053
3054 template <typename Container>
get_back_inserter(std::string & ys)3055 std::back_insert_iterator<Container> get_back_inserter(std::string& ys)
3056 {
3057 return std::back_inserter(ys);
3058 }
3059
3060 template <typename Container, typename Y>
get_back_inserter(std::vector<Y> & ys)3061 std::back_insert_iterator<Container> get_back_inserter(std::vector<Y>& ys)
3062 {
3063 return std::back_inserter(ys);
3064 }
3065
3066 template <typename Container, typename Y>
get_back_inserter(std::list<Y> & ys)3067 std::back_insert_iterator<Container> get_back_inserter(std::list<Y>& ys)
3068 {
3069 return std::back_inserter(ys);
3070 }
3071
3072 template <typename Container, typename Y>
get_back_inserter(std::deque<Y> & ys)3073 std::back_insert_iterator<Container> get_back_inserter(std::deque<Y>& ys)
3074 {
3075 return std::back_inserter(ys);
3076 }
3077
3078 // Avoid self-assignment.
3079 template <typename T>
assign(T & x,T && y)3080 void assign(T& x, T&& y) {
3081 if (&x != &y)
3082 x = std::move(y);
3083 }
3084
3085 template <typename T, std::size_t N>
3086 struct array_back_insert_iterator : public std::back_insert_iterator<std::array<T, N>>
3087 {
3088 typedef std::back_insert_iterator<std::array<T, N>> base_type;
array_back_insert_iteratorfplus::internal::array_back_insert_iterator3089 explicit array_back_insert_iterator(std::array<T, N>& arr) :
3090 base_type(arr), arr_ptr_(&arr), pos_(0) {}
array_back_insert_iteratorfplus::internal::array_back_insert_iterator3091 array_back_insert_iterator(const array_back_insert_iterator<T, N>& other) :
3092 base_type(*other.arr_ptr_), arr_ptr_(other.arr_ptr_), pos_(other.pos_) {}
operator =fplus::internal::array_back_insert_iterator3093 array_back_insert_iterator<T, N>& operator=(const array_back_insert_iterator<T, N>& other)
3094 {
3095 arr_ptr_ = other.arr_ptr_;
3096 pos_ = other.pos_;
3097 return *this;
3098 }
~array_back_insert_iteratorfplus::internal::array_back_insert_iterator3099 ~array_back_insert_iterator()
3100 {
3101 assert(pos_ == 0 || pos_ == N);
3102 }
operator =fplus::internal::array_back_insert_iterator3103 array_back_insert_iterator<T, N>& operator=(const T& x)
3104 {
3105 assert(pos_ < N);
3106 (*arr_ptr_)[pos_] = x;
3107 ++pos_;
3108 return *this;
3109 }
operator =fplus::internal::array_back_insert_iterator3110 array_back_insert_iterator<T, N>& operator=(T&& x)
3111 {
3112 assert(pos_ < N);
3113 assign((*arr_ptr_)[pos_], std::move(x));
3114 ++pos_;
3115 return *this;
3116 }
operator *fplus::internal::array_back_insert_iterator3117 array_back_insert_iterator<T, N>& operator*() { return *this; }
operator ++fplus::internal::array_back_insert_iterator3118 array_back_insert_iterator<T, N>& operator++() { return *this; }
operator ++fplus::internal::array_back_insert_iterator3119 array_back_insert_iterator<T, N> operator++(int) { return *this; }
3120 private:
3121 std::array<T, N>* arr_ptr_;
3122 std::size_t pos_;
3123 };
3124
3125 #if defined(_MSC_VER) && _MSC_VER >= 1900
3126 template <typename T, std::size_t N>
3127 struct std::_Is_checked_helper<array_back_insert_iterator<T, N>>
3128 : public true_type
3129 { // mark array_back_insert_iterator as checked
3130 };
3131 #endif
3132
3133 template <typename Container, typename Y, std::size_t N>
get_back_inserter(std::array<Y,N> & ys)3134 array_back_insert_iterator<Y, N> get_back_inserter(std::array<Y, N>& ys)
3135 {
3136 return array_back_insert_iterator<Y, N>(ys);
3137 }
3138
3139 template <typename Container>
get_back_inserter(Container & ys)3140 std::insert_iterator<Container> get_back_inserter(Container& ys)
3141 {
3142 return std::inserter(ys, std::end(ys));
3143 }
3144
3145 template <typename Iterator>
advance_iterator(Iterator & it,std::size_t distance)3146 void advance_iterator(Iterator& it, std::size_t distance)
3147 {
3148 std::advance(it,
3149 static_cast<typename Iterator::difference_type>(distance));
3150 }
3151
3152 template <typename T>
advance_iterator(T * & it,std::size_t distance)3153 void advance_iterator(T*& it, std::size_t distance)
3154 {
3155 it += static_cast<std::ptrdiff_t>(distance);
3156 }
3157
3158 template <typename Iterator>
add_to_iterator(Iterator it,std::size_t distance=1)3159 Iterator add_to_iterator(Iterator it, std::size_t distance = 1)
3160 {
3161 return std::next(it,
3162 static_cast<typename Iterator::difference_type>(distance));
3163 }
3164
3165 // GCC 4.9 does not support std::rbegin, std::rend and std::make_reverse_iterator
3166 template <typename Iterator>
make_reverse_iterator(Iterator it)3167 std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
3168 {
3169 return std::reverse_iterator<Iterator>(it);
3170 }
3171 } // namespace internal
3172
3173 // API search type: is_even : Int -> Bool
3174 // fwd bind count: 0
3175 // Checks if x is even.
3176 template <typename X>
is_even(X x)3177 bool is_even(X x)
3178 {
3179 static_assert(std::is_integral<X>::value, "type must be integral");
3180 return x % 2 == 0;
3181 }
3182
3183 // API search type: is_odd : Int -> Bool
3184 // fwd bind count: 0
3185 // Checks if x is odd.
3186 template <typename X>
is_odd(X x)3187 bool is_odd(X x)
3188 {
3189 static_assert(std::is_integral<X>::value, "type must be integral");
3190 return x % 2 != 0;
3191 }
3192
3193 // API search type: is_empty : [a] -> Bool
3194 // fwd bind count: 0
3195 // Returns true if the container holds no elements.
3196 // is_empty([1, 2]) == false
3197 // is_empty([]) == true
3198 template <typename Container>
is_empty(const Container & xs)3199 bool is_empty(const Container& xs)
3200 {
3201 return xs.empty();
3202 }
3203
3204 // API search type: is_not_empty : [a] -> Bool
3205 // fwd bind count: 0
3206 // Returns true if the container holds at least one element.
3207 // is_not_empty([1, 2]) == true
3208 template <typename Container>
is_not_empty(const Container & xs)3209 bool is_not_empty(const Container& xs)
3210 {
3211 return !is_empty(xs);
3212 }
3213
3214 // API search type: size_of_cont : [a] -> Int
3215 // fwd bind count: 0
3216 // Returns the number of elements in the given container.
3217 // size_of_cont([3, 4]) == 2
3218 template <typename Container>
size_of_cont(const Container & xs)3219 std::size_t size_of_cont(const Container& xs)
3220 {
3221 return xs.size();
3222 }
3223
3224 // API search type: convert : a -> b
3225 // fwd bind count: 0
3226 // Converts one type of element into another.
3227 template <typename Dest, typename Source>
3228 Dest convert(const Source& x)
3229 {
3230 return Dest(x);
3231 }
3232
3233 // API search type: convert_elems : [a] -> [b]
3234 // fwd bind count: 0
3235 // Converts all elements in a sequence to a different type.
3236 // convert_elems<NewT>([1, 2, 3]) == [NewT(1), NewT(2), NewT(3)]
3237 template <typename NewT, typename ContainerIn,
3238 typename ContainerOut = typename internal::same_cont_new_t<ContainerIn, NewT, 0>::type>
convert_elems(const ContainerIn & xs)3239 ContainerOut convert_elems(const ContainerIn& xs)
3240 {
3241 static_assert(std::is_constructible<NewT,
3242 typename ContainerIn::value_type>::value,
3243 "Elements not convertible.");
3244 ContainerOut ys;
3245 internal::prepare_container(ys, size_of_cont(xs));
3246 auto it = internal::get_back_inserter<ContainerOut>(ys);
3247 // using 'for (const auto& x ...)' is even for ints as fast as
3248 // using 'for (int x ...)' (GCC, O3), so there is no need to
3249 // check if the type is fundamental and then dispatch accordingly.
3250 for (const auto& x : xs)
3251 {
3252 *it = convert<NewT>(x);
3253 }
3254 return ys;
3255 }
3256
3257 // API search type: convert_container : [a] -> [a]
3258 // fwd bind count: 0
3259 // Change the type of the container
3260 // while keeping the elements in the sequence the same.
3261 // convert_container([1, 2, 3]) == [1, 2, 3]
3262 // Useful for example if you want to convert an std::list to an std::vector.
3263 template <typename ContainerOut, typename ContainerIn>
3264 ContainerOut convert_container(const ContainerIn& xs)
3265 {
3266 typedef typename ContainerIn::value_type SourceElem;
3267 typedef typename ContainerOut::value_type DestElem;
3268 static_assert(std::is_same<DestElem, SourceElem>::value,
3269 "Source and dest container must have the same value_type");
3270 ContainerOut ys;
3271 internal::prepare_container(ys, size_of_cont(xs));
3272 auto itOut = internal::get_back_inserter<ContainerOut>(ys);
3273 std::copy(std::begin(xs), std::end(xs), itOut);
3274 return ys;
3275 }
3276
3277 // API search type: convert_container_and_elems : [a] -> [b]
3278 // fwd bind count: 0
3279 // Converts between different containers and elements.
3280 // Dest elements are allowed to have explicit constructors.
3281 // convert([1, 2, 3]) == [1, 2, 3]
3282 template <typename ContainerOut, typename ContainerIn>
3283 ContainerOut convert_container_and_elems(const ContainerIn& xs)
3284 {
3285 static_assert(std::is_convertible<typename ContainerIn::value_type,
3286 typename ContainerOut::value_type>::value,
3287 "Elements not convertible.");
3288 typedef typename ContainerOut::value_type DestElem;
3289 ContainerOut ys;
3290 internal::prepare_container(ys, size_of_cont(xs));
3291 auto it = internal::get_back_inserter<ContainerOut>(ys);
3292 for (const auto& x : xs)
3293 {
3294 *it = convert<DestElem>(x);
3295 }
3296 return ys;
3297 }
3298
3299 namespace internal
3300 {
3301
3302 template <typename Container>
get_segment(internal::reuse_container_t,std::size_t idx_begin,std::size_t idx_end,Container && xs)3303 Container get_segment(internal::reuse_container_t,
3304 std::size_t idx_begin, std::size_t idx_end, Container&& xs)
3305 {
3306 idx_end = std::min(idx_end, size_of_cont(xs));
3307 if (idx_end <= idx_begin)
3308 {
3309 xs.clear();
3310 return std::forward<Container>(xs);
3311 }
3312 auto itBegin = std::begin(xs);
3313 internal::advance_iterator(itBegin, idx_begin);
3314 auto itEnd = itBegin;
3315 internal::advance_iterator(itEnd, idx_end - idx_begin);
3316 xs.erase(std::copy(itBegin, itEnd, std::begin(xs)), std::end(xs));
3317 return std::forward<Container>(xs);
3318 }
3319
3320 template <typename Container>
get_segment(internal::create_new_container_t,std::size_t idx_begin,std::size_t idx_end,const Container & xs)3321 Container get_segment(internal::create_new_container_t,
3322 std::size_t idx_begin, std::size_t idx_end, const Container& xs)
3323 {
3324 idx_end = std::min(idx_end, size_of_cont(xs));
3325 if (idx_end <= idx_begin)
3326 {
3327 return {};
3328 }
3329 Container result;
3330 auto itBegin = std::begin(xs);
3331 internal::advance_iterator(itBegin, idx_begin);
3332 auto itEnd = itBegin;
3333 internal::advance_iterator(itEnd, idx_end - idx_begin);
3334 std::copy(itBegin, itEnd, internal::get_back_inserter(result));
3335 return result;
3336 }
3337
3338 } // namespace internal
3339
3340 // API search type: get_segment : (Int, Int, [a]) -> [a]
3341 // fwd bind count: 2
3342 // Return a defined segment from the sequence.
3343 // get_segment(2, 5, [0,1,2,3,4,5,6,7,8]) == [2,3,4]
3344 // get_segment(2, 15, [0,1,2,3,4,5,6,7,8]) == [2,3,4,5,6,7,8]
3345 // get_segment(5, 2, [0,1,2,3,4,5,6,7,8]) == []
3346 // Also known as slice.
3347 template <typename Container,
3348 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
get_segment(std::size_t idx_begin,std::size_t idx_end,Container && xs)3349 ContainerOut get_segment
3350 (std::size_t idx_begin, std::size_t idx_end, Container&& xs)
3351 {
3352 return internal::get_segment(internal::can_reuse_v<Container>{},
3353 idx_begin, idx_end, std::forward<Container>(xs));
3354 }
3355
3356 namespace internal
3357 {
3358
3359 template <typename ContainerToken, typename Container>
set_segment(internal::reuse_container_t,std::size_t idx_begin,const ContainerToken & token,Container && xs)3360 Container set_segment(internal::reuse_container_t,
3361 std::size_t idx_begin, const ContainerToken& token, Container&& xs)
3362 {
3363 assert(idx_begin + size_of_cont(token) < size_of_cont(xs));
3364 auto itBegin = std::begin(xs);
3365 internal::advance_iterator(itBegin, idx_begin);
3366 std::copy(std::begin(token), std::end(token), itBegin);
3367 return std::forward<Container>(xs);
3368 }
3369
3370 template <typename ContainerToken, typename Container>
set_segment(internal::create_new_container_t,std::size_t idx_begin,const ContainerToken & token,const Container & xs)3371 Container set_segment(internal::create_new_container_t,
3372 std::size_t idx_begin, const ContainerToken& token, const Container& xs)
3373 {
3374 Container result = xs;
3375 return set_segment(internal::reuse_container_t(),
3376 idx_begin, token, std::move(result));
3377 }
3378
3379 } // namespace internal
3380
3381 // API search type: set_segment : (Int, [a], [a]) -> [a]
3382 // fwd bind count: 2
3383 // Replace part of a sequence with a token.
3384 // set_segment(2, [9,9,9], [0,1,2,3,4,5,6,7,8]) == [0,1,9,9,9,5,6,7,8]
3385 // Crashes on invalid indices.
3386 // Also known as replace_segment.
3387 template <typename ContainerToken, typename Container,
3388 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
set_segment(std::size_t idx_begin,const ContainerToken & token,Container && xs)3389 ContainerOut set_segment
3390 (std::size_t idx_begin, const ContainerToken& token, Container&& xs)
3391 {
3392 return internal::set_segment(internal::can_reuse_v<Container>{},
3393 idx_begin, token, std::forward<Container>(xs));
3394 }
3395
3396 namespace internal
3397 {
3398
3399 template <typename Container>
remove_segment(internal::reuse_container_t,std::size_t idx_begin,std::size_t idx_end,Container && xs)3400 Container remove_segment(internal::reuse_container_t,
3401 std::size_t idx_begin, std::size_t idx_end, Container&& xs)
3402 {
3403 assert(idx_begin <= idx_end);
3404 assert(idx_end <= size_of_cont(xs));
3405
3406 auto firstBreakIt = std::begin(xs);
3407 internal::advance_iterator(firstBreakIt, idx_begin);
3408
3409 auto secondBreakIt = std::begin(xs);
3410 internal::advance_iterator(secondBreakIt, idx_end);
3411
3412 xs.erase(
3413 std::copy(secondBreakIt, std::end(xs), firstBreakIt), std::end(xs));
3414 return std::forward<Container>(xs);
3415 }
3416
3417 template <typename Container>
remove_segment(internal::create_new_container_t,std::size_t idx_begin,std::size_t idx_end,const Container & xs)3418 Container remove_segment(internal::create_new_container_t,
3419 std::size_t idx_begin, std::size_t idx_end, const Container& xs)
3420 {
3421 assert(idx_begin <= idx_end);
3422 assert(idx_end <= size_of_cont(xs));
3423
3424 Container result;
3425 std::size_t length = idx_end - idx_begin;
3426 internal::prepare_container(result, size_of_cont(xs) - length);
3427
3428 auto firstBreakIt = std::begin(xs);
3429 internal::advance_iterator(firstBreakIt, idx_begin);
3430 std::copy(std::begin(xs), firstBreakIt, internal::get_back_inserter(result));
3431
3432 auto secondBreakIt = std::begin(xs);
3433 internal::advance_iterator(secondBreakIt, idx_end);
3434 std::copy(secondBreakIt, std::end(xs), internal::get_back_inserter(result));
3435
3436 return result;
3437 }
3438
3439 } // namespace internal
3440
3441 // API search type: remove_segment : (Int, Int, [a]) -> [a]
3442 // fwd bind count: 2
3443 // Cuts our a defined segment from the sequence.
3444 // remove_segment(2, 5, [0,1,2,3,4,5,6,7]) == [0,1,5,6,7]
3445 // crashes on invalid indices
3446 template <typename Container,
3447 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
remove_segment(std::size_t idx_begin,std::size_t idx_end,Container && xs)3448 ContainerOut remove_segment(
3449 std::size_t idx_begin, std::size_t idx_end, Container&& xs)
3450 {
3451 return internal::remove_segment(internal::can_reuse_v<Container>{},
3452 idx_begin, idx_end, std::forward<Container>(xs));
3453 }
3454
3455 // API search type: insert_at : (Int, [a], [a]) -> [a]
3456 // fwd bind count: 2
3457 // Inserts a token into a sequence at a specific position.
3458 // insert_at(2, [8,9], [0,1,2,3,4]) == [0,1,8,9,2,3,4]
3459 // Unsafe! Crashes on invalid index.
3460 template <typename Container>
insert_at(std::size_t idx_begin,const Container & token,const Container & xs)3461 Container insert_at(std::size_t idx_begin,
3462 const Container& token, const Container& xs)
3463 {
3464 assert(idx_begin <= size_of_cont(xs));
3465
3466 Container result;
3467 internal::prepare_container(result, size_of_cont(xs) + size_of_cont(token));
3468
3469 auto breakIt = std::begin(xs);
3470 internal::advance_iterator(breakIt, idx_begin);
3471 std::copy(std::begin(xs), breakIt, internal::get_back_inserter(result));
3472 std::copy(std::begin(token), std::end(token), internal::get_back_inserter(result));
3473 std::copy(breakIt, std::end(xs), internal::get_back_inserter(result));
3474
3475 return result;
3476 }
3477
3478 // API search type: elem_at_idx : (Int, [a]) -> a
3479 // fwd bind count: 1
3480 // Return the nth element of a sequence.
3481 // elem_at_idx(2, [7,6,5,4,3]) == 5
3482 // Unsafe! Crashes on invalid index.
3483 template <typename Container>
elem_at_idx(std::size_t idx,const Container & xs)3484 auto elem_at_idx(std::size_t idx, const Container& xs)
3485 {
3486 assert(idx < size_of_cont(xs));
3487 auto it = std::begin(xs);
3488 internal::advance_iterator(it, idx);
3489 return *it;
3490 }
3491
3492 // API search type: elem_at_idx_maybe : (Int, [a]) -> Maybe a
3493 // fwd bind count: 1
3494 // Return the nth element of a sequence if existing.
3495 // elem_at_idx_maybe(2, [7,6,5,4,3]) == Just 5
3496 // elem_at_idx_maybe(9, [7,6,5,4,3]) == Nothing
3497 // Use elem_at_idx_or_nothing if you want to provide a signed index type.
3498 template <typename Container,
3499 typename T = typename Container::value_type>
elem_at_idx_maybe(std::size_t idx,const Container & xs)3500 maybe<T> elem_at_idx_maybe(std::size_t idx, const Container& xs)
3501 {
3502 if (size_of_cont(xs) < idx)
3503 {
3504 return {};
3505 }
3506 auto it = std::begin(xs);
3507 internal::advance_iterator(it, idx);
3508 return *it;
3509 }
3510
3511 // API search type: elems_at_idxs : ([Int], [a]) -> [a]
3512 // fwd bind count: 1
3513 // Construct a subsequence from the elements with the given indices.
3514 // elem_at_idxs([1, 3], [7,6,5,4,3]) == [6, 4]
3515 template <typename Container,
3516 typename ContainerIdxs,
3517 typename T = typename Container::value_type,
3518 typename ContainerOut = std::vector<T>>
elems_at_idxs(const ContainerIdxs & idxs,const Container & xs)3519 std::vector<T> elems_at_idxs(const ContainerIdxs& idxs, const Container& xs)
3520 {
3521 static_assert(std::is_same<typename ContainerIdxs::value_type, std::size_t>::value,
3522 "Indices must be std::size_t");
3523 ContainerOut result;
3524 internal::prepare_container(result, size_of_cont(idxs));
3525 auto itOut = internal::get_back_inserter(result);
3526 for (std::size_t idx : idxs)
3527 {
3528 *itOut = elem_at_idx(idx, xs);
3529 }
3530 return result;
3531 }
3532
3533 namespace internal
3534 {
3535
3536 template <typename Container, typename F>
3537 Container transform(internal::reuse_container_t, F f, Container&& xs)
3538 {
3539 internal::trigger_static_asserts<internal::unary_function_tag,
3540 F,
3541 decltype(*std::begin(xs))>();
3542 std::transform(std::begin(xs), std::end(xs), std::begin(xs), f);
3543 return std::forward<Container>(xs);
3544 }
3545
3546 template <typename ContainerOut, typename F, typename ContainerIn>
3547 ContainerOut transform(internal::create_new_container_t, F f,
3548 const ContainerIn& xs)
3549 {
3550 internal::trigger_static_asserts<internal::unary_function_tag,
3551 F,
3552 decltype(*std::begin(xs))>();
3553 ContainerOut ys;
3554 internal::prepare_container(ys, size_of_cont(xs));
3555 auto it = internal::get_back_inserter<ContainerOut>(ys);
3556 std::transform(std::begin(xs), std::end(xs), it, f);
3557 return ys;
3558 }
3559
3560 } // namespace internal
3561
3562 // API search type: transform : ((a -> b), [a]) -> [b]
3563 // fwd bind count: 1
3564 // Apply a function to every element in a sequence.
3565 // transform((*2), [1, 3, 4]) == [2, 6, 8]
3566 // Also known as map or fmap.
3567 template <typename F, typename ContainerIn,
3568 typename ContainerOut = typename internal::same_cont_new_t_from_unary_f<
3569 internal::remove_const_and_ref_t<ContainerIn>, F, 0>::type>
transform(F f,ContainerIn && xs)3570 ContainerOut transform(F f, ContainerIn&& xs)
3571 {
3572 using reuse_t = typename std::conditional<
3573 std::is_same<
3574 internal::can_reuse_v<ContainerIn>,
3575 internal::reuse_container_t>::value &&
3576 std::is_base_of<
3577 std::true_type,
3578 internal::has_order<ContainerIn>>::value &&
3579 std::is_same<
3580 internal::remove_const_and_ref_t<ContainerIn>,
3581 ContainerOut>::value,
3582 internal::reuse_container_t,
3583 internal::create_new_container_t>::type;
3584 return internal::transform<ContainerOut>(
3585 reuse_t{}, f, std::forward<ContainerIn>(xs));
3586 }
3587
3588 // API search type: transform_convert : ((a -> b), [a]) -> [b]
3589 // fwd bind count: 1
3590 // transform_convert((*2), [1, 3, 4]) == [2, 6, 8]
3591 // Same as transform, but makes it easy to
3592 // use an output container type different from the input container type.
3593 template <typename ContainerOut, typename F, typename ContainerIn>
3594 ContainerOut transform_convert(F f, const ContainerIn& xs)
3595 {
3596 internal::trigger_static_asserts<internal::unary_function_tag, F, typename ContainerIn::value_type>();
3597 ContainerOut ys;
3598 internal::prepare_container(ys, size_of_cont(xs));
3599 auto it = internal::get_back_inserter<ContainerOut>(ys);
3600 std::transform(std::begin(xs), std::end(xs), it, f);
3601 return ys;
3602 }
3603
3604 // API search type: transform_inner : ((a -> b), [[a]]) -> [[b]]
3605 // fwd bind count: 1
3606 // Applies a function to the elements of the inner containers
3607 // of a nested sequence.
3608 // transform_inner((*2), [[1, 3, 4], [1, 2]]) == [[2, 6, 8], [2, 4]]
3609 // Also known as transform_nested, map_nested or map_inner.
3610 template <typename F, typename ContainerIn,
3611 typename ContainerOut =
3612 typename internal::same_cont_new_t<
3613 ContainerIn,
3614 typename internal::same_cont_new_t_from_unary_f<
3615 typename ContainerIn::value_type, F, 0
3616 >::type, 0
3617 >::type>
transform_inner(F f,const ContainerIn & xs)3618 ContainerOut transform_inner(F f, const ContainerIn& xs)
3619 {
3620 internal::trigger_static_asserts<internal::unary_function_tag, F, typename ContainerIn::value_type::value_type>();
3621 return fplus::transform(
3622 fplus::bind_1st_of_2(
3623 fplus::transform<F, const typename ContainerIn::value_type&>, f),
3624 xs);
3625 }
3626
3627 namespace internal
3628 {
3629
3630 template <typename Container>
reverse(internal::reuse_container_t,Container && xs)3631 Container reverse(internal::reuse_container_t, Container&& xs)
3632 {
3633 static_assert(internal::has_order<Container>::value,
3634 "Reverse: Container has no order.");
3635 std::reverse(std::begin(xs), std::end(xs));
3636 return std::forward<Container>(xs);
3637 }
3638
3639 template <typename Container>
reverse(internal::create_new_container_t,const Container & xs)3640 Container reverse(internal::create_new_container_t, const Container& xs)
3641 {
3642 static_assert(internal::has_order<Container>::value,
3643 "Reverse: Container has no order.");
3644 Container ys = xs;
3645 std::reverse(std::begin(ys), std::end(ys));
3646 return ys;
3647 }
3648
3649 } // namespace internal
3650
3651 // API search type: reverse : [a] -> [a]
3652 // fwd bind count: 0
3653 // Reverse a sequence.
3654 // reverse([0,4,2,6]) == [6,2,4,0]
3655 template <typename Container,
3656 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
reverse(Container && xs)3657 ContainerOut reverse(Container&& xs)
3658 {
3659 return internal::reverse(internal::can_reuse_v<Container>{},
3660 std::forward<Container>(xs));
3661 }
3662
3663 // API search type: take : (Int, [a]) -> [a]
3664 // fwd bind count: 1
3665 // Return the first n elements of a sequence xs.
3666 // In case n >= length(xs), xs is returned.
3667 // take(3, [0,1,2,3,4,5,6,7]) == [0,1,2]
3668 // take(10, [0,1,2]) == [0,1,2]
3669 template <typename Container,
3670 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
take(std::size_t amount,Container && xs)3671 ContainerOut take(std::size_t amount, Container&& xs)
3672 {
3673 if (amount >= size_of_cont(xs))
3674 return xs;
3675 return get_segment(0, amount, std::forward<Container>(xs));
3676 }
3677
3678 // API search type: take_exact : (Int, [a]) -> [a]
3679 // fwd bind count: 1
3680 // Return exactly the first n elements of a sequence xs.
3681 // Unsafe! Crashes then sequence is too short.
3682 // take_exact(3, [0,1,2,3,4,5,6,7]) == [0,1,2]
3683 // take_exact(10, [0,1,2]) == crash
3684 template <typename Container,
3685 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
take_exact(std::size_t amount,Container && xs)3686 ContainerOut take_exact(std::size_t amount, Container&& xs)
3687 {
3688 return get_segment(0, amount, std::forward<Container>(xs));
3689 }
3690
3691 // API search type: take_cyclic : (Int, [a]) -> [a]
3692 // fwd bind count: 1
3693 // Takes n elements from a sequence considering it as cyclic.
3694 // take_cyclic(5, [0,1,2,3]) == [0,1,2,3,0]
3695 // take_cyclic(7, [0,1,2,3]) == [0,1,2,3,0,1,2]
3696 // take_cyclic(7, [0,1]) == [0,1,0,1,0,1,0]
3697 // take_cyclic(2, [0,1,2,3]) == [0,1]
3698 // take_cyclic(3, [0]) == [0,0,0]
3699 // take_cyclic(3, []) == crash!
3700 // Also known as take_wrap.
3701 // xs must be non-empty.
3702 template <typename Container>
take_cyclic(std::size_t amount,const Container & xs)3703 Container take_cyclic(std::size_t amount, const Container& xs)
3704 {
3705 assert(!xs.empty());
3706
3707 Container ys;
3708 internal::prepare_container(ys, size_of_cont(xs));
3709 auto it_out = internal::get_back_inserter(ys);
3710 auto it_in = std::begin(xs);
3711
3712 while (amount != 0)
3713 {
3714 *it_out = *it_in;
3715 --amount;
3716 ++it_in;
3717 if (it_in == std::end(xs))
3718 {
3719 it_in = std::begin(xs);
3720 }
3721 }
3722 return ys;
3723 }
3724
3725 // API search type: drop : (Int, [a]) -> [a]
3726 // fwd bind count: 1
3727 // Skip the first n elements of a sequence xs.
3728 // If n > length(xs) an empty sequence is returned.
3729 // drop(3, [0,1,2,3,4,5,6,7]) == [3,4,5,6,7]
3730 // Also known as skip.
3731 template <typename Container,
3732 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
drop(std::size_t amount,Container && xs)3733 ContainerOut drop(std::size_t amount, Container&& xs)
3734 {
3735 if (amount >= size_of_cont(xs))
3736 return ContainerOut();
3737 return get_segment(amount, size_of_cont(xs), std::forward<Container>(xs));
3738 }
3739
3740 // API search type: take_last : (Int, [a]) -> [a]
3741 // fwd bind count: 1
3742 // Return the last n elements of a sequence xs.
3743 // In case n >= length(xs), xs is returned.
3744 // take_last(3, [0,1,2,3,4,5,6,7]) == [5,6,7]
3745 // take_last(10, [0,1,2]) == [0,1,2]
3746 template <typename Container,
3747 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
take_last(std::size_t amount,Container && xs)3748 ContainerOut take_last(std::size_t amount, Container&& xs)
3749 {
3750 if (amount >= size_of_cont(xs))
3751 return xs;
3752 return drop(size_of_cont(xs) - amount, std::forward<Container>(xs));
3753 }
3754
3755 // API search type: drop_last : (Int, [a]) -> [a]
3756 // fwd bind count: 1
3757 // Skip the last n elements of a sequence xs.
3758 // If n > length(xs) an empty sequence is returned.
3759 // drop_last(3, [0,1,2,3,4,5,6,7]) == [0,1,2,3,4]
3760 template <typename Container,
3761 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
drop_last(std::size_t amount,Container && xs)3762 ContainerOut drop_last(std::size_t amount, Container&& xs)
3763 {
3764 if (amount >= size_of_cont(xs))
3765 return ContainerOut();
3766 return take(size_of_cont(xs) - amount, std::forward<Container>(xs));
3767 }
3768
3769 // API search type: drop_exact : (Int, [a]) -> [a]
3770 // fwd bind count: 1
3771 // Skip exactly the first n elements of a sequence xs.
3772 // Unsafe! Crashes when xs is too short.
3773 // drop_exact(3, [0,1,2,3,4,5,6,7]) == [3,4,5,6,7]
3774 // drop_exact(10, [0,1,2,3,4,5,6,7]) == crash
3775 template <typename Container,
3776 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
drop_exact(std::size_t amount,Container && xs)3777 ContainerOut drop_exact(std::size_t amount, Container&& xs)
3778 {
3779 return get_segment(amount, size_of_cont(xs), std::forward<Container>(xs));
3780 }
3781
3782 // API search type: take_while : ((a -> Bool), [a]) -> [a]
3783 // fwd bind count: 1
3784 // Take elements from the beginning of a sequence
3785 // as long as they are fulfilling a predicate.
3786 // take_while(is_even, [0,2,4,5,6,7,8]) == [0,2,4]
3787 template <typename Container, typename UnaryPredicate>
3788 Container take_while(UnaryPredicate pred, const Container& xs)
3789 {
3790 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
3791 auto itFirst = std::find_if(
3792 std::begin(xs), std::end(xs), logical_not(pred));
3793 if (itFirst == std::end(xs))
3794 return xs;
3795 return Container(std::begin(xs), itFirst);
3796 }
3797
3798 // API search type: take_last_while : ((a -> Bool), [a]) -> [a]
3799 // fwd bind count: 1
3800 // Take elements from the beginning of a sequence
3801 // as long as they are fulfilling a predicate.
3802 // take_last_while(is_even, [0,2,7,5,6,4,8]) == [6,4,8]
3803 template <typename Container, typename UnaryPredicate>
3804 Container take_last_while(UnaryPredicate pred, const Container& xs)
3805 {
3806 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
3807 const auto r_begin = internal::make_reverse_iterator(std::end(xs));
3808 const auto r_end = internal::make_reverse_iterator(std::begin(xs));
3809 const auto itFirstReverse = std::find_if(r_begin, r_end, logical_not(pred));
3810 if (itFirstReverse == r_begin)
3811 return Container();
3812 if (itFirstReverse == r_end)
3813 return xs;
3814 return Container(itFirstReverse.base(), std::end(xs));
3815 }
3816
3817 // API search type: drop_while : ((a -> Bool), [a]) -> [a]
3818 // fwd bind count: 1
3819 // Remove elements from the beginning of a sequence
3820 // as long as they are fulfilling a predicate.
3821 // drop_while(is_even, [0,2,4,5,6,7,8]) == [5,6,7,8]
3822 // Also known as trim_left_by.
3823 template <typename Container, typename UnaryPredicate>
3824 Container drop_while(UnaryPredicate pred, const Container& xs)
3825 {
3826 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
3827 auto itFirstNot = std::find_if_not(std::begin(xs), std::end(xs), pred);
3828 if (itFirstNot == std::end(xs))
3829 return Container();
3830 return Container(itFirstNot, std::end(xs));
3831 }
3832
3833 // API search type: drop_last_while : ((a -> Bool), [a]) -> [a]
3834 // fwd bind count: 1
3835 // Remove elements from the beginning of a sequence
3836 // as long as they are fulfilling a predicate.
3837 // drop_last_while(is_even, [0,2,7,5,6,4,8]) == [0,2,7,5]
3838 template <typename Container, typename UnaryPredicate>
3839 Container drop_last_while(UnaryPredicate pred, const Container& xs)
3840 {
3841 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
3842 const auto r_begin = internal::make_reverse_iterator(std::end(xs));
3843 const auto r_end = internal::make_reverse_iterator(std::begin(xs));
3844 const auto itFirstNotReverse = std::find_if_not(r_begin, r_end, pred);
3845 if (itFirstNotReverse == r_begin)
3846 return xs;
3847 if (itFirstNotReverse == r_end)
3848 return Container();
3849 return Container(std::begin(xs), itFirstNotReverse.base());
3850 }
3851
3852 // API search type: fold_left : (((a, b) -> a), a, [b]) -> a
3853 // fwd bind count: 2
3854 // fold_left((+), 0, [1, 2, 3]) == ((0+1)+2)+3 == 6
3855 // Takes the second argument and the first item of the list
3856 // and applies the function to them,
3857 // then feeds the function with this result and the second argument and so on.
3858 template <typename F, typename Container, typename Acc>
fold_left(F f,const Acc & init,const Container & xs)3859 Acc fold_left(F f, const Acc& init, const Container& xs)
3860 {
3861 using std::begin;
3862 using std::end;
3863
3864 return internal::accumulate(begin(xs), end(xs), init, f);
3865 }
3866
3867 // API search type: reduce : (((a, a) -> a), a, [a]) -> a
3868 // fwd bind count: 2
3869 // reduce((+), 0, [1, 2, 3]) == (0+1+2+3) == 6
3870 // Combines the initial value and all elements of the sequence
3871 // using the given function.
3872 // The set of f, init and value_type should form a monoid.
3873 template <typename F, typename Container>
reduce(F f,const typename Container::value_type & init,const Container & xs)3874 typename Container::value_type reduce(
3875 F f, const typename Container::value_type& init, const Container& xs)
3876 {
3877 return fold_left(f, init, xs);
3878 }
3879
3880 // API search type: fold_left_1 : (((a, a) -> a), [a]) -> a
3881 // fwd bind count: 1
3882 // fold_left_1((+), [1, 2, 3]) == (1+2)+3 == 6
3883 // Takes the first 2 items of the list and applies the function to them,
3884 // then feeds the function with this result and the third argument and so on.
3885 // xs must be non-empty.
3886 template <typename F, typename Container>
fold_left_1(F f,const Container & xs)3887 auto fold_left_1(F f, const Container& xs)
3888 {
3889 assert(!xs.empty());
3890
3891 using std::begin;
3892 using std::end;
3893
3894 const auto it = begin(xs);
3895 return internal::accumulate(std::next(it), end(xs), *it, f);
3896 }
3897
3898 // API search type: reduce_1 : (((a, a) -> a), [a]) -> a
3899 // fwd bind count: 1
3900 // reduce_1((+), [1, 2, 3]) == (1+2+3) == 6
3901 // Joins all elements of the sequence using the given function.
3902 // The set of f and value_type should form a semigroup.
3903 template <typename F, typename Container>
reduce_1(F f,const Container & xs)3904 typename Container::value_type reduce_1(F f, const Container& xs)
3905 {
3906 assert(!xs.empty());
3907 return fold_left_1(f, xs);
3908 }
3909
3910 // API search type: fold_right : (((a, b) -> b), b) -> [a] -> b
3911 // fwd bind count: 2
3912 // fold_right((+), 0, [1, 2, 3]) == 1+(2+(3+0)) == 6
3913 // Takes the second argument and the last item of the list
3914 // and applies the function,
3915 // then it takes the penultimate item from the end and the result, and so on.
3916 template <typename F, typename Container, typename Acc>
fold_right(F f,const Acc & init,const Container & xs)3917 Acc fold_right(F f, const Acc& init, const Container& xs)
3918 {
3919 return internal::accumulate(xs.rbegin(), xs.rend(), init, flip(f));
3920 }
3921
3922 // API search type: fold_right_1 : (((a, a) -> a), [a]) -> a
3923 // fwd bind count: 1
3924 // fold_right_1((+), [1, 2, 3]) == 1+(2+3)) == 6
3925 // Takes the last two items of the list and applies the function,
3926 // then it takes the third item from the end and the result, and so on.
3927 template <typename F, typename Container>
fold_right_1(F f,const Container & xs)3928 auto fold_right_1(F f, const Container& xs)
3929 {
3930 assert(!xs.empty());
3931 const auto it = xs.rbegin();
3932 return internal::accumulate(std::next(it), xs.rend(), *it, flip(f));
3933 }
3934
3935 // API search type: scan_left : (((a, b) -> a), a, [b]) -> [a]
3936 // fwd bind count: 2
3937 // scan_left((+), 0, [1, 2, 3]) == [0, 1, 3, 6]
3938 // Takes the second argument and the first item of the list
3939 // and applies the function to them,
3940 // then feeds the function with this result and the second argument and so on.
3941 // It returns the list of intermediate and final results.
3942 template <typename F, typename ContainerIn, typename Acc>
scan_left(F f,const Acc & init,const ContainerIn & xs)3943 auto scan_left(F f, const Acc& init, const ContainerIn& xs)
3944 {
3945 using ContainerOut =
3946 typename internal::same_cont_new_t<ContainerIn, Acc, 1>::type;
3947
3948 ContainerOut result;
3949 internal::prepare_container(result, size_of_cont(xs) + 1);
3950
3951 using std::begin;
3952 using std::end;
3953
3954 internal::scan_impl(
3955 f, init, internal::get_back_inserter(result), begin(xs), end(xs));
3956 return result;
3957 }
3958
3959 // API search type: scan_left_1 : (((a, a) -> a), [a]) -> [a]
3960 // fwd bind count: 1
3961 // scan_left_1((+), [1, 2, 3]) == [1, 3, 6]
3962 // Takes the first 2 items of the list and applies the function to them,
3963 // then feeds the function with this result and the third argument and so on.
3964 // It returns the list of intermediate and final results.
3965 // xs must be non-empty.
3966 template <typename F, typename ContainerIn>
scan_left_1(F f,const ContainerIn & xs)3967 auto scan_left_1(F f, const ContainerIn& xs)
3968 {
3969 assert(!xs.empty());
3970
3971 using std::begin;
3972 using std::end;
3973
3974 const auto beginIt = begin(xs);
3975
3976 using ContainerOut = typename internal::same_cont_new_t<
3977 ContainerIn,
3978 internal::uncvref_t<decltype(*beginIt)>,
3979 0>::type;
3980
3981 ContainerOut result;
3982 internal::prepare_container(result, size_of_cont(xs));
3983 internal::scan_impl(f,
3984 *beginIt,
3985 internal::get_back_inserter(result),
3986 std::next(beginIt),
3987 end(xs));
3988 return result;
3989 }
3990
3991 // API search type: scan_right : (((a, b) -> b), b, [a]) -> [b]
3992 // fwd bind count: 2
3993 // scan_right((+), 0, [1, 2, 3]) == [6, 5, 3, 0]
3994 // Takes the second argument and the last item of the list
3995 // and applies the function,
3996 // then it takes the penultimate item from the end and the result, and so on.
3997 // It returns the list of intermediate and final results.
3998 template <typename F, typename ContainerIn,
3999 typename Acc = typename utils::function_traits<F>::template arg<1>::type,
4000 typename ContainerOut = typename internal::same_cont_new_t<ContainerIn, Acc, 1>::type>
scan_right(F f,const Acc & init,const ContainerIn & xs)4001 ContainerOut scan_right(F f, const Acc& init, const ContainerIn& xs)
4002 {
4003 return reverse(scan_left(flip(f), init, reverse(xs)));
4004 }
4005
4006 // API search type: scan_right_1 : (((a, a) -> a), [a]) -> [a]
4007 // fwd bind count: 1
4008 // scan_right_1((+), [1, 2, 3]) == [6, 5, 3]
4009 // Takes the last two items of the list and applies the function,
4010 // then it takes the third item from the end and the result, and so on.
4011 // It returns the list of inntermediate and final results.
4012 template <typename F, typename ContainerIn,
4013 typename Acc = typename ContainerIn::value_type,
4014 typename ContainerOut = typename internal::same_cont_new_t<ContainerIn, Acc, 0>::type>
scan_right_1(F f,const ContainerIn & xs)4015 ContainerOut scan_right_1(F f, const ContainerIn& xs)
4016 {
4017 return reverse(scan_left_1(flip(f), reverse(xs)));
4018 }
4019
4020 // API search type: sum : [a] -> a
4021 // fwd bind count: 0
4022 // Adds up all values in a sequence.
4023 // sum([0,3,1]) == 4
4024 // sum([]) == 0
4025 template <typename Container,
4026 typename T = typename Container::value_type>
sum(const Container & xs)4027 T sum(const Container& xs)
4028 {
4029 T result = T();
4030 for (const auto& x : xs)
4031 {
4032 result = result + x;
4033 }
4034 return result;
4035 }
4036
4037 // API search type: product : [a] -> a
4038 // fwd bind count: 0
4039 // Returns the product of all values in a sequence.
4040 // product([3,1,2]) == 6
4041 // product([]) == 1
4042 template <typename Container,
4043 typename T = typename Container::value_type>
product(const Container & xs)4044 T product(const Container& xs)
4045 {
4046 T result{1};
4047 for (const auto& x : xs)
4048 {
4049 result = result * x;
4050 }
4051 return result;
4052 }
4053
4054 namespace internal
4055 {
4056
4057 template <typename T, typename Container>
append_elem(internal::reuse_container_t,const T & y,Container && xs)4058 Container append_elem(internal::reuse_container_t, const T& y, Container&& xs)
4059 {
4060 *internal::get_back_inserter(xs) = y;
4061 return std::forward<Container>(xs);
4062 }
4063
4064 template <typename T, typename Container>
append_elem(internal::create_new_container_t,const T & y,const Container & xs)4065 Container append_elem(internal::create_new_container_t, const T& y,
4066 const Container& xs)
4067 {
4068 Container result;
4069 internal::prepare_container(result, size_of_cont(xs) + 1);
4070 std::copy(std::begin(xs), std::end(xs),
4071 internal::get_back_inserter(result));
4072 *internal::get_back_inserter(result) = y;
4073 return result;
4074 }
4075
4076 } // namespace internal
4077
4078 // API search type: append_elem : (a, [a]) -> [a]
4079 // fwd bind count: 1
4080 // Extends a sequence with one element at the back.
4081 // append_elem([1, 2], 3) == [1, 2, 3]
4082 template <typename Container,
4083 typename ContainerOut = internal::remove_const_and_ref_t<Container>,
4084 typename T = typename ContainerOut::value_type>
4085 ContainerOut append_elem(const T& y, Container&& xs)
4086 {
4087 return internal::append_elem(internal::can_reuse_v<Container>{},
4088 y, std::forward<Container>(xs));
4089 }
4090
4091 namespace internal
4092 {
4093
4094 template <typename T>
prepend_elem(internal::reuse_container_t,const T & y,std::list<T> && xs)4095 std::list<T> prepend_elem(internal::reuse_container_t,
4096 const T& y, std::list<T>&& xs)
4097 {
4098 xs.push_front(y);
4099 return std::forward<std::list<T>>(xs);
4100 }
4101
4102 template <typename T, typename Container>
prepend_elem(internal::reuse_container_t,const T & y,Container && xs)4103 Container prepend_elem(internal::reuse_container_t,
4104 const T& y, Container&& xs)
4105 {
4106 xs.resize(size_of_cont(xs) + 1);
4107 std::copy(++xs.rbegin(), xs.rend(), xs.rbegin());
4108 *std::begin(xs) = y;
4109 return std::forward<Container>(xs);
4110 }
4111
4112 template <typename T, typename Container>
prepend_elem(internal::create_new_container_t,const T & y,const Container & xs)4113 Container prepend_elem(internal::create_new_container_t, const T& y,
4114 const Container& xs)
4115 {
4116 Container result;
4117 internal::prepare_container(result, size_of_cont(xs) + 1);
4118 *internal::get_back_inserter(result) = y;
4119 std::copy(std::begin(xs), std::end(xs),
4120 internal::get_back_inserter(result));
4121 return result;
4122 }
4123
4124 } // namespace internal
4125
4126 // API search type: prepend_elem : (a, [a]) -> [a]
4127 // fwd bind count: 1
4128 // Extends a sequence with one element in the front.
4129 // prepend_elem([2, 3], 1) == [1, 2, 3]
4130 template <typename Container,
4131 typename ContainerOut = internal::remove_const_and_ref_t<Container>,
4132 typename T = typename ContainerOut::value_type>
4133 ContainerOut prepend_elem(const T& y, Container&& xs)
4134 {
4135 return internal::prepend_elem(internal::can_reuse_v<Container>{},
4136 y, std::forward<Container>(xs));
4137 }
4138
4139 // API search type: append : ([a], [a]) -> [a]
4140 // fwd bind count: 1
4141 // Concatenates two sequences.
4142 // append([1, 2], [3, 4, 5]) == [1, 2, 3, 4, 5]
4143 template <typename ContainerIn1, typename ContainerIn2 = ContainerIn1, typename ContainerOut = ContainerIn1>
append(const ContainerIn1 & xs,const ContainerIn2 & ys)4144 ContainerOut append(const ContainerIn1& xs, const ContainerIn2& ys)
4145 {
4146 ContainerOut result;
4147 internal::prepare_container(result, size_of_cont(xs) + size_of_cont(ys));
4148 std::copy(std::begin(xs), std::end(xs),
4149 internal::get_back_inserter(result));
4150 std::copy(std::begin(ys), std::end(ys),
4151 internal::get_back_inserter(result));
4152 return result;
4153 }
4154
4155
4156 // API search type: append_convert : ([a], [a]) -> [a]
4157 // fwd bind count: 1
4158 // Same as append, but makes it easier to
4159 // use an output container type different from the input container type.
4160 template <typename ContainerOut, typename ContainerIn1, typename ContainerIn2 = ContainerIn1>
4161 ContainerOut append_convert(const ContainerIn1& xs, const ContainerIn2& ys)
4162 {
4163 return append<ContainerIn1, ContainerIn2, ContainerOut>(xs, ys);
4164 }
4165
4166 // API search type: concat : [[a]] -> [a]
4167 // fwd bind count: 0
4168 // Concatenates multiple sequences.
4169 // concat([[1, 2], [], [3]]) == [1, 2, 3]
4170 // Also known as flatten.
4171 template <typename ContainerIn,
4172 typename ContainerOut = typename ContainerIn::value_type>
concat(const ContainerIn & xss)4173 ContainerOut concat(const ContainerIn& xss)
4174 {
4175 std::size_t length = sum(
4176 transform(size_of_cont<typename ContainerIn::value_type>, xss));
4177 ContainerOut result;
4178 internal::prepare_container(result, length);
4179 using std::begin;
4180 using std::end;
4181 for(const auto& xs : xss)
4182 {
4183 result.insert(end(result), begin(xs), end(xs));
4184 }
4185 return result;
4186 }
4187
4188 // API search type: interweave : ([a], [a]) -> [a]
4189 // fwd bind count: 1
4190 // Return a sequence that contains elements from the two provided sequences
4191 // in alternating order. If one list runs out of items,
4192 // appends the items from the remaining list.
4193 // interweave([1,3], [2,4]) == [1,2,3,4]
4194 // interweave([1,3,5,7], [2,4]) == [1,2,3,4,5,7]
4195 // See interleave for interweaving more than two sequences.
4196 template <typename Container>
interweave(const Container & xs,const Container & ys)4197 Container interweave(const Container& xs, const Container& ys)
4198 {
4199 Container result;
4200 internal::prepare_container(result, size_of_cont(xs) + size_of_cont(ys));
4201 auto it = internal::get_back_inserter<Container>(result);
4202 auto it_xs = std::begin(xs);
4203 auto it_ys = std::begin(ys);
4204 while (it_xs != std::end(xs) || it_ys != std::end(ys))
4205 {
4206 if (it_xs != std::end(xs))
4207 *it = *(it_xs++);
4208 if (it_ys != std::end(ys))
4209 *it = *(it_ys++);
4210 }
4211 return result;
4212 }
4213
4214 // API search type: unweave : [a] -> ([a], [a])
4215 // fwd bind count: 0
4216 // Puts the elements with an even index into the first list,
4217 // and the elements with an odd index into the second list.
4218 // Inverse of interweave.
4219 // unweave([0,1,2,3]) == ([0,2], [1,3])
4220 // unweave([0,1,2,3,4]) == ([0,2,4], [1,3])
4221 template <typename Container>
unweave(const Container & xs)4222 std::pair<Container, Container> unweave(const Container& xs)
4223 {
4224 std::pair<Container, Container> result;
4225 if (is_even(size_of_cont(xs)))
4226 internal::prepare_container(result.first, size_of_cont(xs) / 2);
4227 else
4228 internal::prepare_container(result.first, size_of_cont(xs) / 2 + 1);
4229 internal::prepare_container(result.second, size_of_cont(xs) / 2);
4230 auto it_even = internal::get_back_inserter<Container>(result.first);
4231 auto it_odd = internal::get_back_inserter<Container>(result.second);
4232 std::size_t counter = 0;
4233 for (const auto& x : xs)
4234 {
4235 if (counter++ % 2 == 0)
4236 *it_even = x;
4237 else
4238 *it_odd = x;
4239 }
4240 return result;
4241 }
4242
4243 namespace internal
4244 {
4245
4246 template <typename Compare, typename T>
sort_by(internal::reuse_container_t,Compare comp,std::list<T> && xs)4247 std::list<T> sort_by(internal::reuse_container_t, Compare comp,
4248 std::list<T>&& xs)
4249 {
4250 xs.sort(comp);
4251 return std::forward<std::list<T>>(xs);
4252 }
4253
4254 template <typename Compare, typename T>
sort_by(internal::create_new_container_t,Compare comp,const std::list<T> & xs)4255 std::list<T> sort_by(internal::create_new_container_t, Compare comp,
4256 const std::list<T>& xs)
4257 {
4258 auto result = xs;
4259 result.sort(comp);
4260 return result;
4261 }
4262
4263 template <typename Compare, typename Container>
sort_by(internal::reuse_container_t,Compare comp,Container && xs)4264 Container sort_by(internal::reuse_container_t, Compare comp, Container&& xs)
4265 {
4266 std::sort(std::begin(xs), std::end(xs), comp);
4267 return std::forward<Container>(xs);
4268 }
4269
4270 template <typename Compare, typename Container>
sort_by(internal::create_new_container_t,Compare comp,const Container & xs)4271 Container sort_by(internal::create_new_container_t, Compare comp,
4272 const Container& xs)
4273 {
4274 auto result = xs;
4275 std::sort(std::begin(result), std::end(result), comp);
4276 return result;
4277 }
4278
4279 } // namespace internal
4280
4281 // API search type: sort_by : (((a, a) -> Bool), [a]) -> [a]
4282 // fwd bind count: 1
4283 // Sort a sequence by given less comparator.
4284 template <typename Compare, typename Container,
4285 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
sort_by(Compare comp,Container && xs)4286 ContainerOut sort_by(Compare comp, Container&& xs)
4287 {
4288 return internal::sort_by(internal::can_reuse_v<Container>{},
4289 comp, std::forward<Container>(xs));
4290 }
4291
4292 namespace internal
4293 {
4294 // workarounds for clang bug 24115
4295 // (std::sort and std::unique with std::function as comp)
4296 // https://llvm.org/bugs/show_bug.cgi?id=24115
4297 template <typename F>
4298 struct is_less_by_struct
4299 {
is_less_by_structfplus::internal::is_less_by_struct4300 is_less_by_struct(F f) : f_(f) {};
4301 template <typename T>
operator ()fplus::internal::is_less_by_struct4302 bool operator()(const T& x, const T& y)
4303 {
4304 return f_(x) < f_(y);
4305 }
4306 private:
4307 F f_;
4308 };
4309 template <typename F>
4310 struct is_equal_by_struct
4311 {
is_equal_by_structfplus::internal::is_equal_by_struct4312 is_equal_by_struct(F f) : f_(f) {};
4313 template <typename T>
operator ()fplus::internal::is_equal_by_struct4314 bool operator()(const T& x, const T& y)
4315 {
4316 return f_(x) == f_(y);
4317 }
4318 private:
4319 F f_;
4320 };
4321 }
4322
4323 // API search type: sort_on : ((a -> b), [a]) -> [a]
4324 // fwd bind count: 1
4325 // Sort a sequence by a given transformer.
4326 template <typename F, typename Container,
4327 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
sort_on(F f,Container && xs)4328 ContainerOut sort_on(F f, Container&& xs)
4329 {
4330 return sort_by(internal::is_less_by_struct<F>(f),
4331 std::forward<Container>(xs));
4332 }
4333
4334 // API search type: sort : [a] -> [a]
4335 // fwd bind count: 0
4336 // Sort a sequence to ascending order using std::less.
4337 template <typename Container,
4338 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
sort(Container && xs)4339 ContainerOut sort(Container&& xs)
4340 {
4341 typedef typename std::remove_reference<Container>::type::value_type T;
4342 return sort_by(std::less<T>(), std::forward<Container>(xs));
4343 }
4344
4345 namespace internal
4346 {
4347
4348 template <typename Compare, typename T>
stable_sort_by(internal::reuse_container_t,Compare comp,std::list<T> && xs)4349 std::list<T> stable_sort_by(internal::reuse_container_t, Compare comp,
4350 std::list<T>&& xs)
4351 {
4352 xs.sort(comp); // std::list<T>::sort ist already stable.
4353 return std::forward<std::list<T>>(xs);
4354 }
4355
4356 template <typename Compare, typename T>
stable_sort_by(internal::create_new_container_t,Compare comp,const std::list<T> & xs)4357 std::list<T> stable_sort_by(internal::create_new_container_t, Compare comp,
4358 const std::list<T>& xs)
4359 {
4360 auto result = xs;
4361 result.sort(comp); // std::list<T>::sort ist already stable.
4362 return result;
4363 }
4364
4365 template <typename Compare, typename Container>
stable_sort_by(internal::reuse_container_t,Compare comp,Container && xs)4366 Container stable_sort_by(internal::reuse_container_t, Compare comp,
4367 Container&& xs)
4368 {
4369 std::sort(std::begin(xs), std::end(xs), comp);
4370 return std::forward<Container>(xs);
4371 }
4372
4373 template <typename Compare, typename Container>
stable_sort_by(internal::create_new_container_t,Compare comp,const Container & xs)4374 Container stable_sort_by(internal::create_new_container_t, Compare comp,
4375 const Container& xs)
4376 {
4377 auto result = xs;
4378 std::sort(std::begin(result), std::end(result), comp);
4379 return result;
4380 }
4381
4382 } // namespace internal
4383
4384
4385 // API search type: stable_sort_by : (((a, a) -> Bool), [a]) -> [a]
4386 // fwd bind count: 1
4387 // Sort a sequence stably by given less comparator.
4388 template <typename Compare, typename Container,
4389 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
stable_sort_by(Compare comp,Container && xs)4390 ContainerOut stable_sort_by(Compare comp, Container&& xs)
4391 {
4392 return internal::stable_sort_by(internal::can_reuse_v<Container>{},
4393 comp, std::forward<Container>(xs));
4394 }
4395
4396 // API search type: stable_sort_on : ((a -> b), [a]) -> [a]
4397 // fwd bind count: 1
4398 // Sort a sequence stably by given transformer.
4399 template <typename F, typename Container,
4400 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
stable_sort_on(F f,Container && xs)4401 ContainerOut stable_sort_on(F f, Container&& xs)
4402 {
4403 return stable_sort_by(internal::is_less_by_struct<F>(f),
4404 std::forward<Container>(xs));
4405 }
4406
4407 // API search type: stable_sort : [a] -> [a]
4408 // fwd bind count: 0
4409 // Sort a sequence stably to ascending order using std::less.
4410 template <typename Container,
4411 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
stable_sort(Container && xs)4412 ContainerOut stable_sort(Container&& xs)
4413 {
4414 typedef typename std::remove_reference<Container>::type::value_type T;
4415 return stable_sort_by(std::less<T>(), std::forward<Container>(xs));
4416 }
4417
4418 namespace internal
4419 {
4420
4421 template <typename Compare, typename Container>
partial_sort_by(internal::reuse_container_t,Compare comp,std::size_t count,Container && xs)4422 Container partial_sort_by(internal::reuse_container_t, Compare comp,
4423 std::size_t count, Container&& xs)
4424 {
4425 if (count > xs.size())
4426 {
4427 count = xs.size();
4428 }
4429 auto middle = std::begin(xs);
4430 internal::advance_iterator(middle, count);
4431 std::partial_sort(std::begin(xs), middle, std::end(xs), comp);
4432 return std::forward<Container>(get_segment(internal::reuse_container_t(),
4433 0, count, xs));
4434 }
4435
4436 template <typename Compare, typename Container>
partial_sort_by(internal::create_new_container_t,Compare comp,std::size_t count,const Container & xs)4437 Container partial_sort_by(internal::create_new_container_t, Compare comp,
4438 std::size_t count, const Container& xs)
4439 {
4440 auto result = xs;
4441 return partial_sort_by(
4442 internal::reuse_container_t(), comp, count, std::move(result));
4443 }
4444
4445 } // namespace internal
4446
4447 // API search type: partial_sort_by : (((a, a) -> Bool), Int, [a]) -> [a]
4448 // fwd bind count: 2
4449 // Partially sort a sequence by a given less comparator.
4450 // Returns only the sorted segment.
4451 template <typename Compare, typename Container,
4452 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
partial_sort_by(Compare comp,std::size_t count,Container && xs)4453 ContainerOut partial_sort_by(Compare comp, std::size_t count, Container&& xs)
4454 {
4455 return internal::partial_sort_by(internal::can_reuse_v<Container>{},
4456 comp, count, std::forward<Container>(xs));
4457 }
4458
4459 // API search type: partial_sort_on : ((a -> b), Int, [a]) -> [a]
4460 // fwd bind count: 2
4461 // Partially sort a sequence by a given transformer.
4462 // Returns only the sorted segment.
4463 template <typename F, typename Container,
4464 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
partial_sort_on(F f,std::size_t count,Container && xs)4465 ContainerOut partial_sort_on(F f, std::size_t count, Container&& xs)
4466 {
4467 return partial_sort_by(internal::is_less_by_struct<F>(f), count,
4468 std::forward<Container>(xs));
4469 }
4470
4471 // API search type: partial_sort : (Int, [a]) -> [a]
4472 // fwd bind count: 1
4473 // Partially sort a sequence in ascending order using std::less.
4474 // Returns only the sorted segment.
4475 template <typename Container,
4476 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
partial_sort(std::size_t count,Container && xs)4477 ContainerOut partial_sort(std::size_t count, Container&& xs)
4478 {
4479 typedef typename std::remove_reference<Container>::type::value_type T;
4480 return partial_sort_by(std::less<T>(), count,
4481 std::forward<Container>(xs));
4482 }
4483
4484 // API search type: nth_element_by : (((a, a) -> Bool), Int, [a]) -> a
4485 // fwd bind count: 2
4486 // Return the nth largest element of a sequence by a given less comparator.
4487 template <typename Compare, typename Container,
4488 typename T = typename Container::value_type>
nth_element_by(Compare comp,std::size_t n,const Container & xs)4489 T nth_element_by(Compare comp, std::size_t n, const Container& xs)
4490 {
4491 assert(n < xs.size());
4492 auto result = xs;
4493 auto middle = std::begin(result);
4494 internal::advance_iterator(middle, n);
4495 std::nth_element(std::begin(result), middle, std::end(result), comp);
4496 return *middle;
4497 }
4498
4499 // API search type: nth_element_on : ((a -> b), Int, [a]) -> a
4500 // fwd bind count: 2
4501 // Return the nth largest element of a sequence by a given transformer.
4502 template <typename F, typename Container,
4503 typename T = typename Container::value_type>
nth_element_on(F f,std::size_t n,const Container & xs)4504 T nth_element_on(F f, std::size_t n, const Container& xs)
4505 {
4506 return nth_element_by(internal::is_less_by_struct<F>(f), n, xs);
4507 }
4508
4509 // API search type: nth_element : (Int, [a]) -> a
4510 // fwd bind count: 1
4511 // Return the nth largest element of a sequence using std::less.
4512 template <typename Container,
4513 typename T = typename Container::value_type>
nth_element(std::size_t n,const Container & xs)4514 T nth_element(std::size_t n, const Container& xs)
4515 {
4516 return nth_element_by(std::less<T>(), n, xs);
4517 }
4518
4519 namespace internal
4520 {
4521
4522 template <typename BinaryPredicate, typename Container>
unique_by(internal::reuse_container_t,BinaryPredicate pred,Container && xs)4523 Container unique_by(internal::reuse_container_t,
4524 BinaryPredicate pred, Container&& xs)
4525 {
4526 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
4527 const auto it_end = std::unique(std::begin(xs), std::end(xs), pred);
4528 xs.erase(it_end, std::end(xs));
4529 return std::forward<Container>(xs);
4530 }
4531
4532 template <typename BinaryPredicate, typename Container>
unique_by(internal::create_new_container_t,BinaryPredicate pred,const Container & xs)4533 Container unique_by(internal::create_new_container_t,
4534 BinaryPredicate pred, const Container& xs)
4535 {
4536 auto result = xs;
4537 return unique_by(internal::reuse_container_t(), pred, std::move(result));
4538 }
4539
4540 } // namespace internal
4541
4542 // API search type: unique_by : (((a, a) -> Bool), [a]) -> [a]
4543 // fwd bind count: 1
4544 // Like unique, eliminates all but the first element
4545 // from every consecutive group of equivalent elements from the sequence;
4546 // but with a user supplied equality predicate.
4547 // See nub_by for making elements globally unique in a sequence.
4548 // O(n)
4549 template <typename BinaryPredicate, typename Container,
4550 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
unique_by(BinaryPredicate pred,Container && xs)4551 ContainerOut unique_by(BinaryPredicate pred, Container&& xs)
4552 {
4553 return internal::unique_by(internal::can_reuse_v<Container>{},
4554 pred, std::forward<Container>(xs));
4555 }
4556
4557 // API search type: unique_on : ((a -> b), [a]) -> [a]
4558 // fwd bind count: 1
4559 // Like unique, eliminates all but the first element
4560 // from every consecutive group of equivalent elements from the sequence;
4561 // but with a user supplied transformation (e.g. getter).
4562 // See nub_on for making elements globally unique in a sequence.
4563 // O(n)
4564 // Also known as drop_repeats.
4565 template <typename F, typename Container,
4566 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
unique_on(F f,Container && xs)4567 ContainerOut unique_on(F f, Container&& xs)
4568 {
4569 return unique_by(internal::is_equal_by_struct<F>(f),
4570 std::forward<Container>(xs));
4571 }
4572
4573 // API search type: unique : [a] -> [a]
4574 // fwd bind count: 0
4575 // Eliminates all but the first element
4576 // from every consecutive group of equivalent elements from the sequence.
4577 // unique([1,2,2,3,2]) == [1,2,3,2]
4578 // See nub for making elements globally unique in a sequence.
4579 // O(n)
4580 template <typename Container,
4581 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
unique(Container && xs)4582 ContainerOut unique(Container&& xs)
4583 {
4584 typedef typename std::remove_reference<Container>::type::value_type T;
4585 return unique_on(identity<T>, std::forward<Container>(xs));
4586 }
4587
4588 // API search type: intersperse : (a, [a]) -> [a]
4589 // fwd bind count: 1
4590 // Insert a value between all adjacent values in a sequence.
4591 // intersperse(0, [1, 2, 3]) == [1, 0, 2, 0, 3]
4592 // Also known as interpose.
4593 template <typename Container,
4594 typename X = typename Container::value_type>
4595 Container intersperse(const X& value, const Container& xs)
4596 {
4597 if (xs.empty())
4598 return Container();
4599 if (size_of_cont(xs) == 1)
4600 return xs;
4601 Container result;
4602 internal::prepare_container(result, std::max<std::size_t>(0, size_of_cont(xs)*2-1));
4603 auto it = internal::get_back_inserter(result);
4604 for_each(std::begin(xs), --std::end(xs), [&value, &it](const X& x)
__anon1e7ca4c42702(const X& x) 4605 {
4606 *it = x;
4607 *it = value;
4608 });
4609 *it = xs.back();
4610 return result;
4611 }
4612
4613 // API search type: join : ([a], [[a]]) -> [a]
4614 // fwd bind count: 1
4615 // Inserts a separator sequence in between the elements
4616 // of a sequence of sequences and concatenates the result.
4617 // Also known as intercalate or implode.
4618 // join(", ", ["a", "bee", "cee"]) == "a, bee, cee"
4619 // join([0, 0], [[1], [2], [3, 4]]) == [1, 0, 0, 2, 0, 0, 3, 4]
4620 template <typename Container,
4621 typename X = typename Container::value_type>
join(const X & separator,const Container & xs)4622 X join(const X& separator, const Container& xs)
4623 {
4624 return concat(intersperse(separator, xs));
4625 }
4626
4627 // API search type: join_elem : (a, [[a]]) -> [a]
4628 // fwd bind count: 1
4629 // Inserts a separator in between the elements
4630 // of a sequence of sequences and concatenates the result.
4631 // Also known as intercalate_elem.
4632 // join_elem(';', ["a", "bee", "cee"]) == "a;bee;cee"
4633 // join_elem(0, [[1], [2], [3, 4]]) == [1, 0, 2, 0, 3, 4]]
4634 template <typename Container,
4635 typename Inner = typename Container::value_type,
4636 typename X = typename Inner::value_type>
4637 Inner join_elem(const X& separator, const Container& xs)
4638 {
4639 return join(Inner(1, separator), xs);
4640 }
4641
4642 // API search type: is_elem_of_by : ((a -> Bool), [a]) -> Bool
4643 // fwd bind count: 1
4644 // Checks if at least one element of the container fulfils a predicate.
4645 // is_elem_of_by((==), [1,2,3]) == true
4646 template <typename UnaryPredicate, typename Container>
is_elem_of_by(UnaryPredicate pred,const Container & xs)4647 bool is_elem_of_by(UnaryPredicate pred, const Container& xs)
4648 {
4649 return std::find_if(std::begin(xs), std::end(xs), pred) != std::end(xs);
4650 }
4651
4652 // API search type: is_elem_of : (a, [a]) -> Bool
4653 // fwd bind count: 1
4654 // Checks if an element is a member of a container.
4655 // is_elem_of(2, [1,2,3]) == true
4656 // Also known as flip(contains).
4657 template <typename Container>
is_elem_of(const typename Container::value_type & x,const Container & xs)4658 bool is_elem_of(const typename Container::value_type& x, const Container& xs)
4659 {
4660 return is_elem_of_by(is_equal_to(x), xs);
4661 }
4662
4663 // API search type: nub_by : (((a, a) -> Bool), [a]) -> [a]
4664 // fwd bind count: 1
4665 // Makes the elements in a container unique with respect to a predicate
4666 // nub_by((==), [1,2,2,3,2]) == [1,2,3]
4667 // O(n^2)
4668 template <typename Container, typename BinaryPredicate>
4669 Container nub_by(BinaryPredicate p, const Container& xs)
4670 {
4671 Container result;
4672 auto itOut = internal::get_back_inserter(result);
4673 for (const auto &x : xs)
4674 {
4675 auto eqToX = bind_1st_of_2(p, x);
4676 if (!is_elem_of_by(eqToX, result))
4677 {
4678 *itOut = x;
4679 }
4680 }
4681 return result;
4682 }
4683
4684 // API search type: nub_on : ((a -> b), [a]) -> [a]
4685 // fwd bind count: 1
4686 // Makes the elements in a container unique
4687 // with respect to their function value.
4688 // nub_on((mod 10), [12,32,15]) == [12,15]
4689 // O(n^2)
4690 template <typename Container, typename F>
4691 Container nub_on(F f, const Container& xs)
4692 {
4693 return nub_by(is_equal_by(f), xs);
4694 }
4695
4696 // API search type: nub : [a] -> [a]
4697 // fwd bind count: 0
4698 // Makes the elements in a container unique.
4699 // nub([1,2,2,3,2]) == [1,2,3]
4700 // O(n^2)
4701 // Also known as distinct.
4702 template <typename Container>
nub(const Container & xs)4703 Container nub(const Container& xs)
4704 {
4705 typedef typename Container::value_type T;
4706 return nub_by(std::equal_to<T>(), xs);
4707 }
4708
4709 // API search type: all_unique_by_eq : (((a, a) -> Bool), [a]) -> Bool
4710 // fwd bind count: 1
4711 // Checks if all elements in a container are unique
4712 // with respect to a predicate.
4713 // Returns true for empty containers.
4714 // O(n^2)
4715 template <typename Container, typename BinaryPredicate>
all_unique_by_eq(BinaryPredicate p,const Container & xs)4716 bool all_unique_by_eq(BinaryPredicate p, const Container& xs)
4717 {
4718 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
4719 return size_of_cont(nub_by(p, xs)) == size_of_cont(xs);
4720 }
4721
4722 // API search type: all_unique_on : ((a -> b), [a]) -> Bool
4723 // fwd bind count: 1
4724 // Checks if all elements in a container are unique
4725 // with respect to their function values.
4726 // Returns true for empty containers.
4727 // O(n^2)
4728 template <typename Container, typename F>
all_unique_on(F f,const Container & xs)4729 bool all_unique_on(F f, const Container& xs)
4730 {
4731 return all_unique_by_eq(is_equal_by(f), xs);
4732 }
4733
4734 // API search type: all_unique : [a] -> Bool
4735 // fwd bind count: 0
4736 // Checks if all elements in a container are unique.
4737 // Returns true for empty containers.
4738 // O(n^2)
4739 template <typename Container>
all_unique(const Container & xs)4740 bool all_unique(const Container& xs)
4741 {
4742 typedef typename Container::value_type T;
4743 auto comp = std::equal_to<T>();
4744 return all_unique_by_eq(comp, xs);
4745 }
4746
4747 // API search type: is_strictly_sorted_by : (((a, a) -> Bool), [a]) -> Bool
4748 // fwd bind count: 1
4749 // Checks if a container already is strictly sorted using a predicate.
4750 // comp(a, b) must return true only if a < b.
4751 // O(n)
4752 template <typename Container, typename Compare>
is_strictly_sorted_by(Compare comp,const Container & xs)4753 bool is_strictly_sorted_by(Compare comp, const Container& xs)
4754 {
4755 internal::check_compare_for_container<Compare, Container>();
4756 if (size_of_cont(xs) < 2)
4757 return true;
4758 auto it1 = std::begin(xs);
4759 for (auto it2 = it1 + 1; it2 < std::end(xs); ++it1, ++it2)
4760 if (!internal::invoke(comp, *it1, *it2))
4761 return false;
4762 return true;
4763 }
4764
4765 // API search type: is_strictly_sorted_on : ((a -> b), [a]) -> Bool
4766 // fwd bind count: 1
4767 // Checks if a container already is strictly sorted using a transformer.
4768 // O(n)
4769 template <typename Container, typename F>
is_strictly_sorted_on(F f,const Container & xs)4770 bool is_strictly_sorted_on(F f, const Container& xs)
4771 {
4772 return is_strictly_sorted_by(is_less_by(f), xs);
4773 }
4774
4775 // API search type: is_strictly_sorted : [a] -> Bool
4776 // fwd bind count: 0
4777 // Checks if a container already is strictly sorted
4778 // in ascending order using std::less.
4779 // O(n)
4780 template <typename Container>
is_strictly_sorted(const Container & xs)4781 bool is_strictly_sorted(const Container& xs)
4782 {
4783 typedef typename Container::value_type T;
4784 auto comp = std::less<T>();
4785 return is_strictly_sorted_by(comp, xs);
4786 }
4787
4788 // API search type: is_sorted_by : (((a, a) -> Bool), [a]) -> Bool
4789 // fwd bind count: 1
4790 // Checks if a container already is sorted using a predicate.
4791 // comp(a, b) must return true only if a < b.
4792 // O(n)
4793 template <typename Container, typename Compare>
is_sorted_by(Compare comp,const Container & xs)4794 bool is_sorted_by(Compare comp, const Container& xs)
4795 {
4796 internal::check_compare_for_container<Compare, Container>();
4797 if (size_of_cont(xs) < 2)
4798 return true;
4799 auto it1 = std::begin(xs);
4800 for (auto it2 = it1 + 1; it2 < std::end(xs); ++it1, ++it2)
4801 if (internal::invoke(comp, *it2, *it1))
4802 return false;
4803 return true;
4804 }
4805
4806 // API search type: is_sorted_on : ((a -> b), [a]) -> Bool
4807 // fwd bind count: 1
4808 // Checks if a container already is strictly sorted using a transformer.
4809 // O(n)
4810 template <typename Container, typename F>
is_sorted_on(F f,const Container & xs)4811 bool is_sorted_on(F f, const Container& xs)
4812 {
4813 return is_sorted_by(is_less_by(f), xs);
4814 }
4815
4816 // API search type: is_sorted : [a] -> Bool
4817 // fwd bind count: 0
4818 // Checks if a container already is sorted
4819 // in ascending order using std::less.
4820 // O(n)
4821 template <typename Container>
is_sorted(const Container & xs)4822 bool is_sorted(const Container& xs)
4823 {
4824 typedef typename Container::value_type T;
4825 auto comp = std::less<T>();
4826 return is_sorted_by(comp, xs);
4827 }
4828
4829 // API search type: is_prefix_of : ([a], [a]) -> Bool
4830 // fwd bind count: 1
4831 // Checks if a containers starts with a token.
4832 // is_prefix_of("Fun", "FunctionalPlus") == true
4833 template <typename Container>
is_prefix_of(const Container & token,const Container & xs)4834 bool is_prefix_of(const Container& token, const Container& xs)
4835 {
4836 if (size_of_cont(token) > size_of_cont(xs))
4837 return false;
4838 return get_segment(0, size_of_cont(token), xs) == token;
4839 }
4840
4841 // API search type: is_suffix_of : ([a], [a]) -> Bool
4842 // fwd bind count: 1
4843 // Checks if a containers contains a token as a segment.
4844 // is_suffix_of("us", "FunctionalPlus") == true
4845 template <typename Container>
is_suffix_of(const Container & token,const Container & xs)4846 bool is_suffix_of(const Container& token, const Container& xs)
4847 {
4848 if (size_of_cont(token) > size_of_cont(xs))
4849 return false;
4850 return get_segment(size_of_cont(xs) - size_of_cont(token),
4851 size_of_cont(xs), xs) == token;
4852 }
4853
4854 // API search type: all_by : ((a -> Bool), [a]) -> Bool
4855 // fwd bind count: 1
4856 // Checks if a containers contains a token as a segment.
4857 // all_by(is_even, [2, 4, 6]) == true
4858 // Returns true for empty containers.
4859 template <typename UnaryPredicate, typename Container>
all_by(UnaryPredicate p,const Container & xs)4860 bool all_by(UnaryPredicate p, const Container& xs)
4861 {
4862 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
4863 return std::all_of(std::begin(xs), std::end(xs), p);
4864 }
4865
4866 // API search type: all : [Bool] -> Bool
4867 // fwd bind count: 0
4868 // Checks if all values in a container evaluate to true.
4869 // all([true, false, true]) == false
4870 // Returns true for empty containers.
4871 template <typename Container>
all(const Container & xs)4872 bool all(const Container& xs)
4873 {
4874 typedef typename Container::value_type T;
4875 return all_by(identity<T>, xs);
4876 }
4877
4878 // API search type: all_the_same_by : (((a, a) -> Bool), [a]) -> Bool
4879 // fwd bind count: 1
4880 // Checks if all values in a container are equal using a binary predicate.
4881 // Returns true for empty containers.
4882 template <typename Container, typename BinaryPredicate>
all_the_same_by(BinaryPredicate p,const Container & xs)4883 bool all_the_same_by(BinaryPredicate p, const Container& xs)
4884 {
4885 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
4886 if (size_of_cont(xs) < 2)
4887 return true;
4888 auto unaryPredicate = bind_1st_of_2(p, xs.front());
4889 return all_by(unaryPredicate, xs);
4890 }
4891
4892 // API search type: all_the_same_on : ((a -> b), [a]) -> Bool
4893 // fwd bind count: 1
4894 // Checks if all values in a container are equal using a transformer.
4895 // Returns true for empty containers.
4896 template <typename Container, typename F>
all_the_same_on(F f,const Container & xs)4897 bool all_the_same_on(F f, const Container& xs)
4898 {
4899 if (size_of_cont(xs) < 2)
4900 return true;
4901 auto unaryPredicate = is_equal_by_to(f, f(xs.front()));
4902 return all_by(unaryPredicate, xs);
4903 }
4904
4905 // API search type: all_the_same : [a] -> Bool
4906 // fwd bind count: 0
4907 // Checks if all values in a container are equal.
4908 // Returns true for empty containers.
4909 template <typename Container>
all_the_same(const Container & xs)4910 bool all_the_same(const Container& xs)
4911 {
4912 typedef typename Container::value_type T;
4913 auto binaryPredicate = std::equal_to<T>();
4914 return all_the_same_by(binaryPredicate, xs);
4915 }
4916
4917 // API search type: numbers_step : (a, a, a) -> [a]
4918 // fwd bind count: 2
4919 // Return a sequence of numbers using a specific step.
4920 // numbers_step(2, 9, 2) == [2, 4, 6, 8]
4921 template <typename T,
4922 typename ContainerOut = std::vector<T>>
numbers_step(const T start,const T end,const T step)4923 ContainerOut numbers_step
4924 (const T start, const T end, const T step)
4925 {
4926 ContainerOut result;
4927 if ((step > 0 && start >= end) ||
4928 (step < 0 && start <= end) ||
4929 step == 0)
4930 {
4931 return result;
4932 }
4933 std::size_t size = static_cast<std::size_t>((end - start) / step);
4934 internal::prepare_container(result, size);
4935 auto it = internal::get_back_inserter<ContainerOut>(result);
4936 for (T x = start; x < end; x += step)
4937 *it = x;
4938 return result;
4939 }
4940
4941 // API search type: numbers : (a, a) -> [a]
4942 // fwd bind count: 1
4943 // Return an ascending sequence of numbers..
4944 // Also known as range.
4945 // numbers(2, 9) == [2, 3, 4, 5, 6, 7, 8]
4946 template <typename T,
4947 typename ContainerOut = std::vector<T>>
numbers(const T start,const T end)4948 ContainerOut numbers(const T start, const T end)
4949 {
4950 return numbers_step<T, ContainerOut>(start, end, 1);
4951 }
4952
4953 // API search type: singleton_seq : a -> [a]
4954 // fwd bind count: 0
4955 // Construct a sequence containing a single value.
4956 // singleton_seq(3) == [3].
4957 template <typename T, typename ContainerOut = std::vector<T>>
singleton_seq(const T & x)4958 ContainerOut singleton_seq(const T& x)
4959 {
4960 return ContainerOut(1, x);
4961 }
4962
4963 // API search type: all_idxs : [a] -> [Int]
4964 // fwd bind count: 0
4965 // Returns a vector containing all valid indices of sequence xs.
4966 // all_idxs([6,4,7,6]) == [0,1,2,3]
4967 template <typename Container>
all_idxs(const Container & xs)4968 std::vector<std::size_t> all_idxs(const Container& xs)
4969 {
4970 return numbers<std::size_t>(0, size_of_cont(xs));
4971 }
4972
4973 // API search type: init : [a] -> [a]
4974 // fwd bind count: 0
4975 // init([0,1,2,3]) == [0,1,2]
4976 // Unsafe! xs must be non-empty.
4977 template <typename Container,
4978 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
init(Container && xs)4979 ContainerOut init(Container&& xs)
4980 {
4981 assert(!is_empty(xs));
4982 return get_segment(0, size_of_cont(std::forward<Container>(xs)) - 1, xs);
4983 }
4984
4985 // API search type: tail : [a] -> [a]
4986 // fwd bind count: 0
4987 // Drops the first element of a container, keeps the rest. Unsafe!
4988 // tail([0,1,2,3]) == [1,2,3]
4989 // Unsafe! xs must be non-empty.
4990 template <typename Container,
4991 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
tail(Container && xs)4992 ContainerOut tail(Container&& xs)
4993 {
4994 assert(!is_empty(xs));
4995 return get_segment(1, size_of_cont(std::forward<Container>(xs)), xs);
4996 }
4997
4998 // API search type: head : [a] -> a
4999 // fwd bind count: 0
5000 // Return the first element of a container.
5001 // head([0,1,2,3]) == 0
5002 // Unsafe! xs must be non-empty.
5003 template <typename Container>
head(const Container & xs)5004 typename Container::value_type head(const Container& xs)
5005 {
5006 assert(!is_empty(xs));
5007 return xs.front();
5008 }
5009
5010 // API search type: last : [a] -> a
5011 // fwd bind count: 0
5012 // Return the last element of a container.
5013 // last([0,1,2,3]) == 3
5014 // Unsafe! xs must be non-empty.
5015 template <typename Container>
last(const Container & xs)5016 typename Container::value_type last(const Container& xs)
5017 {
5018 assert(!is_empty(xs));
5019 return xs.back();
5020 }
5021
5022 // API search type: mean_stddev : [a] -> (a, a)
5023 // fwd bind count: 0
5024 // Calculates the mean and the population standard deviation.
5025 // mean_stddev([4, 8]) == (6, 2)
5026 // mean_stddev([1, 3, 7, 4]) == (3.75, 2.5)
5027 // xs must be non-empty.
5028 template <typename Result, typename Container>
mean_stddev(const Container & xs)5029 std::pair<Result, Result> mean_stddev(const Container& xs)
5030 {
5031 assert(size_of_cont(xs) != 0);
5032
5033 // http://stackoverflow.com/a/7616783/1866775
5034 Result sum = static_cast<Result>(
5035 internal::accumulate(xs.begin(), xs.end(),
5036 static_cast<typename Container::value_type>(0)));
5037 Result mean = sum / static_cast<Result>(xs.size());
5038
5039 std::vector<Result> diff(xs.size());
5040 std::transform(xs.begin(), xs.end(), diff.begin(),
5041 [mean](Result x)
5042 {
5043 return x - mean;
5044 });
5045 Result sq_sum = std::inner_product(
5046 diff.begin(), diff.end(), diff.begin(), static_cast<Result>(0));
5047 Result stddev = std::sqrt(sq_sum / static_cast<Result>(xs.size()));
5048 return std::make_pair(mean, stddev);
5049 }
5050
5051 // API search type: count_occurrences_by : ((a -> b), [a]) -> Map b Int
5052 // fwd bind count: 1
5053 // Returns a discrete frequency distribution of the elements in a container
5054 // applying a specific transformer.
5055 // count_occurrences_by(floor, [1.1, 2.3, 2.7, 3.6, 2.4]) == [(1, 1), (2, 3), (3, 1)]
5056 // O(n)
5057 template <typename F, typename ContainerIn>
count_occurrences_by(F f,const ContainerIn & xs)5058 auto count_occurrences_by(F f, const ContainerIn& xs)
5059 {
5060 using In = typename ContainerIn::value_type;
5061 using MapOut =
5062 std::map<std::decay_t<internal::invoke_result_t<F, In>>, std::size_t>;
5063
5064 internal::trigger_static_asserts<internal::unary_function_tag, F, typename ContainerIn::value_type>();
5065 MapOut result;
5066 for (const auto& x : xs)
5067 {
5068 ++result[internal::invoke(f, x)];
5069 }
5070 return result;
5071 }
5072
5073 // API search type: count_occurrences : [a] -> Map a Int
5074 // fwd bind count: 0
5075 // Returns a discrete frequency distribution of the elements in a container
5076 // applying a specific transformer.
5077 // Can be used to create a histogram.
5078 // count_occurrences([1,2,2,3,2]) == [(1, 1), (2, 3), (3, 1)]
5079 // O(n)
5080 template <typename ContainerIn,
5081 typename MapOut = typename std::map<
5082 typename ContainerIn::value_type, std::size_t>>
count_occurrences(const ContainerIn & xs)5083 MapOut count_occurrences(const ContainerIn& xs)
5084 {
5085 return count_occurrences_by(identity<typename ContainerIn::value_type>, xs);
5086 }
5087
5088 // API search type: lexicographical_less_by : (((a, a) -> Bool), [a], [a]) -> Bool
5089 // fwd bind count: 2
5090 // Lexicographical less-than comparison using a specific predicate.
5091 // lexicographical_less_by((<), [0,1,2,2,4,5], [0,1,2,3,4,5]) == true
5092 // lexicographical_less_by((<), "012245", "012345") == true
5093 // lexicographical_less_by((<), "01234", "012345") == true
5094 // lexicographical_less_by((<), "012345", "01234") == false
5095 // lexicographical_less_by((<), "012345", "012345") == false
5096 template <typename Container, typename BinaryPredicate>
lexicographical_less_by(BinaryPredicate p,const Container & xs,const Container & ys)5097 bool lexicographical_less_by(BinaryPredicate p,
5098 const Container& xs, const Container& ys)
5099 {
5100 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
5101 auto itXs = std::begin(xs);
5102 auto itYs = std::begin(ys);
5103 while (itXs != std::end(xs) && itYs != std::end(ys))
5104 {
5105 if (internal::invoke(p, *itXs, *itYs))
5106 {
5107 return true;
5108 }
5109 if (internal::invoke(p, *itYs, *itXs))
5110 {
5111 return false;
5112 }
5113 ++itXs;
5114 ++itYs;
5115 }
5116 if (size_of_cont(xs) < size_of_cont(ys))
5117 {
5118 return true;
5119 }
5120 return false;
5121 }
5122
5123 // API search type: lexicographical_less : ([a], [a]) -> Bool
5124 // fwd bind count: 1
5125 // Lexicographical less-than comparison.
5126 // lexicographical_less([0,1,2,2,4,5], [0,1,2,3,4,5]) == true
5127 // lexicographical_less("012245", "012345") == true
5128 // lexicographical_less("01234", "012345") == true
5129 // lexicographical_less("012345", "01234") == false
5130 // lexicographical_less("012345", "012345") == false
5131 template <typename Container>
lexicographical_less(const Container & xs,const Container & ys)5132 bool lexicographical_less(const Container& xs, const Container& ys)
5133 {
5134 return lexicographical_less_by(
5135 is_less<typename Container::value_type>, xs, ys);
5136 }
5137
5138 // API search type: lexicographical_sort : [[a]] -> [[a]]
5139 // fwd bind count: 0
5140 // sort by lexicographical_less
5141 template <typename Container,
5142 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
lexicographical_sort(Container && xs)5143 ContainerOut lexicographical_sort(Container&& xs)
5144 {
5145 typedef typename std::remove_reference<Container>::type::value_type T;
5146 return sort_by(lexicographical_less<T>, std::forward<Container>(xs));
5147 }
5148
5149 // API search type: replicate : (Int, a) -> [a]
5150 // fwd bind count: 1
5151 // Create a sequence containing x n times.
5152 // replicate(3, 1) == [1, 1, 1]
5153 template <typename T,
5154 typename ContainerOut = std::vector<T>>
replicate(std::size_t n,const T & x)5155 ContainerOut replicate(std::size_t n, const T& x)
5156 {
5157 return ContainerOut(n, x);
5158 }
5159
5160 namespace internal
5161 {
5162
5163 template <typename UnaryPredicate, typename T>
instead_of_if(internal::reuse_container_t,UnaryPredicate pred,const T & alt,T && x)5164 T instead_of_if(internal::reuse_container_t, UnaryPredicate pred,
5165 const T& alt, T&& x)
5166 {
5167 if (internal::invoke(pred, x))
5168 return alt;
5169 else
5170 return std::forward<T>(x);
5171 }
5172
5173 template <typename UnaryPredicate, typename T>
instead_of_if(internal::create_new_container_t,UnaryPredicate pred,const T & alt,const T & x)5174 T instead_of_if(internal::create_new_container_t, UnaryPredicate pred,
5175 const T& alt, const T& x)
5176 {
5177 if (internal::invoke(pred, x))
5178 return alt;
5179 else
5180 return x;
5181 }
5182
5183 } // namespace internal
5184
5185 // API search type: instead_of_if : ((a -> Bool), a, a) -> a
5186 // fwd bind count: 2
5187 // Return alt if pred(x), otherwise x itself.
5188 template <typename UnaryPredicate, typename T, typename TAlt>
instead_of_if(UnaryPredicate pred,const TAlt & alt,T && x)5189 auto instead_of_if(UnaryPredicate pred, const TAlt& alt, T&& x)
5190 {
5191 return internal::instead_of_if(internal::can_reuse_v<T>{},
5192 pred, alt, std::forward<T>(x));
5193 }
5194
5195 // API search type: instead_of_if_empty : ((a -> Bool), [a], [a]) -> [a]
5196 // fwd bind count: 2
5197 // Return alt if xs is empty, otherwise xs itself.
5198 template <typename Container, typename ContainerAlt,
5199 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
instead_of_if_empty(const ContainerAlt & alt,Container && xs)5200 ContainerOut instead_of_if_empty(const ContainerAlt& alt, Container&& xs)
5201 {
5202 return instead_of_if(
5203 is_empty<internal::remove_const_and_ref_t<Container>>,
5204 alt, std::forward<Container>(xs));
5205 }
5206
5207 } // namespace fplus
5208
5209 //
5210 // container_properties.hpp
5211 //
5212
5213 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
5214 // https://github.com/Dobiasd/FunctionalPlus
5215 // Distributed under the Boost Software License, Version 1.0.
5216 // (See accompanying file LICENSE_1_0.txt or copy at
5217 // http://www.boost.org/LICENSE_1_0.txt)
5218
5219
5220
5221 //
5222 // generate.hpp
5223 //
5224
5225 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
5226 // https://github.com/Dobiasd/FunctionalPlus
5227 // Distributed under the Boost Software License, Version 1.0.
5228 // (See accompanying file LICENSE_1_0.txt or copy at
5229 // http://www.boost.org/LICENSE_1_0.txt)
5230
5231
5232
5233 //
5234 // filter.hpp
5235 //
5236
5237 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
5238 // https://github.com/Dobiasd/FunctionalPlus
5239 // Distributed under the Boost Software License, Version 1.0.
5240 // (See accompanying file LICENSE_1_0.txt or copy at
5241 // http://www.boost.org/LICENSE_1_0.txt)
5242
5243
5244
5245 //
5246 // result.hpp
5247 //
5248
5249 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
5250 // https://github.com/Dobiasd/FunctionalPlus
5251 // Distributed under the Boost Software License, Version 1.0.
5252 // (See accompanying file LICENSE_1_0.txt or copy at
5253 // http://www.boost.org/LICENSE_1_0.txt)
5254
5255
5256
5257
5258 #include <cassert>
5259 #include <functional>
5260 #include <memory>
5261
5262 namespace fplus
5263 {
5264
5265 template <typename Ok, typename Error>
5266 class result;
5267
5268 template <typename Ok, typename Error>
5269 result<Ok, Error> ok(const Ok& val);
5270
5271 template <typename Ok, typename Error>
5272 result<Ok, Error> error(const Error& error);
5273
5274 // Can hold a value of type Ok or an error of type Error.
5275 template <typename Ok, typename Error>
5276 class result
5277 {
5278 public:
is_ok() const5279 bool is_ok() const { return static_cast<bool>(ptr_ok_); }
is_error() const5280 bool is_error() const { return static_cast<bool>(ptr_error_); }
unsafe_get_ok() const5281 const Ok& unsafe_get_ok() const {
5282 check_either_or_invariant(); assert(is_ok()); return *ptr_ok_;
5283 }
unsafe_get_error() const5284 const Error& unsafe_get_error() const {
5285 check_either_or_invariant(); assert(is_error()); return *ptr_error_;
5286 }
5287 typedef Ok ok_t;
5288 typedef Error error_t;
5289
result(const result<Ok,Error> & other)5290 result(const result<Ok, Error>& other) :
5291 ptr_ok_(other.is_ok() ? ptr_ok(new Ok(other.unsafe_get_ok())) : ptr_ok()),
5292 ptr_error_(other.is_error() ? ptr_error(new Error(other.unsafe_get_error())) : ptr_error())
5293 {
5294 check_either_or_invariant();
5295 }
operator =(const result<Ok,Error> & other)5296 result<Ok, Error>& operator = (const result<Ok, Error>& other)
5297 {
5298 ptr_ok_ = other.is_ok() ? ptr_ok(new Ok(other.unsafe_get_ok())) : ptr_ok();
5299 ptr_error_ = other.is_error() ? ptr_error(new Error(other.unsafe_get_error())) : ptr_error();
5300 return *this;
5301 }
5302 private:
check_either_or_invariant() const5303 void check_either_or_invariant() const
5304 {
5305 assert(is_ok() != is_error());
5306 }
result()5307 result() : ptr_ok_(ptr_ok()), ptr_error_(ptr_error()) {}
5308 typedef std::unique_ptr<Ok> ptr_ok;
5309 typedef std::unique_ptr<Error> ptr_error;
5310 friend result<Ok, Error> ok<Ok, Error>(const Ok& ok);
5311 friend result<Ok, Error> error<Ok, Error>(const Error& error);
5312 ptr_ok ptr_ok_;
5313 ptr_error ptr_error_;
5314 };
5315
5316 // API search type: is_ok : Result a b -> Bool
5317 // fwd bind count: 0
5318 // Is not error?
5319 template <typename Ok, typename Error>
is_ok(const result<Ok,Error> & result)5320 bool is_ok(const result<Ok, Error>& result)
5321 {
5322 return result.is_ok();
5323 }
5324
5325 // API search type: is_error : Result a b -> Bool
5326 // fwd bind count: 0
5327 // Is not OK?
5328 template <typename Ok, typename Error>
is_error(const result<Ok,Error> & result)5329 bool is_error(const result<Ok, Error>& result)
5330 {
5331 return !is_ok(result);
5332 }
5333
5334 // API search type: unsafe_get_ok : Result a b -> a
5335 // fwd bind count: 0
5336 // Crashes if result is error!
5337 template <typename Ok, typename Error>
5338 Ok unsafe_get_ok(const result<Ok, Error>& result)
5339 {
5340 return result.unsafe_get_ok();
5341 }
5342
5343 // API search type: unsafe_get_error : Result a b -> b
5344 // fwd bind count: 0
5345 // Crashes if result is ok!
5346 template <typename Ok, typename Error>
unsafe_get_error(const result<Ok,Error> & result)5347 Error unsafe_get_error(const result<Ok, Error>& result)
5348 {
5349 return result.unsafe_get_error();
5350 }
5351
5352 // API search type: ok_with_default : (a, Result a b) -> a
5353 // fwd bind count: 1
5354 // Get the value from a result or the default in case it is error.
5355 template <typename Ok, typename Error>
5356 Ok ok_with_default(const Ok& defaultValue, const result<Ok, Error>& result)
5357 {
5358 if (is_ok(result))
5359 return unsafe_get_ok(result);
5360 return defaultValue;
5361 }
5362
5363 // API search type: ok : a -> Result a b
5364 // fwd bind count: 0
5365 // Wrap a value in a result as a Ok.
5366 template <typename Ok, typename Error>
ok(const Ok & val)5367 result<Ok, Error> ok(const Ok& val)
5368 {
5369 result<Ok, Error> x;
5370 x.ptr_ok_.reset(new Ok(val));
5371 return x;
5372 }
5373
5374 // API search type: error : b -> Result a b
5375 // fwd bind count: 0
5376 // Construct an error of a certain result type.
5377 template <typename Ok, typename Error>
error(const Error & error)5378 result<Ok, Error> error(const Error& error)
5379 {
5380 result<Ok, Error> x;
5381 x.ptr_error_.reset(new Error(error));
5382 return x;
5383 }
5384
5385 // API search type: to_maybe : Result a b -> Maybe a
5386 // fwd bind count: 0
5387 // Convert ok to just, error to nothing.
5388 template <typename Ok, typename Error>
to_maybe(const result<Ok,Error> & result)5389 maybe<Ok> to_maybe(const result<Ok, Error>& result)
5390 {
5391 if (is_ok(result))
5392 return just<Ok>(unsafe_get_ok(result));
5393 else
5394 return nothing<Ok>();
5395 }
5396
5397 // API search type: from_maybe : (b, Maybe a) -> Result a b
5398 // fwd bind count: 1
5399 // Convert just to ok, nothing to error.
5400 template <typename Error, typename Ok>
from_maybe(const Error & err,const maybe<Ok> & maybe)5401 result<Ok, Error> from_maybe(const Error& err, const maybe<Ok>& maybe)
5402 {
5403 if (is_just(maybe))
5404 return ok<Ok, Error>(unsafe_get_just(maybe));
5405 else
5406 return error<Ok, Error>(err);
5407 }
5408
5409 // API search type: throw_on_error : (e, Result a b) -> a
5410 // fwd bind count: 1
5411 // Throws the given exception in case of error.
5412 // Return ok value if ok.
5413 template <typename E, typename Ok, typename Error>
5414 Ok throw_on_error(const E& e, const result<Ok, Error>& result)
5415 {
5416 if (is_error(result))
5417 throw e;
5418 return unsafe_get_ok(result);
5419 }
5420
5421 // API search type: throw_type_on_error : Result a b -> a
5422 // Throws the given exception type constructed with error value if error.
5423 // Return ok value if ok.
5424 template <typename E, typename Ok, typename Error>
5425 Ok throw_type_on_error(const result<Ok, Error>& result)
5426 {
5427 if (is_error(result))
5428 throw E(unsafe_get_error(result));
5429 return unsafe_get_ok(result);
5430 }
5431
5432 // True if ok values are the same or if errors are the same.
5433 template <typename Ok, typename Error>
operator ==(const result<Ok,Error> & x,const result<Ok,Error> & y)5434 bool operator == (const result<Ok, Error>& x, const result<Ok, Error>& y)
5435 {
5436 if (is_ok(x) && is_ok(y))
5437 return unsafe_get_ok(x) == unsafe_get_ok(y);
5438 if (is_error(x) && is_error(y))
5439 return unsafe_get_error(x) == unsafe_get_error(y);
5440 return false;
5441 }
5442
5443 // False if ok values are the same or if both errors are the same.
5444 template <typename Ok, typename Error>
operator !=(const result<Ok,Error> & x,const result<Ok,Error> & y)5445 bool operator != (const result<Ok, Error>& x, const result<Ok, Error>& y)
5446 {
5447 return !(x == y);
5448 }
5449
5450 // API search type: lift_result : ((a -> b), Result a c) -> Result b c
5451 // fwd bind count: 1
5452 // Lifts a function into the result functor.
5453 // A function that for example was able to convert and int into a string,
5454 // now can convert a result<int, Err> into a result<string, Err>.
5455 // An error stays the same error, regardless of the conversion.
5456 template <typename Error, typename F, typename A>
lift_result(F f,const result<A,Error> & r)5457 auto lift_result(F f, const result<A, Error>& r)
5458 {
5459 internal::trigger_static_asserts<internal::unary_function_tag, F, A>();
5460
5461 using B = std::decay_t<internal::invoke_result_t<F, A>>;
5462
5463 if (is_ok(r))
5464 return ok<B, Error>(internal::invoke(f, unsafe_get_ok(r)));
5465 return error<B, Error>(unsafe_get_error(r));
5466 }
5467
5468 // API search type: lift_result_both : ((a -> c), (b -> d), Result a b) -> Result c d
5469 // fwd bind count: 2
5470 // Lifts two functions into the result functor.
5471 template <typename F, typename G, typename A, typename B>
lift_result_both(F f,G g,const result<A,B> & r)5472 auto lift_result_both(F f, G g, const result<A, B>& r)
5473 {
5474 internal::trigger_static_asserts<internal::unary_function_tag, F, A>();
5475 internal::trigger_static_asserts<internal::unary_function_tag, G, B>();
5476
5477 using C = std::decay_t<internal::invoke_result_t<F, A>>;
5478 using D = std::decay_t<internal::invoke_result_t<G, B>>;
5479
5480 if (is_ok(r))
5481 return ok<C, D>(internal::invoke(f, unsafe_get_ok(r)));
5482 return error<C, D>(internal::invoke(g, unsafe_get_error(r)));
5483 }
5484
5485 // API search type: unify_result : ((a -> c), (b -> c), Result a b) -> c
5486 // fwd bind count: 2
5487 // Extracts the value (Ok or Error) from a Result
5488 // as defined by the two given functions.
5489 template <typename F, typename G, typename A, typename B>
unify_result(F f,G g,const result<A,B> & r)5490 auto unify_result(F f, G g, const result<A, B>& r)
5491 {
5492 internal::trigger_static_asserts<internal::unary_function_tag, F, A>();
5493 internal::trigger_static_asserts<internal::unary_function_tag, G, B>();
5494 static_assert(std::is_same<internal::invoke_result_t<F, A>,
5495 internal::invoke_result_t<G, B>>::value,
5496 "Both functions must return the same type.");
5497 if (is_ok(r))
5498 return internal::invoke(f, unsafe_get_ok(r));
5499 return internal::invoke(g, unsafe_get_error(r));
5500 }
5501
5502 // API search type: join_result : Result (Result a b) b -> Result a b
5503 // Flattens a nested result.
5504 // join_result(Ok Ok x) == Ok x
5505 // join_result(Ok Error e) == Error e
5506 // join_result(Error e) == Error e
5507 template <typename OK, typename Error>
join_result(const result<result<OK,Error>,Error> & r)5508 result<OK, Error> join_result(const result<result<OK, Error>, Error>& r)
5509 {
5510 if (is_ok(r))
5511 return unsafe_get_ok(r);
5512 else
5513 return error<OK, Error>(r.unsafe_get_error());
5514 }
5515
5516 // API search type: and_then_result : ((a -> Result c b), (Result a b)) -> Result c b
5517 // fwd bind count: 1
5518 // Monadic bind.
5519 // Returns the error if the result is an error.
5520 // Otherwise return the result of applying
5521 // the function to the ok value of the result.
5522 template <typename Ok, typename Error, typename F>
and_then_result(F f,const result<Ok,Error> & r)5523 auto and_then_result(F f, const result<Ok, Error>& r)
5524 {
5525 internal::trigger_static_asserts<internal::unary_function_tag, F, Ok>();
5526
5527 using FOut = std::decay_t<internal::invoke_result_t<F, Ok>>;
5528 static_assert(std::is_same<Error, typename FOut::error_t>::value,
5529 "Error type must stay the same.");
5530 if (is_ok(r))
5531 return internal::invoke(f, unsafe_get_ok(r));
5532 else
5533 return error<typename FOut::ok_t, typename FOut::error_t>(r.unsafe_get_error());
5534 }
5535
5536 // API search type: compose_result : ((a -> Result b c), (b -> Result d c)) -> (a -> Result d c)
5537 // Left-to-right Kleisli composition of monads.
5538 // It is possible to compose a variadic number of callables.
5539 // The first callable can take a variadic number of parameters.
5540 template <typename... Callables>
compose_result(Callables &&...callables)5541 auto compose_result(Callables&&... callables)
5542 {
5543 auto bind_result = [](auto f, auto g) {
5544 return [f = std::move(f), g = std::move(g)](auto&&... args)
5545 {
5546 internal::trigger_static_asserts<internal::check_arity_tag,
5547 decltype(f),
5548 decltype(args)...>();
5549 #if defined(_MSC_VER) && _MSC_VER >= 1920 // in VS2019, compilation with /permissive- breaks with 'using' syntax below
5550 struct FOut : std::decay_t<
5551 internal::invoke_result_t<decltype(f), decltype(args)...>> {};
5552 #else
5553 using FOut = std::decay_t<
5554 internal::invoke_result_t<decltype(f), decltype(args)...>>;
5555 #endif
5556
5557 internal::trigger_static_asserts<internal::unary_function_tag,
5558 decltype(g),
5559 typename FOut::ok_t>();
5560 #if defined(_MSC_VER) && _MSC_VER >= 1920 // in VS2019, compilation with /permissive- breaks with 'using' syntax below
5561 struct GOut : std::decay_t<
5562 internal::invoke_result_t<decltype(g), typename FOut::ok_t>> {};
5563 #else
5564 using GOut = std::decay_t<
5565 internal::invoke_result_t<decltype(g), typename FOut::ok_t>>;
5566 #endif
5567 static_assert(std::is_same<typename FOut::error_t,
5568 typename GOut::error_t>::value,
5569 "Error type must stay the same.");
5570
5571 auto resultB =
5572 internal::invoke(f, std::forward<decltype(args)>(args)...);
5573 if (is_ok(resultB))
5574 return internal::invoke(g, unsafe_get_ok(resultB));
5575 return error<typename GOut::ok_t, typename GOut::error_t>(
5576 unsafe_get_error(resultB));
5577 };
5578 };
5579 return internal::compose_binary_lift(bind_result,
5580 std::forward<Callables>(callables)...);
5581 }
5582 } // namespace fplus
5583
5584 #include <algorithm>
5585
5586 namespace fplus
5587 {
5588
5589 namespace internal
5590 {
5591
5592 template <typename Pred, typename Container>
keep_if(internal::reuse_container_t,Pred pred,Container && xs)5593 Container keep_if(internal::reuse_container_t, Pred pred, Container&& xs)
5594 {
5595 internal::check_unary_predicate_for_container<Pred, Container>();
5596 xs.erase(std::remove_if(
5597 std::begin(xs), std::end(xs), logical_not(pred)), std::end(xs));
5598 return std::forward<Container>(xs);
5599 }
5600
5601 template <typename Pred, typename Container>
keep_if(internal::create_new_container_t,Pred pred,const Container & xs)5602 Container keep_if(internal::create_new_container_t, Pred pred,
5603 const Container& xs)
5604 {
5605 internal::check_unary_predicate_for_container<Pred, Container>();
5606 Container result;
5607 auto it = internal::get_back_inserter<Container>(result);
5608 std::copy_if(std::begin(xs), std::end(xs), it, pred);
5609 return result;
5610 }
5611
5612 } // namespace internal
5613
5614 // API search type: keep_if : ((a -> Bool), [a]) -> [a]
5615 // fwd bind count: 1
5616 // Keep the elements of a sequence fulfilling a predicate.
5617 // keep_if(is_even, [1, 2, 3, 2, 4, 5]) == [2, 2, 4]
5618 // Also known as filter.
5619 template <typename Pred, typename Container,
5620 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
keep_if(Pred pred,Container && xs)5621 ContainerOut keep_if(Pred pred, Container&& xs)
5622 {
5623 return internal::keep_if(internal::can_reuse_v<Container>{},
5624 pred, std::forward<Container>(xs));
5625 }
5626
5627 // API search type: drop_if : ((a -> Bool), [a]) -> [a]
5628 // fwd bind count: 1
5629 // Drop the elements of a sequence fulfilling a predicate.
5630 // drop_if(is_even, [1, 2, 3, 2, 4, 5]) == [1, 3, 5]
5631 // Also known as reject.
5632 template <typename Pred, typename Container,
5633 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
drop_if(Pred pred,Container && xs)5634 ContainerOut drop_if(Pred pred, Container&& xs)
5635 {
5636 return keep_if(logical_not(pred), std::forward<Container>(xs));
5637 }
5638
5639 // API search type: without : (a, [a]) -> [a]
5640 // fwd bind count: 1
5641 // Keep all elements a sequence not equal to elem.
5642 // without(0, [1, 0, 0, 5, 3, 0, 1]) == [1, 5, 3, 1]
5643 template <typename Container,
5644 typename T = typename Container::value_type,
5645 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
without(T elem,Container && xs)5646 ContainerOut without(T elem, Container&& xs)
5647 {
5648 return drop_if(is_equal_to(elem), std::forward<Container>(xs));
5649 }
5650
5651 // API search type: without_any : (a, [a]) -> [a]
5652 // fwd bind count: 1
5653 // Keep all elements a sequence not present in elems.
5654 // without([0, 1], [1, 0, 0, 5, 3, 0, 1]) == [5, 3]
5655 template <typename Container, typename ContainerElems,
5656 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
without_any(const ContainerElems & elems,Container && xs)5657 ContainerOut without_any(const ContainerElems& elems, Container&& xs)
5658 {
5659 static_assert(std::is_same<
5660 typename ContainerElems::value_type,
5661 typename std::remove_reference<Container>::type::value_type>::value,
5662 "Container values must be of the same type.");
5663 const auto pred = bind_2nd_of_2(is_elem_of<ContainerElems>, elems);
5664 return drop_if(pred, std::forward<Container>(xs));
5665 }
5666
5667 // API search type: keep_if_with_idx : (((Int, a) -> Bool), [a]) -> [a]
5668 // fwd bind count: 1
5669 // Keep the elements of a sequence fulfilling a predicate.
5670 // Predicate takes index and value.
5671 // All elements fulfilling the predicate are kept.
5672 template <typename Pred, typename Container>
keep_if_with_idx(Pred pred,const Container & xs)5673 Container keep_if_with_idx(Pred pred, const Container& xs)
5674 {
5675 internal::check_index_with_type_predicate_for_container<Pred, Container>();
5676 Container ys;
5677 auto it = internal::get_back_inserter<Container>(ys);
5678 std::size_t idx = 0;
5679 for (const auto& x : xs)
5680 {
5681 if (internal::invoke(pred, idx++, x))
5682 *it = x;
5683 }
5684 return ys;
5685 }
5686
5687 // API search type: drop_if_with_idx : (((Int, a) -> Bool), [a]) -> [a]
5688 // fwd bind count: 1
5689 // Drop the elements of a sequence fulfilling a predicate.
5690 // Predicate takes index and value.
5691 // All elements fulfilling the predicate are skipped.
5692 template <typename Pred, typename Container>
drop_if_with_idx(Pred pred,const Container & xs)5693 Container drop_if_with_idx(Pred pred, const Container& xs)
5694 {
5695 internal::check_index_with_type_predicate_for_container<Pred, Container>();
5696 const auto inverse_pred = [pred](auto idx, const auto& x)
5697 {
5698 return !internal::invoke(pred, idx, x);
5699 };
5700 return keep_if_with_idx(inverse_pred, xs);
5701 }
5702
5703 namespace internal
5704 {
5705
5706 template <typename UnaryPredicate, typename Container>
keep_by_idx(internal::reuse_container_t,UnaryPredicate pred,Container && xs)5707 Container keep_by_idx(internal::reuse_container_t,
5708 UnaryPredicate pred, Container&& xs)
5709 {
5710 auto itOut = std::begin(xs);
5711 std::size_t i = 0;
5712 for (auto it = std::begin(xs); it != std::end(xs); ++it)
5713 {
5714 if (internal::invoke(pred, i++))
5715 assign(*itOut++, std::move(*it));
5716 }
5717 xs.erase(itOut, std::end(xs));
5718 return std::forward<Container>(xs);
5719 }
5720
5721 template <typename UnaryPredicate, typename Container>
keep_by_idx(internal::create_new_container_t,UnaryPredicate pred,const Container & xs)5722 Container keep_by_idx(internal::create_new_container_t,
5723 UnaryPredicate pred, const Container& xs)
5724 {
5725 Container ys = xs;
5726 return internal::keep_by_idx(internal::reuse_container_t(),
5727 pred, std::move(ys));
5728 }
5729
5730 } // namespace internal
5731
5732 // API search type: keep_by_idx : ((Int -> Bool), [a]) -> [a]
5733 // fwd bind count: 1
5734 // Keep the elements of a sequence with an index fulfilling a predicate.
5735 // Predicate takes an index and decides if an element is kept.
5736 template <typename UnaryPredicate, typename Container,
5737 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
keep_by_idx(UnaryPredicate pred,Container && xs)5738 ContainerOut keep_by_idx(UnaryPredicate pred, Container&& xs)
5739 {
5740 internal::check_unary_predicate_for_type<UnaryPredicate, std::size_t>();
5741 return internal::keep_by_idx(internal::can_reuse_v<Container>{},
5742 pred, std::forward<Container>(xs));
5743 }
5744
5745 // API search type: drop_by_idx : ((Int -> Bool), [a]) -> [a]
5746 // fwd bind count: 1
5747 // Drop the elements of a sequence with an index fulfilling a predicate.
5748 // Predicate takes an index and decides if an element is dropped.
5749 template <typename UnaryPredicate, typename Container,
5750 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
drop_by_idx(UnaryPredicate pred,Container && xs)5751 ContainerOut drop_by_idx(UnaryPredicate pred, Container&& xs)
5752 {
5753 internal::check_unary_predicate_for_type<UnaryPredicate, std::size_t>();
5754 return keep_by_idx(logical_not(pred), std::forward<Container>(xs));
5755 }
5756
5757 // API search type: keep_idxs : ([Int], [a]) -> [a]
5758 // fwd bind count: 1
5759 // Keep the elements of a sequence with an index present in idxs_to_keep.
5760 // keep_idxs([2,5], [1,2,3,4,5,6,7]) == [3,6]
5761 template <typename ContainerIdxs, typename Container>
keep_idxs(const ContainerIdxs & idxs_to_keep,const Container & xs)5762 Container keep_idxs(const ContainerIdxs& idxs_to_keep, const Container& xs)
5763 {
5764 static_assert(std::is_same<typename ContainerIdxs::value_type, std::size_t>::value,
5765 "Indices must be std::size_t");
5766 auto idxs_left = convert_container<std::list<std::size_t>>(
5767 unique(sort(idxs_to_keep)));
5768 Container ys;
5769 auto it = internal::get_back_inserter<Container>(ys);
5770 std::size_t idx = 0;
5771 for (const auto& x : xs)
5772 {
5773 if (!idxs_left.empty() && idxs_left.front() == idx)
5774 {
5775 idxs_left.pop_front();
5776 *it = x;
5777 }
5778 ++idx;
5779 }
5780 return ys;
5781 }
5782
5783 // API search type: drop_idxs : ([Int], [a]) -> [a]
5784 // fwd bind count: 1
5785 // Drop the elements of a sequence with an index present in idxs_to_keep.
5786 // drop_idxs([2,5], [1,2,3,4,5,6,7]) == [1,2,4,5,7]
5787 template <typename ContainerIdxs, typename Container>
drop_idxs(const ContainerIdxs & idxs_to_drop,const Container & xs)5788 Container drop_idxs(const ContainerIdxs& idxs_to_drop, const Container& xs)
5789 {
5790 static_assert(std::is_same<typename ContainerIdxs::value_type, std::size_t>::value,
5791 "Indices must be std::size_t");
5792 auto idxs_left = convert_container<std::list<std::size_t>>(
5793 unique(sort(idxs_to_drop)));
5794 Container ys;
5795 auto it = internal::get_back_inserter<Container>(ys);
5796 std::size_t idx = 0;
5797 for (const auto& x : xs)
5798 {
5799 if (idxs_left.empty() || idxs_left.front() != idx)
5800 {
5801 *it = x;
5802 }
5803 else
5804 {
5805 if (!idxs_left.empty())
5806 {
5807 idxs_left.pop_front();
5808 }
5809 }
5810 ++idx;
5811 }
5812 return ys;
5813 }
5814
5815 // API search type: drop_idx : (Int, [a]) -> [a]
5816 // fwd bind count: 1
5817 // Remove the element at a specific index from a sequence.
5818 // drop_idx(2, [1,2,3,4,5,6,7]) == [1,2,4,5,6,7]
5819 template <typename Container>
drop_idx(std::size_t idx,const Container & xs)5820 Container drop_idx(std::size_t idx, const Container& xs)
5821 {
5822 return drop_by_idx(is_equal_to(idx), xs);
5823 }
5824
5825 // API search type: justs : [Maybe a] -> [a]
5826 // fwd bind count: 0
5827 // From a Container filled with Maybe<T> the nothings are dropped
5828 // and the values inside the justs are returned in a new container.
5829 template <typename ContainerIn,
5830 typename ContainerOut =
5831 typename internal::same_cont_new_t<ContainerIn,
5832 typename ContainerIn::value_type::type>::type>
justs(const ContainerIn & xs)5833 ContainerOut justs(const ContainerIn& xs)
5834 {
5835 typedef typename ContainerIn::value_type::type T;
5836 auto justsInMaybes = keep_if(is_just<T>, xs);
5837 ContainerOut ys;
5838 internal::prepare_container(ys, fplus::size_of_cont(justsInMaybes));
5839 auto itOut = internal::get_back_inserter<ContainerOut>(ys);
5840 std::transform(std::begin(justsInMaybes), std::end(justsInMaybes),
5841 itOut, unsafe_get_just<T>);
5842 return ys;
5843 }
5844
5845 // API search type: oks : [Result a b] -> [a]
5846 // fwd bind count: 0
5847 // From a Container filled with Result<Ok, Error> the errors are dropped
5848 // and the values inside the ok are returned in a new container.
5849 template <typename ContainerIn,
5850 typename ContainerOut =
5851 typename internal::same_cont_new_t<ContainerIn,
5852 typename ContainerIn::value_type::ok_t>::type>
oks(const ContainerIn & xs)5853 ContainerOut oks(const ContainerIn& xs)
5854 {
5855 typedef typename ContainerIn::value_type::ok_t Ok;
5856 typedef typename ContainerIn::value_type::error_t Error;
5857 auto oksInResults = keep_if(is_ok<Ok, Error>, xs);
5858 ContainerOut ys;
5859 internal::prepare_container(ys, fplus::size_of_cont(oksInResults));
5860 auto itOut = internal::get_back_inserter<ContainerOut>(ys);
5861 std::transform(std::begin(oksInResults), std::end(oksInResults),
5862 itOut, unsafe_get_ok<Ok, Error>);
5863 return ys;
5864 }
5865
5866 // API search type: errors : [Result a b] -> [b]
5867 // fwd bind count: 0
5868 // From a Container filled with Result<Ok, Error> the oks are dropped
5869 // and the values inside the errors are returned in a new container.
5870 template <typename ContainerIn,
5871 typename ContainerOut =
5872 typename internal::same_cont_new_t<ContainerIn,
5873 typename ContainerIn::value_type::error_t>::type>
errors(const ContainerIn & xs)5874 ContainerOut errors(const ContainerIn& xs)
5875 {
5876 typedef typename ContainerIn::value_type::ok_t Ok;
5877 typedef typename ContainerIn::value_type::error_t Error;
5878 auto errorsInResults = keep_if(is_error<Ok, Error>, xs);
5879 ContainerOut ys;
5880 internal::prepare_container(ys, fplus::size_of_cont(errorsInResults));
5881 auto itOut = internal::get_back_inserter<ContainerOut>(ys);
5882 std::transform(std::begin(errorsInResults), std::end(errorsInResults),
5883 itOut, unsafe_get_error<Ok, Error>);
5884 return ys;
5885 }
5886
5887 // API search type: trim_left : (a, [a]) -> [a]
5888 // fwd bind count: 1
5889 // Remove elements from the left as long as they equal x.
5890 // trim_left('_', "___abc__") == "abc__"
5891 // trim_left(0, [0,0,0,5,6,7,8,6,4]) == [5,6,7,8,6,4]
5892 template <typename Container,
5893 typename T = typename Container::value_type>
5894 Container trim_left(const T& x, const Container& xs)
5895 {
5896 return drop_while(is_equal_to(x), xs);
5897 }
5898
5899 // API search type: trim_token_left : ([a], [a]) -> [a]
5900 // fwd bind count: 1
5901 // Remove elements from the left as long as they match token.
5902 // trim_token_left([0,1,2], [0,1,2,0,1,2,7,5,9]) == [7,5,9]
5903 template <typename Container>
trim_token_left(const Container & token,const Container & xs)5904 Container trim_token_left(const Container& token, const Container& xs)
5905 {
5906 auto result = xs;
5907 while (is_prefix_of(token, result))
5908 {
5909 result = get_segment(size_of_cont(token), size_of_cont(result), result);
5910 }
5911 return result;
5912 }
5913
5914 // API search type: trim_right_by : ((a -> Bool), [a]) -> [a]
5915 // fwd bind count: 1
5916 // Remove elements from the left as long as p is fulfilled.
5917 // trim_right_by(is_even, [0,2,4,5,6,7,8,6,4]) == [0,2,4,5,6,7]
5918 template <typename Container, typename UnaryPredicate>
5919 Container trim_right_by(UnaryPredicate p, const Container& xs)
5920 {
5921 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
5922 return reverse(drop_while(p, reverse(xs)));
5923 }
5924
5925 // API search type: trim_right : (a, [a]) -> [a]
5926 // fwd bind count: 1
5927 // Remove elements from the left as long as they equal x.
5928 // trim_right('_', "___abc__") == "___abc"
5929 // trim_right(4, [0,2,4,5,6,7,8,4,4]) == [0,2,4,5,6,7,8]
5930 template <typename Container,
5931 typename T = typename Container::value_type>
5932 Container trim_right(const T& x, const Container& xs)
5933 {
5934 return trim_right_by(is_equal_to(x), xs);
5935 }
5936
5937 // API search type: trim_token_right : ([a], [a]) -> [a]
5938 // fwd bind count: 1
5939 // Remove elements from the right as long as they match token.
5940 // trim_token_right([0,1,2], [7,5,9,0,1,2,0,1,2]) == [7,5,9]
5941 template <typename Container>
trim_token_right(const Container & token,const Container & xs)5942 Container trim_token_right(const Container& token, const Container& xs)
5943 {
5944 return reverse(trim_token_left(reverse(token), reverse(xs)));
5945 }
5946
5947 // API search type: trim_by : ((a -> Bool), [a]) -> [a]
5948 // fwd bind count: 1
5949 // Remove elements from the left and right as long as p is fulfilled.
5950 // trim_by(is_even, [0,2,4,5,6,7,8,6,4]) == [5,6,7]
5951 template <typename Container, typename UnaryPredicate>
5952 Container trim_by(UnaryPredicate p, const Container& xs)
5953 {
5954 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
5955 return trim_right_by(p, drop_while(p, xs));
5956 }
5957
5958 // API search type: trim : (a, [a]) -> [a]
5959 // fwd bind count: 1
5960 // Remove elements from the left and right as long as they equal x.
5961 // trim('_', "___abc__") == "abc"
5962 // trim(0, [0,2,4,5,6,7,8,0,0]) == [2,4,5,6,7,8]
5963 template <typename Container,
5964 typename T = typename Container::value_type>
5965 Container trim(const T& x, const Container& xs)
5966 {
5967 return trim_right(x, trim_left(x, xs));
5968 }
5969
5970 // API search type: trim_token : ([a], [a]) -> [a]
5971 // fwd bind count: 1
5972 // Remove elements from the left and right as long as they match token.
5973 // trim_token([0,1], [0,1,7,8,9,0,1]) == [7,8,9]
5974 template <typename Container>
trim_token(const Container & token,const Container & xs)5975 Container trim_token(const Container& token, const Container& xs)
5976 {
5977 return trim_token_right(token, trim_token_left(token, xs));
5978 }
5979
5980 // API search type: adjacent_keep_snd_if : (((a, a) -> Bool), [a]) -> [a]
5981 // fwd bind count: 1
5982 // For each pair of adjacent elements in a source sequence,
5983 // evaluate the specified binary predicate.
5984 // If the predicate evaluates to false,
5985 // the second element of the pair is removed from the result sequence;
5986 // otherwise, it is included.
5987 // The first element in the source sequence is always included.
5988 // Also known as adjacent_filter.
5989 template <typename BinaryPredicate, typename Container>
adjacent_keep_snd_if(BinaryPredicate p,const Container & xs)5990 Container adjacent_keep_snd_if(BinaryPredicate p, const Container& xs)
5991 {
5992 if (is_empty(xs))
5993 {
5994 return {};
5995 }
5996 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
5997 Container result;
5998 auto it = internal::get_back_inserter<Container>(result);
5999 auto it_in = std::begin(xs);
6000 *it = *it_in;
6001 while (internal::add_to_iterator(it_in) != std::end(xs))
6002 {
6003 if (p(*it_in, *internal::add_to_iterator(it_in)))
6004 {
6005 *it = *internal::add_to_iterator(it_in);
6006 }
6007 internal::advance_iterator(it_in, 1);
6008 }
6009 return result;
6010 }
6011
6012 // API search type: adjacent_drop_fst_if : (((a, a) -> Bool), [a]) -> [a]
6013 // fwd bind count: 1
6014 // For each pair of adjacent elements in a source sequence,
6015 // evaluate the specified binary predicate.
6016 // If the predicate evaluates to true,
6017 // the first element of the pair is removed from the result sequence;
6018 // otherwise, it is included.
6019 // The last element in the source sequence is always included.
6020 // Also known as adjacent_remove_if.
6021 template <typename BinaryPredicate, typename Container>
adjacent_drop_fst_if(BinaryPredicate p,const Container & xs)6022 Container adjacent_drop_fst_if(BinaryPredicate p, const Container& xs)
6023 {
6024 if (is_empty(xs))
6025 {
6026 return {};
6027 }
6028 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
6029 Container result;
6030 auto it = internal::get_back_inserter<Container>(result);
6031 auto it_in = std::begin(xs);
6032 while (internal::add_to_iterator(it_in) != std::end(xs))
6033 {
6034 if (!internal::invoke(p, *it_in, *internal::add_to_iterator(it_in)))
6035 {
6036 *it = *it_in;
6037 }
6038 internal::advance_iterator(it_in, 1);
6039 }
6040 *it = *it_in;
6041 return result;
6042 }
6043
6044 // API search type: adjacent_drop_snd_if : (((a, a) -> Bool), [a]) -> [a]
6045 // fwd bind count: 1
6046 // For each pair of adjacent elements in a source sequence,
6047 // evaluate the specified binary predicate.
6048 // If the predicate evaluates to true,
6049 // the second element of the pair is removed from the result sequence;
6050 // otherwise, it is included.
6051 // The first element in the source sequence is always included.
6052 template <typename BinaryPredicate, typename Container>
adjacent_drop_snd_if(BinaryPredicate p,const Container & xs)6053 Container adjacent_drop_snd_if(BinaryPredicate p, const Container& xs)
6054 {
6055 typedef typename Container::value_type T;
6056 const auto not_p = [&p](const T& x, const T& y) -> bool
6057 {
6058 return !internal::invoke(p, x, y);
6059 };
6060 return adjacent_keep_snd_if(not_p, xs);
6061 }
6062
6063 // API search type: adjacent_keep_fst_if : (((a, a) -> Bool), [a]) -> [a]
6064 // fwd bind count: 1
6065 // For each pair of adjacent elements in a source sequence,
6066 // evaluate the specified binary predicate.
6067 // If the predicate evaluates to false,
6068 // the first element of the pair is removed from the result sequence;
6069 // otherwise, it is included.
6070 // The last element in the source sequence is always included.
6071 template <typename BinaryPredicate, typename Container>
adjacent_keep_fst_if(BinaryPredicate p,const Container & xs)6072 Container adjacent_keep_fst_if(BinaryPredicate p, const Container& xs)
6073 {
6074 typedef typename Container::value_type T;
6075 const auto not_p = [&p](const T& x, const T& y) -> bool
6076 {
6077 return !internal::invoke(p, x, y);
6078 };
6079 return adjacent_drop_fst_if(not_p, xs);
6080 }
6081
6082 } // namespace fplus
6083
6084
6085 namespace fplus
6086 {
6087
6088 // API search type: generate : ((() -> a), Int) -> [a]
6089 // Grab values from executing a nullary function
6090 // to generate a sequence of amount values.
6091 // generate(f, 3) == [f(), f(), f()]
6092 // Can for example be used to generate a list of random numbers.
6093 template <typename ContainerOut, typename F>
6094 ContainerOut generate(F f, std::size_t amount)
6095 {
6096 internal::trigger_static_asserts<internal::nullary_function_tag, F>();
6097 ContainerOut ys;
6098 internal::prepare_container(ys, amount);
6099 auto it = internal::get_back_inserter<ContainerOut>(ys);
6100 for (std::size_t i = 0; i < amount; ++i)
6101 {
6102 *it = internal::invoke(f);
6103 }
6104 return ys;
6105 }
6106
6107 // API search type: generate_by_idx : ((Int -> a), Int) -> [a]
6108 // fwd bind count: 1
6109 // Grab values from executing a unary function with an index
6110 // to generate a sequence of amount values.
6111 // generate_by_idx(f, 3) == [f(0), f(1), f(2)]
6112 template <typename ContainerOut, typename F>
6113 ContainerOut generate_by_idx(F f, std::size_t amount)
6114 {
6115 internal::
6116 trigger_static_asserts<internal::unary_function_tag, F, std::size_t>();
6117
6118 ContainerOut ys;
6119 internal::prepare_container(ys, amount);
6120 auto it = internal::get_back_inserter<ContainerOut>(ys);
6121 for (std::size_t i = 0; i < amount; ++i)
6122 {
6123 *it = internal::invoke(f, i);
6124 }
6125 return ys;
6126 }
6127
6128 // API search type: repeat : (Int, [a]) -> [a]
6129 // fwd bind count: 1
6130 // Create a sequence containing xs concatenated n times.
6131 // repeat(3, [1, 2]) == [1, 2, 1, 2, 1, 2]
6132 template <typename Container>
repeat(std::size_t n,const Container & xs)6133 Container repeat(std::size_t n, const Container& xs)
6134 {
6135 std::vector<Container> xss(n, xs);
6136 return concat(xss);
6137 }
6138
6139 // API search type: infixes : (Int, [a]) -> [[a]]
6140 // fwd bind count: 1
6141 // Return als possible infixed of xs with a given length.
6142 // infixes(3, [1,2,3,4,5,6]) == [[1,2,3], [2,3,4], [3,4,5], [4,5,6]]
6143 // length must be > 0
6144 template <typename ContainerIn,
6145 typename ContainerOut = std::vector<ContainerIn>>
infixes(std::size_t length,const ContainerIn & xs)6146 ContainerOut infixes(std::size_t length, const ContainerIn& xs)
6147 {
6148 assert(length > 0);
6149 static_assert(std::is_convertible<ContainerIn,
6150 typename ContainerOut::value_type>::value,
6151 "ContainerOut can not take values of type ContainerIn as elements.");
6152 ContainerOut result;
6153 if (size_of_cont(xs) < length)
6154 return result;
6155 internal::prepare_container(result, size_of_cont(xs) - length);
6156 auto itOut = internal::get_back_inserter(result);
6157 for (std::size_t idx = 0; idx <= size_of_cont(xs) - length; ++idx)
6158 {
6159 *itOut = get_segment(idx, idx + length, xs);
6160 }
6161 return result;
6162 }
6163
6164 // API search type: carthesian_product_with_where : (((a, b) -> c), ((a -> b), Bool), [a], [b]) -> [c]
6165 // fwd bind count: 3
6166 // carthesian_product_with_where(make_pair, always(true), "ABC", "XY")
6167 // == [(A,X),(A,Y),(B,X),(B,Y),(C,X),(C,Y)]
6168 // same as (in Haskell):
6169 // [ f x y | x <- xs, y <- ys, pred x y ]
6170 // same as (in pseudo SQL):
6171 // SELECT f(xs.x, ys.y)
6172 // FROM xs, ys
6173 // WHERE pred(xs.x, ys.y);
6174 template <typename F, typename Pred, typename Container1, typename Container2>
carthesian_product_with_where(F f,Pred pred,const Container1 & xs,const Container2 & ys)6175 auto carthesian_product_with_where(F f,
6176 Pred pred,
6177 const Container1& xs,
6178 const Container2& ys)
6179 {
6180 using X = typename Container1::value_type;
6181 using Y = typename Container2::value_type;
6182 using FOut = internal::invoke_result_t<F, X, Y>;
6183 using ContainerOut = std::vector<std::decay_t<FOut>>;
6184
6185 ContainerOut result;
6186 auto itOut = internal::get_back_inserter(result);
6187 for (const auto& x : xs)
6188 {
6189 for (const auto& y : ys)
6190 {
6191 if (internal::invoke(pred, x, y))
6192 {
6193 itOut = f(x, y);
6194 }
6195 }
6196 }
6197 return result;
6198 }
6199
6200 // API search type: carthesian_product_with : (((a, b) -> c), [a], [b]) -> [c]
6201 // fwd bind count: 2
6202 // carthesian_product_with(make_pair, "ABC", "XY")
6203 // == [(A,X),(A,Y),(B,X),(B,Y),(C,X),(C,Y)]
6204 // same as (in Haskell):
6205 // [ f x y | x <- xs, y <- ys ]
6206 // same as (in pseudo SQL):
6207 // SELECT f(xs.x, ys.y)
6208 // FROM xs, ys;
6209 template <typename F, typename Container1, typename Container2>
carthesian_product_with(F f,const Container1 & xs,const Container2 & ys)6210 auto carthesian_product_with(F f, const Container1& xs, const Container2& ys)
6211 {
6212 auto always_true_x_y = [](const auto&, const auto&) { return true; };
6213 return carthesian_product_with_where(f, always_true_x_y, xs, ys);
6214 }
6215
6216 // API search type: carthesian_product_where : (((a, b) -> Bool), [a], [b]) -> [(a, b)]
6217 // fwd bind count: 2
6218 // carthesian_product_where(always(true), "ABC", "XY")
6219 // == [(A,X),(A,Y),(B,X),(B,Y),(C,X),(C,Y)]
6220 // same as (in Haskell):
6221 // [ (x, y) | x <- xs, y <- ys, pred x y ]
6222 // same as (in pseudo SQL):
6223 // SELECT (xs.x, ys.y)
6224 // FROM xs, ys
6225 // WHERE pred(xs.x, ys.y);
6226 template <typename Pred, typename Container1, typename Container2>
carthesian_product_where(Pred pred,const Container1 & xs,const Container2 & ys)6227 auto carthesian_product_where(Pred pred,
6228 const Container1& xs, const Container2& ys)
6229 {
6230 auto make_res_pair = [](const auto& x, const auto& y)
6231 {
6232 return std::make_pair(x, y);
6233 };
6234 return carthesian_product_with_where(make_res_pair, pred, xs, ys);
6235 }
6236
6237 // API search type: carthesian_product : ([a], [b]) -> [(a, b)]
6238 // fwd bind count: 1
6239 // carthesian_product("ABC", "XY")
6240 // == [(A,X),(A,Y),(B,X),(B,Y),(C,X),(C,Y)]
6241 // same as (in Haskell):
6242 // [ (x, y) | x <- xs, y <- ys ]
6243 // same as (in pseudo SQL):
6244 // SELECT (xs.x, ys.y)
6245 // FROM xs, ys;
6246 template <typename Container1, typename Container2>
carthesian_product(const Container1 & xs,const Container2 & ys)6247 auto carthesian_product(const Container1& xs, const Container2& ys)
6248 {
6249 auto make_res_pair = [](const auto& x, const auto& y)
6250 {
6251 return std::make_pair(x, y);
6252 };
6253 auto always_true_x_y = [](const auto&, const auto&) { return true; };
6254 return carthesian_product_with_where(
6255 make_res_pair, always_true_x_y, xs, ys);
6256 }
6257
6258
6259 namespace internal
6260 {
6261 // productN :: Int -> [a] -> [[a]]
6262 // productN n = foldr go [[]] . replicate n
6263 // where go elems acc = [x:xs | x <- elems, xs <- acc]
6264 template <typename T>
helper_carthesian_product_n_idxs(std::size_t power,const std::vector<T> & xs)6265 std::vector<std::vector<T>> helper_carthesian_product_n_idxs
6266 (std::size_t power, const std::vector<T>& xs)
6267 {
6268 static_assert(std::is_same<T, std::size_t>::value,
6269 "T must be std::size_t");
6270 typedef std::vector<T> Vec;
6271 typedef std::vector<Vec> VecVec;
6272 if (power == 0)
6273 return VecVec();
6274 auto go = [](const Vec& elems, const VecVec& acc)
6275 {
6276 VecVec result;
6277 for (const T& x : elems)
6278 {
6279 for (const Vec& tail : acc)
6280 {
6281 result.push_back(append(Vec(1, x), tail));
6282 }
6283 }
6284 return result;
6285 };
6286 return fold_right(go, VecVec(1), replicate(power, xs));
6287 }
6288 }
6289
6290 // API search type: carthesian_product_n : (Int, [a]) -> [[a]]
6291 // fwd bind count: 1
6292 // Returns the product set with a given power.
6293 // carthesian_product_n(2, "ABCD")
6294 // == AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
6295 template <typename ContainerIn,
6296 typename T = typename ContainerIn::value_type,
6297 typename ContainerOut = std::vector<ContainerIn>>
carthesian_product_n(std::size_t power,const ContainerIn & xs_in)6298 ContainerOut carthesian_product_n(std::size_t power, const ContainerIn& xs_in)
6299 {
6300 if (power == 0)
6301 return ContainerOut(1);
6302 std::vector<T> xs = convert_container<std::vector<T>>(xs_in);
6303 auto idxs = all_idxs(xs);
6304 auto result_idxss = internal::helper_carthesian_product_n_idxs(power, idxs);
6305 typedef typename ContainerOut::value_type ContainerOutInner;
6306 auto to_result_cont = [&](const std::vector<std::size_t>& indices)
6307 {
6308 return convert_container_and_elems<ContainerOutInner>(
6309 elems_at_idxs(indices, xs));
6310 };
6311 return transform(to_result_cont, result_idxss);
6312 }
6313
6314 // API search type: permutations : (Int, [a]) -> [[a]]
6315 // fwd bind count: 1
6316 // Generate all possible permutations with a given power.
6317 // permutations(2, "ABCD") == AB AC AD BA BC BD CA CB CD DA DB DC
6318 template <typename ContainerIn,
6319 typename T = typename ContainerIn::value_type,
6320 typename ContainerOut = std::vector<ContainerIn>>
permutations(std::size_t power,const ContainerIn & xs_in)6321 ContainerOut permutations(std::size_t power, const ContainerIn& xs_in)
6322 {
6323 if (power == 0)
6324 return ContainerOut(1);
6325 std::vector<T> xs = convert_container<std::vector<T>>(xs_in);
6326 auto idxs = all_idxs(xs);
6327 typedef std::vector<std::size_t> idx_vec;
6328 auto result_idxss = keep_if(all_unique<idx_vec>,
6329 internal::helper_carthesian_product_n_idxs(power, idxs));
6330 typedef typename ContainerOut::value_type ContainerOutInner;
6331 auto to_result_cont = [&](const std::vector<std::size_t>& indices)
6332 {
6333 return convert_container_and_elems<ContainerOutInner>(
6334 elems_at_idxs(indices, xs));
6335 };
6336 return transform(to_result_cont, result_idxss);
6337 }
6338
6339 // API search type: combinations : (Int, [a]) -> [[a]]
6340 // fwd bind count: 1
6341 // Generate all possible combinations with a given power.
6342 // combinations(2, "ABCD") == AB AC AD BC BD CD
6343 template <typename ContainerIn,
6344 typename T = typename ContainerIn::value_type,
6345 typename ContainerOut = std::vector<ContainerIn>>
combinations(std::size_t power,const ContainerIn & xs_in)6346 ContainerOut combinations(std::size_t power, const ContainerIn& xs_in)
6347 {
6348 if (power == 0)
6349 return ContainerOut(1);
6350 std::vector<T> xs = convert_container<std::vector<T>>(xs_in);
6351 auto idxs = all_idxs(xs);
6352 typedef std::vector<std::size_t> idx_vec;
6353 auto result_idxss = keep_if(is_strictly_sorted<idx_vec>,
6354 internal::helper_carthesian_product_n_idxs(power, idxs));
6355 typedef typename ContainerOut::value_type ContainerOutInner;
6356 auto to_result_cont = [&](const std::vector<std::size_t>& indices)
6357 {
6358 return convert_container_and_elems<ContainerOutInner>(
6359 elems_at_idxs(indices, xs));
6360 };
6361 return transform(to_result_cont, result_idxss);
6362 }
6363
6364 // API search type: combinations_with_replacement : (Int, [a]) -> [[a]]
6365 // fwd bind count: 1
6366 // Generate all possible combinations using replacement with a given power.
6367 // combinations_with_replacement(2, "ABCD") == AA AB AC AD BB BC BD CC CD DD
6368 template <typename ContainerIn,
6369 typename T = typename ContainerIn::value_type,
6370 typename ContainerOut = std::vector<ContainerIn>>
combinations_with_replacement(std::size_t power,const ContainerIn & xs_in)6371 ContainerOut combinations_with_replacement(std::size_t power,
6372 const ContainerIn& xs_in)
6373 {
6374 if (power == 0)
6375 return ContainerOut(1);
6376 std::vector<T> xs = convert_container<std::vector<T>>(xs_in);
6377 auto idxs = all_idxs(xs);
6378 typedef std::vector<std::size_t> idx_vec;
6379 auto result_idxss = keep_if(is_sorted<idx_vec>,
6380 internal::helper_carthesian_product_n_idxs(power, idxs));
6381 typedef typename ContainerOut::value_type ContainerOutInner;
6382 auto to_result_cont = [&](const std::vector<std::size_t>& indices)
6383 {
6384 return convert_container_and_elems<ContainerOutInner>(
6385 elems_at_idxs(indices, xs));
6386 };
6387 return transform(to_result_cont, result_idxss);
6388 }
6389
6390 // API search type: power_set : [a] -> [[a]]
6391 // fwd bind count: 0
6392 // Return the set of all subsets of xs_in,
6393 // including the empty set and xs_in itself.
6394 // power_set("xyz") == ["", "x", "y", "z", "xy", "xz", "yz", "xyz"]
6395 // Also known as subsequences.
6396 template <typename ContainerIn,
6397 typename T = typename ContainerIn::value_type,
6398 typename ContainerOut = std::vector<ContainerIn>>
power_set(const ContainerIn & xs_in)6399 ContainerOut power_set(const ContainerIn& xs_in)
6400 {
6401 return concat(
6402 generate_by_idx<std::vector<ContainerOut>>(
6403 bind_1st_of_2(
6404 flip(combinations<ContainerIn, T, ContainerOut>),
6405 xs_in),
6406 size_of_cont(xs_in) + 1));
6407 }
6408
6409 // API search type: iterate : ((a -> a), Int, a) -> [a]
6410 // fwd bind count: 2
6411 // Repeatedly apply a function (n times) to a value (starting with x)
6412 // and recording the outputs on its way.
6413 // iterate((*2), 5, 3) = [3, 6, 12, 24, 48]
6414 // = [3, f(3), f(f(3)), f(f(f(3))), f(f(f(f(3))))]
6415 template <typename F,
6416 typename T,
6417 typename ContainerOut = std::vector<T>>
iterate(F f,std::size_t size,const T & x)6418 ContainerOut iterate(F f, std::size_t size, const T& x)
6419 {
6420 ContainerOut result;
6421 if (size == 0)
6422 return result;
6423 internal::prepare_container(result, size + 1);
6424 auto it_out = internal::get_back_inserter(result);
6425 T current = x;
6426 *it_out = current;
6427 for (std::size_t i = 1; i < size; ++i)
6428 {
6429 current = internal::invoke(f, current);
6430 *it_out = current;
6431 }
6432 return result;
6433 }
6434
6435 // API search type: iterate_maybe : ((a -> Maybe a), a) -> [a]
6436 // fwd bind count: 1
6437 // Repeatedly apply a function to a value (starting with x)
6438 // and recording the outputs on its way.
6439 // Stops when the function returns nothing.
6440 // iterate_maybe(next_collats_val, 5) = [5, 16, 8, 4, 2, 1]
6441 template <typename F,
6442 typename T,
6443 typename ContainerOut = std::vector<T>>
iterate_maybe(F f,const T & x)6444 ContainerOut iterate_maybe(F f, const T& x)
6445 {
6446 ContainerOut result;
6447 auto it_out = internal::get_back_inserter(result);
6448 maybe<T> current(x);
6449 while (current.is_just())
6450 {
6451 *it_out = current.unsafe_get_just();
6452 current = internal::invoke(f, current.unsafe_get_just());
6453 }
6454 return result;
6455 }
6456
6457 // API search type: adjacent_difference_by : [a] -> [a]
6458 // fwd bind count: 1
6459 // Computes the differences between the second
6460 // and the first of each adjacent pair of elements of the sequence
6461 // using a binary function.
6462 // adjacent_difference_by([0,4,1,2,5]) == [0,4,-3,1,3]
6463 template <typename ContainerIn, typename F>
adjacent_difference_by(F f,const ContainerIn & xs)6464 auto adjacent_difference_by(F f, const ContainerIn& xs)
6465 {
6466 using X = typename ContainerIn::value_type;
6467 using TOut = internal::invoke_result_t<F, X, X>;
6468 using ContainerOut = std::vector<std::decay_t<TOut>>;
6469
6470 ContainerOut result;
6471
6472 using std::begin;
6473 using std::end;
6474 internal::prepare_container(result, size_of_cont(xs));
6475 std::adjacent_difference(begin(xs), end(xs), back_inserter(result), f);
6476 return result;
6477 }
6478
6479 // API search type: adjacent_difference : [a] -> [a]
6480 // fwd bind count: 0
6481 // Computes the differences between the second
6482 // and the first of each adjacent pair of elements of the sequence.
6483 // adjacent_difference([0,4,1,2,5]) == [0,4,-3,1,3]
6484 template <typename Container>
adjacent_difference(const Container & xs)6485 Container adjacent_difference(const Container& xs)
6486 {
6487 return adjacent_difference_by(
6488 std::minus<typename Container::value_type>(), xs);
6489 }
6490
6491 // API search type: rotate_left : [a] -> [a]
6492 // fwd bind count: 0
6493 // Removes the first element and appends it to the back.
6494 // rotate_left("xyz") == "yzx"
6495 template <typename Container>
rotate_left(const Container & xs)6496 Container rotate_left(const Container& xs)
6497 {
6498 if (is_empty(xs))
6499 return xs;
6500 Container ys;
6501 auto size = size_of_cont(xs);
6502 internal::prepare_container(ys, size);
6503 auto it = std::begin(xs);
6504 auto it_out = internal::get_back_inserter(ys);
6505 ++it;
6506 while (it != std::end(xs))
6507 {
6508 *it_out = *it;
6509 ++it;
6510 }
6511 *it_out = xs.front();
6512 return ys;
6513 }
6514
6515 // API search type: rotate_right : [a] -> [a]
6516 // fwd bind count: 0
6517 // Removes the last element and prepends it to the front.
6518 // rotate_right("xyz") == "zxy"
6519 template <typename Container>
rotate_right(const Container & xs)6520 Container rotate_right(const Container& xs)
6521 {
6522 return reverse(rotate_left(reverse(xs)));
6523 }
6524
6525 // API search type: rotations_left : [a] -> [[a]]
6526 // fwd bind count: 0
6527 // Returns all possible rotations using rotate_left.
6528 // rotations_left("abcd") == ["abcd", "bcda", "cdab", "dabc"]
6529 template <typename ContainerIn,
6530 typename T = typename ContainerIn::value_type,
6531 typename ContainerOut = std::vector<ContainerIn>>
rotations_left(const ContainerIn & xs_in)6532 ContainerOut rotations_left(const ContainerIn& xs_in)
6533 {
6534 return iterate(rotate_left<ContainerIn>, size_of_cont(xs_in), xs_in);
6535 }
6536
6537 // API search type: rotations_right : [a] -> [[a]]
6538 // fwd bind count: 0
6539 // Returns all possible rotations using rotate_right.
6540 // rotations_right("abcd") == ["abcd", "dabc", "cdab", "bcda"]
6541 template <typename ContainerIn,
6542 typename T = typename ContainerIn::value_type,
6543 typename ContainerOut = std::vector<ContainerIn>>
rotations_right(const ContainerIn & xs_in)6544 ContainerOut rotations_right(const ContainerIn& xs_in)
6545 {
6546 return iterate(rotate_right<ContainerIn>, size_of_cont(xs_in), xs_in);
6547 }
6548
6549 // API search type: fill_left : (a, Int, [a]) -> [a]
6550 // fwd bind count: 2
6551 // Right-align a sequence.
6552 // fill_left(0, 6, [1,2,3,4]) == [0,0,1,2,3,4]
6553 // Also known as pad_left.
6554 template <typename Container,
6555 typename T = typename Container::value_type>
6556 Container fill_left(const T& x, std::size_t min_size, const Container& xs)
6557 {
6558 if (min_size <= size_of_cont(xs))
6559 return xs;
6560 return append(replicate<T, Container>(min_size - size_of_cont(xs), x), xs);
6561 }
6562
6563 // API search type: fill_right : (a, Int, [a]) -> [a]
6564 // fwd bind count: 2
6565 // Left-align a sequence.
6566 // fill_right(0, 6, [1,2,3,4]) == [1,2,3,4,0,0]
6567 template <typename Container,
6568 typename T = typename Container::value_type>
6569 Container fill_right(const T& x, std::size_t min_size, const Container& xs)
6570 {
6571 if (min_size <= size_of_cont(xs))
6572 return xs;
6573 return append(xs, replicate<T, Container>(min_size - size_of_cont(xs), x));
6574 }
6575
6576 // API search type: inits : [a] -> [[a]]
6577 // fwd bind count: 0
6578 // Generate all possible segments of xs that include the first element.
6579 // inits([0,1,2,3]) == [[],[0],[0,1],[0,1,2],[0,1,2,3]]
6580 template <typename ContainerIn,
6581 typename T = typename ContainerIn::value_type,
6582 typename ContainerOut = std::vector<ContainerIn>>
inits(const ContainerIn & xs)6583 ContainerOut inits(const ContainerIn& xs)
6584 {
6585 ContainerOut result;
6586 std::size_t xs_size = size_of_cont(xs);
6587 internal::prepare_container(result, xs_size + 1);
6588 auto it_out = internal::get_back_inserter(result);
6589 for (std::size_t i = 0; i <= xs_size; ++i)
6590 *it_out = get_segment(0, i, xs);
6591 return result;
6592 }
6593
6594 // API search type: tails : [a] -> [[a]]
6595 // fwd bind count: 0
6596 // Generate all possible segments of xs that include the last element.
6597 // tails([0,1,2,3]) == [[0,1,2,3],[1,2,3],[2,3],[3],[]]
6598 template <typename ContainerIn,
6599 typename T = typename ContainerIn::value_type,
6600 typename ContainerOut = std::vector<ContainerIn>>
tails(const ContainerIn & xs)6601 ContainerOut tails(const ContainerIn& xs)
6602 {
6603 ContainerOut result;
6604 std::size_t xs_size = size_of_cont(xs);
6605 internal::prepare_container(result, xs_size + 1);
6606 auto it_out = internal::get_back_inserter(result);
6607 for (std::size_t i = 0; i <= xs_size; ++i)
6608 *it_out = get_segment(i, xs_size, xs);
6609 return result;
6610 }
6611
6612 } // namespace fplus
6613
6614 //
6615 // numeric.hpp
6616 //
6617
6618 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
6619 // https://github.com/Dobiasd/FunctionalPlus
6620 // Distributed under the Boost Software License, Version 1.0.
6621 // (See accompanying file LICENSE_1_0.txt or copy at
6622 // http://www.boost.org/LICENSE_1_0.txt)
6623
6624
6625
6626 //
6627 // pairs.hpp
6628 //
6629
6630 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
6631 // https://github.com/Dobiasd/FunctionalPlus
6632 // Distributed under the Boost Software License, Version 1.0.
6633 // (See accompanying file LICENSE_1_0.txt or copy at
6634 // http://www.boost.org/LICENSE_1_0.txt)
6635
6636
6637
6638 //
6639 // internal/asserts/pairs.hpp
6640 //
6641
6642 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
6643 // https://github.com/Dobiasd/FunctionalPlus
6644 // Distributed under the Boost Software License, Version 1.0.
6645 // (See accompanying file LICENSE_1_0.txt or copy at
6646 // http://www.boost.org/LICENSE_1_0.txt)
6647
6648
6649
6650 namespace fplus
6651 {
6652 namespace internal
6653 {
6654 struct apply_to_pair_tag
6655 {
6656 };
6657
6658 struct zip_with_tag
6659 {
6660 };
6661
6662 struct zip_with_3_tag
6663 {
6664 };
6665
6666 struct transform_fst_tag
6667 {
6668 };
6669
6670 struct transform_snd_tag
6671 {
6672 };
6673
6674 struct inner_product_with_tag
6675 {
6676 };
6677
6678 template <typename F, typename X, typename Y>
6679 struct function_traits_asserts<apply_to_pair_tag, F, X, Y>
6680 {
6681 static_assert(utils::function_traits<F>::arity == 2,
6682 "Function must take two parameters.");
6683 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6684 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
6685 static_assert(std::is_convertible<X, FIn0>::value,
6686 "Function does not take pair.first type as first Parameter.");
6687 static_assert(std::is_convertible<Y, FIn1>::value,
6688 "Function does not take pair.second type as second Parameter.");
6689 };
6690
6691 template <typename F, typename X, typename Y>
6692 struct function_traits_asserts<zip_with_tag, F, X, Y>
6693 {
6694 static_assert(utils::function_traits<F>::arity == 2,
6695 "Function must take two parameters.");
6696 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6697 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
6698 static_assert(std::is_convertible<X, FIn0>::value,
6699 "Function does not take elements from first Container as first Parameter.");
6700 static_assert(std::is_convertible<Y, FIn1>::value,
6701 "Function does not take elements from second Container as second Parameter.");
6702 };
6703
6704 template <typename F, typename X, typename Y, typename Z>
6705 struct function_traits_asserts<zip_with_3_tag, F, X, Y, Z>
6706 {
6707 static_assert(utils::function_traits<F>::arity == 3,
6708 "Function must take two parameters.");
6709 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6710 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
6711 typedef typename utils::function_traits<F>::template arg<2>::type FIn2;
6712 static_assert(std::is_convertible<X, FIn0>::value,
6713 "Function does not take elements from first Container as first Parameter.");
6714 static_assert(std::is_convertible<Y, FIn1>::value,
6715 "Function does not take elements from second Container as second Parameter.");
6716 static_assert(std::is_convertible<Z, FIn2>::value,
6717 "Function does not take elements from third Container as third Parameter.");
6718 };
6719
6720 template <typename F, typename X>
6721 struct function_traits_asserts<transform_fst_tag, F, X>
6722 {
6723 static_assert(utils::function_traits<F>::arity == 1,
6724 "Function must take one parameter.");
6725 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6726 static_assert(std::is_convertible<X, FIn0>::value,
6727 "Function does not take pair.first type as first Parameter.");
6728 };
6729
6730 template <typename F, typename X>
6731 struct function_traits_asserts<transform_snd_tag, F, X>
6732 {
6733 static_assert(utils::function_traits<F>::arity == 1,
6734 "Function must take one parameter.");
6735 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6736 static_assert(std::is_convertible<X, FIn0>::value,
6737 "Function does not take pair.second type as first Parameter.");
6738 };
6739
6740 template <typename F, typename X, typename Y>
6741 struct function_traits_asserts<inner_product_with_tag, F, X, Y>
6742 {
6743 static_assert(utils::function_traits<F>::arity == 2,
6744 "Function must take two parameters.");
6745 typedef typename utils::function_traits<F>::template arg<0>::type FIn0;
6746 typedef typename utils::function_traits<F>::template arg<1>::type FIn1;
6747 static_assert(std::is_convertible<X, FIn0>::value,
6748 "Function does not take elements from first Container as first Parameter.");
6749 static_assert(std::is_convertible<Y, FIn1>::value,
6750 "Function does not take elements from second Container as second Parameter.");
6751 };
6752 }
6753 }
6754
6755 #include <utility>
6756
6757 namespace fplus
6758 {
6759 // API search type: apply_to_pair : (((a, b) -> c), (a, b)) -> c
6760 // fwd bind count: 1
6761 // Apply binary function to parts of a pair.
6762 template <typename F, typename FIn0, typename FIn1>
apply_to_pair(F f,const std::pair<FIn0,FIn1> & p)6763 auto apply_to_pair(F f, const std::pair<FIn0, FIn1>& p)
6764 {
6765 internal::trigger_static_asserts<internal::apply_to_pair_tag, F, FIn0, FIn1>();
6766 return internal::invoke(f, p.first, p.second);
6767 }
6768
6769 // API search type: zip_with : (((a, b) -> c), [a], [b]) -> [c]
6770 // fwd bind count: 2
6771 // Zip two sequences using a binary function.
6772 // zip_with((+), [1, 2, 3], [5, 6]) == [1+5, 2+6] == [6, 8]
6773 template <typename ContainerIn1,
6774 typename ContainerIn2,
6775 typename F,
6776 typename X = typename ContainerIn1::value_type,
6777 typename Y = typename ContainerIn2::value_type,
6778 typename TOut = std::decay_t<internal::invoke_result_t<F, X, Y>>,
6779 typename ContainerOut = std::vector<TOut>>
zip_with(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)6780 ContainerOut zip_with(F f, const ContainerIn1& xs, const ContainerIn2& ys)
6781 {
6782 internal::trigger_static_asserts<internal::zip_with_tag, F, X, Y>();
6783 ContainerOut result;
6784 std::size_t resultSize = std::min(size_of_cont(xs), size_of_cont(ys));
6785 internal::prepare_container(result, resultSize);
6786 auto itResult = internal::get_back_inserter(result);
6787 auto itXs = std::begin(xs);
6788 auto itYs = std::begin(ys);
6789 for (std::size_t i = 0; i < resultSize; ++i)
6790 {
6791 *itResult = internal::invoke(f, *itXs, *itYs);
6792 ++itXs;
6793 ++itYs;
6794 }
6795 return result;
6796 }
6797
6798 // API search type: zip_with_3 : (((a, b, c) -> d), [a], [b], [c]) -> [c]
6799 // fwd bind count: 3
6800 // Zip three sequences using a ternary function.
6801 // zip_with_3((+), [1, 2, 3], [5, 6], [1, 1]) == [7, 9]
6802 template <
6803 typename ContainerIn1,
6804 typename ContainerIn2,
6805 typename ContainerIn3,
6806 typename F,
6807 typename X = typename ContainerIn1::value_type,
6808 typename Y = typename ContainerIn2::value_type,
6809 typename Z = typename ContainerIn3::value_type,
6810 typename TOut = std::decay_t<internal::invoke_result_t<F, X, Y, Z>>,
6811 typename ContainerOut = typename std::vector<TOut>>
zip_with_3(F f,const ContainerIn1 & xs,const ContainerIn2 & ys,const ContainerIn3 & zs)6812 ContainerOut zip_with_3(F f,
6813 const ContainerIn1& xs,
6814 const ContainerIn2& ys,
6815 const ContainerIn3& zs)
6816 {
6817 internal::trigger_static_asserts<internal::zip_with_3_tag, F, X, Y, Z>();
6818 static_assert(std::is_same<
6819 typename internal::same_cont_new_t<ContainerIn1, void>::type,
6820 typename internal::same_cont_new_t<ContainerIn2, void>::type>::value,
6821 "All three Containers must be of same outer type.");
6822 static_assert(std::is_same<
6823 typename internal::same_cont_new_t<ContainerIn2, void>::type,
6824 typename internal::same_cont_new_t<ContainerIn3, void>::type>::value,
6825 "All three Containers must be of same outer type.");
6826 ContainerOut result;
6827 std::size_t resultSize = std::min(size_of_cont(xs), size_of_cont(ys));
6828 internal::prepare_container(result, resultSize);
6829 auto itResult = internal::get_back_inserter(result);
6830 auto itXs = std::begin(xs);
6831 auto itYs = std::begin(ys);
6832 auto itZs = std::begin(zs);
6833 for (std::size_t i = 0; i < resultSize; ++i)
6834 {
6835 *itResult = internal::invoke(f, *itXs, *itYs, *itZs);
6836 ++itXs;
6837 ++itYs;
6838 ++itZs;
6839 }
6840 return result;
6841 }
6842
6843 // API search type: zip_with_defaults : (((a, b) -> c), a, b, [a], [b]) -> [c]
6844 // fwd bind count: 4
6845 // Zip two sequences and using a binary function
6846 // and extrapolate the shorter sequence with a default value.
6847 // zip_with_defaults((+), 6, 7, [1,2,3], [1,2]) == [2,4,10]
6848 // zip_with_defaults((+), 6, 7, [1,2], [1,2,3]) == [2,4,9]
6849 template <
6850 typename ContainerIn1,
6851 typename ContainerIn2,
6852 typename F,
6853 typename X = typename ContainerIn1::value_type,
6854 typename Y = typename ContainerIn2::value_type>
zip_with_defaults(F f,const X & default_x,const Y & default_y,const ContainerIn1 & xs,const ContainerIn2 & ys)6855 auto zip_with_defaults(F f,
6856 const X& default_x,
6857 const Y& default_y,
6858 const ContainerIn1& xs,
6859 const ContainerIn2& ys)
6860 {
6861 internal::trigger_static_asserts<internal::zip_with_tag, F, X, Y>();
6862 const auto size_xs = size_of_cont(xs);
6863 const auto size_ys = size_of_cont(ys);
6864 if (size_xs < size_ys)
6865 {
6866 const auto extended_xs = append(
6867 xs,
6868 replicate<X, ContainerIn1>(size_ys - size_xs, default_x));
6869 return zip_with(f, extended_xs, ys);
6870 }
6871 else if (size_xs > size_ys)
6872 {
6873 const auto extended_ys = append(
6874 ys,
6875 replicate<Y, ContainerIn2>(size_xs - size_ys, default_y));
6876 return zip_with(f, xs, extended_ys);
6877 }
6878 return zip_with(f, xs, ys);
6879 }
6880
6881 // API search type: zip : ([a], [b]) -> [(a, b)]
6882 // fwd bind count: 1
6883 // Combine two sequences to one sequence of pairs.
6884 // zip([1, 2, 3], [5, 6]) == [(1, 5), (2, 6)]
6885 template <typename ContainerIn1, typename ContainerIn2,
6886 typename X = typename ContainerIn1::value_type,
6887 typename Y = typename ContainerIn2::value_type>
zip(const ContainerIn1 & xs,const ContainerIn2 & ys)6888 auto zip(const ContainerIn1& xs, const ContainerIn2& ys)
6889 {
6890 auto MakePair = [](const X& x, const Y& y)
6891 { return std::make_pair(x, y); };
6892 return zip_with(MakePair, xs, ys);
6893 }
6894
6895 // API search type: zip_repeat : ([a], [b]) -> [(a, b)]
6896 // fwd bind count: 1
6897 // Similar to zip but repeats the shorter sequence
6898 // to align with the longer sequence.
6899 // zip([1, 2, 3, 4], [5, 6]) == [(1, 5), (2, 6), (3, 5), (4, 6)]
6900 template <typename ContainerIn1, typename ContainerIn2>
zip_repeat(const ContainerIn1 & xs,const ContainerIn2 & ys)6901 auto zip_repeat(const ContainerIn1& xs, const ContainerIn2& ys)
6902 {
6903 auto nx = xs.size();
6904 auto ny = ys.size();
6905 auto qx = ny/nx + (ny % nx ? 1 : 0);
6906 auto qy = nx/ny + (nx % ny ? 1 : 0);
6907 return zip(qx > 1 ? repeat(qx, xs) : xs,
6908 qy > 1 ? repeat(qy, ys) : ys);
6909 }
6910
6911 // API search type: unzip : [(a, b)] -> ([a], [b])
6912 // fwd bind count: 0
6913 // Split a sequence of pairs into two sequences.
6914 // unzip([(1, 5), (2, 6)]) == ([1, 2], [5, 6])
6915 template <typename ContainerIn,
6916 typename TIn = typename ContainerIn::value_type,
6917 typename X = typename TIn::first_type,
6918 typename Y = typename TIn::second_type,
6919 typename ContainerOutX = typename internal::same_cont_new_t<ContainerIn, X>::type,
6920 typename ContainerOutY = typename internal::same_cont_new_t<ContainerIn, Y>::type>
unzip(const ContainerIn & pairs)6921 std::pair<ContainerOutX, ContainerOutY> unzip(const ContainerIn& pairs)
6922 {
6923 ContainerOutX firsts;
6924 ContainerOutY seconds;
6925 internal::prepare_container(firsts, size_of_cont(pairs));
6926 internal::prepare_container(seconds, size_of_cont(pairs));
6927 auto itFirsts = internal::get_back_inserter(firsts);
6928 auto itSeconds = internal::get_back_inserter(seconds);
6929 for (const auto& pair : pairs)
6930 {
6931 *itFirsts = pair.first;
6932 *itSeconds = pair.second;
6933 }
6934 return std::make_pair(firsts, seconds);
6935 }
6936
6937 // API search type: fst : ((a, b)) -> a
6938 // fwd bind count: 0
6939 // Return the first element of a pair.
6940 // fst((0, 1)) == 0
6941 template <typename X, typename Y>
6942 X fst(const std::pair<X, Y>& pair)
6943 {
6944 return pair.first;
6945 }
6946
6947 // API search type: snd : ((a, b)) -> b
6948 // fwd bind count: 0
6949 // Return the second element of a pair.
6950 // snd((0, 1)) == 1
6951 template <typename X, typename Y>
snd(const std::pair<X,Y> & pair)6952 Y snd(const std::pair<X, Y>& pair)
6953 {
6954 return pair.second;
6955 }
6956
6957 // API search type: transform_fst : ((a -> c), (a, b)) -> (c, b)
6958 // fwd bind count: 1
6959 // Apply a function to the first element of a pair.
6960 // transform_fst(square, (4, 5)) == (16, 5)
6961 template <typename X, typename Y, typename F,
6962 typename ResultFirst = std::decay_t<internal::invoke_result_t<F, X>>>
transform_fst(F f,const std::pair<X,Y> & pair)6963 std::pair<ResultFirst, Y> transform_fst(F f, const std::pair<X, Y>& pair)
6964 {
6965 internal::trigger_static_asserts<internal::transform_fst_tag, F, X>();
6966 return std::make_pair(internal::invoke(f, pair.first), pair.second);
6967 }
6968
6969 // API search type: transform_snd : ((b -> c), (a, b)) -> (a, c)
6970 // fwd bind count: 1
6971 // Apply a function to the second element of a pair.
6972 // transform_snd(square, (4, 5)) == (4, 25)
6973 template <typename X, typename Y, typename F,
6974 typename ResultSecond = std::decay_t<internal::invoke_result_t<F, Y>>>
transform_snd(F f,const std::pair<X,Y> & pair)6975 std::pair<X, ResultSecond> transform_snd(F f, const std::pair<X, Y>& pair)
6976 {
6977 internal::trigger_static_asserts<internal::transform_snd_tag, F, Y>();
6978 return std::make_pair(pair.first, internal::invoke(f, pair.second));
6979 }
6980
6981 // API search type: transform_pair : ((a -> c), (b -> d), (a, b)) -> (c, d)
6982 // fwd bind count: 2
6983 // Apply functions the both parts of a pair.
6984 // transform_pair(square, square, (4, 5)) == (16, 25)
6985 template <
6986 typename X,
6987 typename Y,
6988 typename F,
6989 typename G,
6990 typename ResultFirst = std::decay_t<internal::invoke_result_t<F, X>>,
6991 typename ResultSecond = std::decay_t<internal::invoke_result_t<G, Y>>>
transform_pair(F f,G g,const std::pair<X,Y> & pair)6992 std::pair<ResultFirst, ResultSecond> transform_pair(F f,
6993 G g,
6994 const std::pair<X, Y>& pair)
6995 {
6996 internal::trigger_static_asserts<internal::transform_fst_tag, F, X>();
6997 internal::trigger_static_asserts<internal::transform_snd_tag, G, Y>();
6998 return std::make_pair(internal::invoke(f, pair.first),
6999 internal::invoke(g, pair.second));
7000 }
7001
7002 // API search type: swap_pair_elems : (a, b) -> (b, a)
7003 // fwd bind count: 0
7004 // Swap the first and the second element of a pair.
7005 // swap_pair_elems((3,4)) == (4,3)
7006 template <typename X, typename Y>
swap_pair_elems(const std::pair<X,Y> & pair)7007 std::pair<Y, X> swap_pair_elems(const std::pair<X, Y>& pair)
7008 {
7009 return std::make_pair(pair.second, pair.first);
7010 }
7011
7012 // API search type: swap_pairs_elems : [(a, b)] -> [(b, a)]
7013 // fwd bind count: 0
7014 // Swap the first and the second element of every pair in a sequence.
7015 // swap_pairs_elems([(1,2), (3,4)]) == [(2,1), (4,3)]
7016 template <typename ContainerIn,
7017 typename X = typename ContainerIn::value_type::first_type,
7018 typename Y = typename ContainerIn::value_type::second_type>
swap_pairs_elems(const ContainerIn & xs)7019 auto swap_pairs_elems(const ContainerIn& xs)
7020 {
7021 return fplus::transform(swap_pair_elems<X, Y>, xs);
7022 }
7023
7024 // API search type: adjacent_pairs : [a] -> [(a, a)]
7025 // fwd bind count: 0
7026 // Split a sequence into pairs of elements.
7027 // adjacent_pairs([0,1,2,3,4]) == [(0,1), (2,3)]
7028 // Also known as zip_with_next.
7029 template <typename Container,
7030 typename ContainerOut =
7031 typename internal::same_cont_new_t<Container,
7032 std::pair<
7033 typename Container::value_type,
7034 typename Container::value_type>>::type>
adjacent_pairs(const Container & xs)7035 ContainerOut adjacent_pairs(const Container& xs)
7036 {
7037 typedef typename Container::value_type T;
7038 static_assert(std::is_convertible<
7039 std::pair<T, T>,
7040 typename ContainerOut::value_type>::value,
7041 "ContainerOut can not store pairs of elements from ContainerIn.");
7042 ContainerOut result;
7043 if (size_of_cont(xs) < 2)
7044 return result;
7045 const std::size_t out_size = size_of_cont(xs) / 2;
7046 internal::prepare_container(result, out_size);
7047 auto itOut = internal::get_back_inserter(result);
7048 auto it1 = std::begin(xs);
7049 auto it2 = it1;
7050 internal::advance_iterator(it2, 1);
7051 const auto it_source_end =
7052 internal::add_to_iterator(std::begin(xs), out_size + out_size);
7053 for (;;)
7054 {
7055 *itOut = std::make_pair(*it1, *it2);
7056 internal::advance_iterator(it1, 2);
7057 if (it1 == it_source_end)
7058 break;
7059 internal::advance_iterator(it2, 2);
7060 }
7061 return result;
7062 }
7063
7064 // API search type: overlapping_pairs : [a] -> [(a, a)]
7065 // fwd bind count: 0
7066 // Zip a sequence with itself shifted one element.
7067 // overlapping_pairs([0,1,2,3]) == [(0,1),(1,2),(2,3)]
7068 template <typename Container,
7069 typename ContainerOut =
7070 typename internal::same_cont_new_t<Container,
7071 std::pair<
7072 typename Container::value_type,
7073 typename Container::value_type>, -1>::type>
overlapping_pairs(const Container & xs)7074 ContainerOut overlapping_pairs(const Container& xs)
7075 {
7076 typedef typename Container::value_type T;
7077 static_assert(std::is_convertible<
7078 std::pair<T, T>,
7079 typename ContainerOut::value_type>::value,
7080 "ContainerOut can not store pairs of elements from ContainerIn.");
7081 ContainerOut result;
7082 if (size_of_cont(xs) < 2)
7083 return result;
7084 internal::prepare_container(result, size_of_cont(xs) - 1);
7085 auto itOut = internal::get_back_inserter(result);
7086 auto it1 = std::begin(xs);
7087 auto it2 = it1;
7088 internal::advance_iterator(it2, 1);
7089 for (; it2 != std::end(xs); ++it1, ++it2)
7090 {
7091 *itOut = std::make_pair(*it1, *it2);
7092 }
7093 return result;
7094 }
7095
7096 // API search type: overlapping_pairs_cyclic : [a] -> [(a, a)]
7097 // fwd bind count: 0
7098 // Zip a sequence with itself shifted one element,
7099 // finally zipping the last element with the first one.
7100 // overlapping_pairs_cyclic([0,1,2,3]) == [(0,1),(1,2),(2,3),(3,0)]
7101 template <typename Container,
7102 typename ContainerOut =
7103 typename internal::same_cont_new_t<Container,
7104 std::pair<
7105 typename Container::value_type,
7106 typename Container::value_type>, 0>::type>
overlapping_pairs_cyclic(const Container & xs)7107 ContainerOut overlapping_pairs_cyclic(const Container& xs)
7108 {
7109 typedef typename Container::value_type T;
7110 static_assert(std::is_convertible<
7111 std::pair<T, T>,
7112 typename ContainerOut::value_type>::value,
7113 "ContainerOut can not store pairs of elements from ContainerIn.");
7114 ContainerOut result;
7115 if (size_of_cont(xs) < 2)
7116 return result;
7117 internal::prepare_container(result, size_of_cont(xs));
7118 auto itOut = internal::get_back_inserter(result);
7119 auto it1 = std::begin(xs);
7120 auto it2 = it1;
7121 internal::advance_iterator(it2, 1);
7122 for (; it2 != std::end(xs); ++it1, ++it2)
7123 {
7124 *itOut = std::make_pair(*it1, *it2);
7125 }
7126 *itOut = std::make_pair(*it1, xs.front());
7127 return result;
7128 }
7129
7130 // API search type: enumerate : [a] -> [(Int, a)]
7131 // fwd bind count: 0
7132 // Attach its index to every element of a sequence.
7133 // enumerate([6,4,7,6]) == [(0, 6), (1, 4), (2, 7), (3, 6)]
7134 template <typename Container>
enumerate(const Container & xs)7135 auto enumerate(const Container& xs)
7136 {
7137 return zip(all_idxs(xs), xs);
7138 }
7139
7140 // API search type: inner_product_with : (((a, a) -> b), ((b, b) -> b), b, [a], [a]) -> b
7141 // fwd bind count: 4
7142 // Calculate the inner product of two sequences using custom operations.
7143 // inner_product_with((+), (*), [1, 2, 3], [4, 5, 6]) == [32]
7144 template <
7145 typename ContainerIn1,
7146 typename ContainerIn2,
7147 typename OP1,
7148 typename OP2,
7149 typename Acc,
7150 typename X = typename ContainerIn1::value_type,
7151 typename Y = typename ContainerIn2::value_type,
7152 typename OP2Out = internal::invoke_result_t<OP2, X, Y>>
inner_product_with(OP1 op1,OP2 op2,const Acc & value,const ContainerIn1 & xs,const ContainerIn2 & ys)7153 auto inner_product_with(OP1 op1,
7154 OP2 op2,
7155 const Acc& value,
7156 const ContainerIn1& xs,
7157 const ContainerIn2& ys)
7158 {
7159 internal::trigger_static_asserts<internal::inner_product_with_tag, OP2, X, Y>();
7160 internal::trigger_static_asserts<internal::inner_product_with_tag, OP1, Acc, OP2Out>();
7161 assert(size_of_cont(xs) == size_of_cont(ys));
7162 return std::inner_product(
7163 std::begin(xs), std::end(xs), std::begin(ys), value, op1, op2);
7164 }
7165
7166 // API search type: inner_product : (a, [a], [a]) -> a
7167 // fwd bind count: 2
7168 // Calculate the inner product of two sequences.
7169 // inner_product([1, 2, 3], [4, 5, 6]) == [32]
7170 template <typename ContainerIn1, typename ContainerIn2,
7171 typename Z>
inner_product(const Z & value,const ContainerIn1 & xs,const ContainerIn2 & ys)7172 Z inner_product(const Z& value,
7173 const ContainerIn1& xs, const ContainerIn2& ys)
7174 {
7175 assert(size_of_cont(xs) == size_of_cont(ys));
7176
7177 return std::inner_product(
7178 std::begin(xs), std::end(xs), std::begin(ys), value);
7179 }
7180
7181 // API search type: first_mismatch_idx_by : (((a, b) -> Bool), [a], [b]) -> Maybe Int
7182 // fwd bind count: 2
7183 // Find the first index at which the two sequences differ
7184 // using a binary predicate.
7185 // first_mismatch_idx_by((==), [1, 2, 3], [1, 4, 3]) == Just 1
7186 // first_mismatch_idx_by((==), [1, 2, 3], [1, 4]) == Just 1
7187 // first_mismatch_idx_by((==), [1, 2, 3], [1, 2]) == Nothing
7188 // first_mismatch_idx_by((==), [], [1, 2]) == Nothing
7189 template <typename ContainerIn1, typename ContainerIn2,
7190 typename BinaryPredicate>
first_mismatch_idx_by(BinaryPredicate p,const ContainerIn1 & xs,const ContainerIn2 & ys)7191 maybe<std::size_t> first_mismatch_idx_by(BinaryPredicate p,
7192 const ContainerIn1& xs, const ContainerIn2& ys)
7193 {
7194 auto itXs = std::begin(xs);
7195 auto itYs = std::begin(ys);
7196 std::size_t minSize = std::min(size_of_cont(xs), size_of_cont(ys));
7197 for (std::size_t i = 0; i < minSize; ++i)
7198 {
7199 if (!internal::invoke(p, *itXs, *itYs))
7200 {
7201 return just(i);
7202 }
7203 ++itXs;
7204 ++itYs;
7205 }
7206 return nothing<std::size_t>();
7207 }
7208
7209 // API search type: first_mismatch_by : (((a, b) -> Bool), [a], [b]) -> Maybe (a, b)
7210 // fwd bind count: 2
7211 // Find the first pair of elements differing in the two sequences
7212 // using a binary predicate.
7213 // first_mismatch_by((==), [1, 2, 3], [1, 4, 3]) == Just (2, 4)
7214 // first_mismatch_by((==), [1, 2, 3], [1, 4]) == Just (2, 4)
7215 // first_mismatch_by((==), [1, 2, 3], [1, 2]) == Nothing
7216 // first_mismatch_by((==), [], [1, 2]) == Nothing
7217 template <typename ContainerIn1, typename ContainerIn2,
7218 typename BinaryPredicate,
7219 typename X = typename ContainerIn1::value_type,
7220 typename Y = typename ContainerIn2::value_type,
7221 typename TOut = std::pair<X, Y>>
first_mismatch_by(BinaryPredicate p,const ContainerIn1 & xs,const ContainerIn2 & ys)7222 maybe<TOut> first_mismatch_by(BinaryPredicate p,
7223 const ContainerIn1& xs, const ContainerIn2& ys)
7224 {
7225 const auto maybe_idx = first_mismatch_idx_by(p, xs, ys);
7226 if (is_nothing(maybe_idx))
7227 {
7228 return nothing<TOut>();
7229 }
7230 else
7231 {
7232 const auto idx = maybe_idx.unsafe_get_just();
7233 return just(std::make_pair(
7234 elem_at_idx(idx, xs),
7235 elem_at_idx(idx, ys)));
7236 }
7237 }
7238
7239 // API search type: first_mismatch_idx_on : ((a -> b), [a], [a]) -> Maybe Int
7240 // fwd bind count: 2
7241 // Find the first index of elements differing in the two sequences
7242 // using a transformer.
7243 // first_mismatch_idx_on((mod 2), [1, 2, 3], [3, 5, 3]) == 1
7244 // first_mismatch_idx_on((mod 2), [1, 2, 3], [1, 5]) == 1
7245 // first_mismatch_idx_on((mod 2), [1, 2, 3], [1, 6]) == Nothing
7246 // first_mismatch_idx_on((mod 2), [], [1, 2]) == Nothing
7247 template <typename ContainerIn1, typename ContainerIn2,
7248 typename F,
7249 typename X = typename ContainerIn1::value_type,
7250 typename Y = typename ContainerIn2::value_type,
7251 typename TOut = std::pair<X, Y>>
first_mismatch_idx_on(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7252 maybe<std::size_t> first_mismatch_idx_on(F f,
7253 const ContainerIn1& xs, const ContainerIn2& ys)
7254 {
7255 static_assert(std::is_same<X, Y>::value,
7256 "Both containers must have the same element type.");
7257 return first_mismatch_idx_by(is_equal_by(f), xs, ys);
7258 }
7259
7260 // API search type: first_mismatch_on : ((a -> b), [a], [a]) -> Maybe (a, a)
7261 // fwd bind count: 2
7262 // Find the first pair of elements differing in the two sequences
7263 // using a transformer.
7264 // first_mismatch_on((mod 2), [1, 2, 3], [3, 5, 3]) == Just (2, 5)
7265 // first_mismatch_on((mod 2), [1, 2, 3], [1, 5]) == Just (2, 5)
7266 // first_mismatch_on((mod 2), [1, 2, 3], [1, 6]) == Nothing
7267 // first_mismatch_on((mod 2), [], [1, 2]) == Nothing
7268 template <typename ContainerIn1, typename ContainerIn2,
7269 typename F,
7270 typename X = typename ContainerIn1::value_type,
7271 typename Y = typename ContainerIn2::value_type,
7272 typename TOut = std::pair<X, Y>>
first_mismatch_on(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7273 maybe<TOut> first_mismatch_on(F f,
7274 const ContainerIn1& xs, const ContainerIn2& ys)
7275 {
7276 static_assert(std::is_same<X, Y>::value,
7277 "Both containers must have the same element type.");
7278 return first_mismatch_by(is_equal_by(f), xs, ys);
7279 }
7280
7281 // API search type: first_mismatch_idx : ([a], [a]) -> Maybe Int
7282 // fwd bind count: 2
7283 // Find the first index of elements differing in the two sequences.
7284 // first_mismatch_idx((==), [1, 2, 3], [1, 4, 3]) == 1
7285 // first_mismatch_idx((==), [1, 2, 3], [1, 4]) == 1
7286 // first_mismatch_idx((==), [1, 2, 3], [1, 2]) == Nothing
7287 // first_mismatch_idx((==), [], [1, 2]) == Nothing
7288 template <typename ContainerIn1, typename ContainerIn2,
7289 typename X = typename ContainerIn1::value_type,
7290 typename Y = typename ContainerIn2::value_type>
first_mismatch_idx(const ContainerIn1 & xs,const ContainerIn2 & ys)7291 maybe<std::size_t> first_mismatch_idx(
7292 const ContainerIn1& xs, const ContainerIn2& ys)
7293 {
7294 static_assert(std::is_same<X, Y>::value,
7295 "Both containers must have the same element type.");
7296 return first_mismatch_idx_by(std::equal_to<X>(), xs, ys);
7297 }
7298
7299 // API search type: first_mismatch : ([a], [a]) -> Maybe (a, a)
7300 // fwd bind count: 2
7301 // Find the first pair of elements differing in the two sequences
7302 // first_mismatch((==), [1, 2, 3], [1, 4, 3]) == Just (2, 4)
7303 // first_mismatch((==), [1, 2, 3], [1, 4]) == Just (2, 4)
7304 // first_mismatch((==), [1, 2, 3], [1, 2]) == Nothing
7305 // first_mismatch((==), [], [1, 2]) == Nothing
7306 template <typename ContainerIn1, typename ContainerIn2,
7307 typename X = typename ContainerIn1::value_type,
7308 typename Y = typename ContainerIn2::value_type,
7309 typename TOut = std::pair<X, Y>>
first_mismatch(const ContainerIn1 & xs,const ContainerIn2 & ys)7310 maybe<TOut> first_mismatch(const ContainerIn1& xs, const ContainerIn2& ys)
7311 {
7312 static_assert(std::is_same<X, Y>::value,
7313 "Both containers must have the same element type.");
7314 return first_mismatch_by(std::equal_to<X>(), xs, ys);
7315 }
7316
7317 // API search type: first_match_idx_by : (((a, b) -> Bool), [a], [b]) -> Maybe Int
7318 // fwd bind count: 2
7319 // Find the first index at which the two sequences equal
7320 // using a binary predicate.
7321 // first_match_idx_by((==), [1, 2, 3], [3, 2, 3]) == Just 1
7322 // first_match_idx_by((==), [], [1, 2]) == Nothing
7323 template <typename ContainerIn1, typename ContainerIn2,
7324 typename F,
7325 typename X = typename ContainerIn1::value_type,
7326 typename Y = typename ContainerIn2::value_type>
first_match_idx_by(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7327 maybe<std::size_t> first_match_idx_by(F f,
7328 const ContainerIn1& xs, const ContainerIn2& ys)
7329 {
7330 auto itXs = std::begin(xs);
7331 auto itYs = std::begin(ys);
7332 std::size_t minSize = std::min(size_of_cont(xs), size_of_cont(ys));
7333 for (std::size_t i = 0; i < minSize; ++i)
7334 {
7335 if (internal::invoke(f, *itXs, *itYs))
7336 {
7337 return just(i);
7338 }
7339 ++itXs;
7340 ++itYs;
7341 }
7342 return nothing<std::size_t>();
7343 }
7344
7345 // API search type: first_match_by : (((a, b) -> Bool), [a], [b]) -> Maybe (a, b)
7346 // fwd bind count: 2
7347 // Find the first pair of equal elements in the two sequences
7348 // using a binary predicate.
7349 // first_match_by((==), [1, 2, 3], [3, 2, 3]) == Just (2, 2)
7350 // first_match_by((==), [], [1, 2]) == Nothing
7351 template <typename ContainerIn1, typename ContainerIn2,
7352 typename F,
7353 typename X = typename ContainerIn1::value_type,
7354 typename Y = typename ContainerIn2::value_type,
7355 typename TOut = std::pair<X, Y>>
first_match_by(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7356 maybe<TOut> first_match_by(F f, const ContainerIn1& xs, const ContainerIn2& ys)
7357 {
7358 const auto maybe_idx = first_match_idx_by(f, xs, ys);
7359 if (is_nothing(maybe_idx))
7360 {
7361 return nothing<TOut>();
7362 }
7363 else
7364 {
7365 const auto idx = maybe_idx.unsafe_get_just();
7366 return just(std::make_pair(
7367 elem_at_idx(idx, xs),
7368 elem_at_idx(idx, ys)));
7369 }
7370 }
7371
7372 // API search type: first_match_idx_on : ((a -> b), [a], [a]) -> Maybe Int
7373 // fwd bind count: 2
7374 // Find the first index of equal elements in the two sequences
7375 // using a transformer.
7376 // first_match_idx_on((mod 2), [1, 2, 3], [2, 4, 3]) == 1
7377 // first_match_idx_on((mod 2), [], [1, 2]) == Nothing
7378 template <typename ContainerIn1, typename ContainerIn2,
7379 typename F,
7380 typename X = typename ContainerIn1::value_type,
7381 typename Y = typename ContainerIn2::value_type>
first_match_idx_on(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7382 maybe<std::size_t> first_match_idx_on(F f,
7383 const ContainerIn1& xs, const ContainerIn2& ys)
7384 {
7385 static_assert(std::is_same<X, Y>::value,
7386 "Both containers must have the same element type.");
7387 return first_match_idx_by(is_equal_by(f), xs, ys);
7388 }
7389
7390 // API search type: first_match_on : ((a -> b), [a], [a]) -> Maybe (a, a)
7391 // fwd bind count: 2
7392 // Find the first pair of equal elements in the two sequences
7393 // using a transformer.
7394 // first_match_on((mod 2), [1, 2, 3], [2, 4, 3]) == Just (2, 4)
7395 // first_match_on((mod 2), [], [1, 2]) == Nothing
7396 template <typename ContainerIn1, typename ContainerIn2,
7397 typename F,
7398 typename X = typename ContainerIn1::value_type,
7399 typename Y = typename ContainerIn2::value_type,
7400 typename TOut = std::pair<X, Y>>
first_match_on(F f,const ContainerIn1 & xs,const ContainerIn2 & ys)7401 maybe<TOut> first_match_on(F f, const ContainerIn1& xs, const ContainerIn2& ys)
7402 {
7403 static_assert(std::is_same<X, Y>::value,
7404 "Both containers must have the same element type.");
7405 return first_match_by(is_equal_by(f), xs, ys);
7406 }
7407
7408 // API search type: first_match_idx : ([a], [a]) -> Maybe Int
7409 // fwd bind count: 2
7410 // Find the first index of equal elements in the two sequences.
7411 // first_match_idx((==), [1, 2, 3], [5, 2, 3]) == 1
7412 // first_match_idx((==), [], [1, 2]) == Nothing
7413 template <typename ContainerIn1, typename ContainerIn2,
7414 typename X = typename ContainerIn1::value_type,
7415 typename Y = typename ContainerIn2::value_type>
first_match_idx(const ContainerIn1 & xs,const ContainerIn2 & ys)7416 maybe<std::size_t> first_match_idx(
7417 const ContainerIn1& xs, const ContainerIn2& ys)
7418 {
7419 static_assert(std::is_same<X, Y>::value,
7420 "Both containers must have the same element type.");
7421 return first_match_idx_by(std::equal_to<X>(), xs, ys);
7422 }
7423
7424 // API search type: first_match : ([a], [a]) -> Maybe (a, a)
7425 // fwd bind count: 2
7426 // Find the first pair of equal elements in the two sequences.
7427 // first_match((==), [1, 2, 3], [5, 2, 3]) == Just (2, 2)
7428 // first_match((==), [], [1, 2]) == Nothing
7429 template <typename ContainerIn1, typename ContainerIn2,
7430 typename X = typename ContainerIn1::value_type,
7431 typename Y = typename ContainerIn2::value_type,
7432 typename TOut = std::pair<X, Y>>
first_match(const ContainerIn1 & xs,const ContainerIn2 & ys)7433 maybe<TOut> first_match(const ContainerIn1& xs, const ContainerIn2& ys)
7434 {
7435 static_assert(std::is_same<X, Y>::value,
7436 "Both containers must have the same element type.");
7437 return first_match_by(std::equal_to<X>(), xs, ys);
7438 }
7439
7440 } // namespace fplus
7441
7442 #include <algorithm>
7443 #include <cmath>
7444 #include <functional>
7445 #include <limits>
7446 #include <stdexcept>
7447 #include <type_traits>
7448
7449 namespace fplus
7450 {
7451
7452 // API search type: is_in_interval : (a, a, a) -> Bool
7453 // fwd bind count: 2
7454 // Checks if x is in [low, high), i.e. left-closed and right-open.
7455 template <typename T>
is_in_interval(const T & low,const T & high,const T & x)7456 bool is_in_interval(const T& low, const T& high, const T& x)
7457 {
7458 return (low <= x) && (x < high);
7459 }
7460
7461 // API search type: is_in_interval_around : (a, a, a) -> Bool
7462 // fwd bind count: 2
7463 // Checks if x is in [center - radius, center + radius),
7464 // i.e. left-closed and right-open.
7465 template <typename T>
is_in_interval_around(const T & radius,const T & center,const T & x)7466 bool is_in_interval_around(const T& radius, const T& center, const T& x)
7467 {
7468 return is_in_interval(center - radius, center + radius, x);
7469 }
7470
7471 // API search type: is_in_open_interval : (a, a, a) -> Bool
7472 // fwd bind count: 2
7473 // Checks if x is in (low, high), i.e. left-open and right-open.
7474 template <typename T>
is_in_open_interval(const T & low,const T & high,const T & x)7475 bool is_in_open_interval(const T& low, const T& high, const T& x)
7476 {
7477 return (low < x) && (x < high);
7478 }
7479
7480 // API search type: is_in_open_interval_around : (a, a, a) -> Bool
7481 // fwd bind count: 2
7482 // Checks if x is in (center - radius, center + radius),
7483 // i.e. left-open and right-open.
7484 template <typename T>
is_in_open_interval_around(const T & radius,const T & center,const T & x)7485 bool is_in_open_interval_around(const T& radius, const T& center, const T& x)
7486 {
7487 return is_in_open_interval(center - radius, center + radius, x);
7488 }
7489
7490 // API search type: is_in_closed_interval : (a, a, a) -> Bool
7491 // fwd bind count: 2
7492 // Checks if x is in [low, high], i.e. left-closed and right-closed.
7493 template <typename T>
is_in_closed_interval(const T & low,const T & high,const T & x)7494 bool is_in_closed_interval(const T& low, const T& high, const T& x)
7495 {
7496 return (low <= x) && (x <= high);
7497 }
7498
7499 // API search type: is_in_closed_interval_around : (a, a, a) -> Bool
7500 // Checks if x is in [center - radius, center + radius],
7501 // i.e. left-closed and right-closed.
7502 template <typename T>
is_in_closed_interval_around(const T & radius,const T & center,const T & x)7503 bool is_in_closed_interval_around(const T& radius, const T& center, const T& x)
7504 {
7505 return is_in_closed_interval(center - radius, center + radius, x);
7506 }
7507
7508 // API search type: reference_interval : (Float, Float, Float, Float, Float) -> Float
7509 // fwd bind count: 4
7510 // Linearly projects a value
7511 // from [old_low, old_high] into [new_low, new_high].
7512 // Does not clamp.
7513 // reference_interval(2, 6, 0, 4, 3) == 5
7514 // reference_interval(2, 10, 0, 4, 3) == 8
7515 // reference_interval(2, 6, 0, 4, -1) == 1
7516 // reference_interval(2, 10, 0, 4, -1) == 0
7517 template <typename T>
reference_interval(const T & new_low,const T & new_high,const T & old_low,const T & old_high,const T & x)7518 T reference_interval(const T& new_low, const T& new_high,
7519 const T& old_low, const T& old_high, const T& x)
7520 {
7521 const T scale = (new_high - new_low) / (old_high - old_low);
7522 return scale * (x - old_low) + new_low;
7523 }
7524
7525 // API search type: clamp : (a, a, a) -> a
7526 // fwd bind count: 2
7527 // Puts value into [low, high], i.e. left-closed and right-closed.
7528 template <typename T>
clamp(const T & low,const T & high,const T & x)7529 T clamp(const T& low, const T& high, const T& x)
7530 {
7531 return std::max(low, std::min(high, x));
7532 }
7533
7534 // API search type: is_negative : a -> Bool
7535 // fwd bind count: 0
7536 // Checks if x < 0.
7537 template <typename X>
is_negative(X x)7538 bool is_negative(X x)
7539 {
7540 return x < 0;
7541 }
7542
7543 // API search type: is_positive : a -> Bool
7544 // fwd bind count: 0
7545 // Checks if x is not negative.
7546 template <typename X>
is_positive(X x)7547 bool is_positive(X x)
7548 {
7549 return !is_negative(x);
7550 }
7551
7552 namespace internal
7553 {
7554 template <typename X>
7555 typename std::enable_if<std::is_unsigned<X>::value, X>::type
abs_helper(X x)7556 abs_helper(X x)
7557 {
7558 return x;
7559 }
7560
7561 template <typename X>
7562 typename std::enable_if<!std::is_unsigned<X>::value, X>::type
abs_helper(X x)7563 abs_helper(X x)
7564 {
7565 return std::abs(x);
7566 }
7567 }
7568
7569 // API search type: abs : a -> a
7570 // fwd bind count: 0
7571 // Returns the absolute (always non-negative) value of x.
7572 template <typename X>
abs(X x)7573 X abs(X x)
7574 {
7575 return internal::abs_helper(x);
7576 }
7577
7578 // API search type: abs_diff : (a, a) -> a
7579 // fwd bind count: 1
7580 // Returns the absolute difference of two values.
7581 template <typename X>
abs_diff(X a,X b)7582 X abs_diff(X a, X b)
7583 {
7584 return a > b ? a - b : b - a;
7585 }
7586
7587 // API search type: square : a -> a
7588 // fwd bind count: 0
7589 // Returns the square (x*x) of a value x.
7590 template <typename X>
square(X x)7591 X square(X x)
7592 {
7593 return x * x;
7594 }
7595
7596 // API search type: cube : a -> a
7597 // fwd bind count: 0
7598 // Returns the cube (x*x*x) of a value x.
7599 template <typename X>
cube(X x)7600 X cube(X x)
7601 {
7602 return x * x * x;
7603 }
7604
7605 // API search type: sign : a -> Int
7606 // fwd bind count: 0
7607 // Returns -1 for negative values, 1 otherwise.
7608 // sign(-3) == -1
7609 // sign(0) == 1
7610 // sign(16) == 1
7611 template <typename X>
sign(X x)7612 int sign(X x)
7613 {
7614 return is_negative(x) ? -1 : 1;
7615 }
7616
7617 // API search type: sign_with_zero : a -> Int
7618 // fwd bind count: 0
7619 // Returns -1 for negative values, 0 for zero, 1 for positive values.
7620 // sign_with_zero(-3) == -1
7621 // sign_with_zero(0) == 0
7622 // sign_with_zero(16) == 1
7623 template <typename X>
sign_with_zero(X x)7624 int sign_with_zero(X x)
7625 {
7626 return x == 0 ? 0 : sign(x);
7627 }
7628
7629 // API search type: integral_cast_throw : Int -> Int
7630 // fwd bind count: 0
7631 // Converts one integer type into another.
7632 // Throws an std::underflow_error or std::overflow_error
7633 // if the value does not fit into the destination type.
7634 template <typename Out, typename X>
7635 Out integral_cast_throw(X x)
7636 {
7637 #ifdef _MSC_VER
7638 __pragma(warning(push))
7639 __pragma(warning(disable:4127))
7640 #endif
7641 static_assert(std::is_integral<X>::value, "type must be integral");
7642 static_assert(std::is_integral<Out>::value, "type must be integral");
7643 if (std::is_signed<X>::value && std::is_signed<Out>::value)
7644 {
7645 if (static_cast<std::int64_t>(x) <
7646 static_cast<std::int64_t>(std::numeric_limits<Out>::lowest()))
7647 {
7648 throw std::underflow_error("");
7649 }
7650 if (static_cast<std::int64_t>(x) >
7651 static_cast<std::int64_t>(std::numeric_limits<Out>::max()))
7652 {
7653 throw std::overflow_error("");
7654 }
7655 return static_cast<Out>(x);
7656 }
7657 else if (!std::is_signed<X>::value && !std::is_signed<Out>::value)
7658 {
7659 if (static_cast<std::uint64_t>(x) <
7660 static_cast<std::uint64_t>(std::numeric_limits<Out>::lowest()))
7661 {
7662 throw std::underflow_error("");
7663 }
7664 if (static_cast<std::uint64_t>(x) >
7665 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7666 {
7667 throw std::overflow_error("");
7668 }
7669 return static_cast<Out>(x);
7670 }
7671 else if (std::is_signed<X>::value && !std::is_signed<Out>::value)
7672 {
7673 if (x < 0)
7674 return 0;
7675 if (static_cast<std::uint64_t>(x) >
7676 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7677 {
7678 throw std::overflow_error("");
7679 }
7680 return static_cast<Out>(x);
7681 }
7682 else if (!std::is_signed<X>::value && std::is_signed<Out>::value)
7683 {
7684 if (static_cast<std::uint64_t>(x) >
7685 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7686 {
7687 throw std::overflow_error("");
7688 }
7689 return static_cast<Out>(x);
7690 }
7691 else
7692 {
7693 assert(false);
7694 return static_cast<Out>(x);
7695 }
7696 #ifdef _MSC_VER
7697 __pragma(warning(pop))
7698 #endif
7699 }
7700
7701 // API search type: integral_cast_clamp : Int -> Int
7702 // fwd bind count: 0
7703 // Converts one integer type into another.
7704 // If the value does not fit into the destination type,
7705 // the nearest possible value is used.
7706 // Also known as saturate_cast.
7707 template <typename Out, typename X>
7708 Out integral_cast_clamp(X x)
7709 {
7710 static_assert(std::is_integral<X>::value, "type must be integral");
7711 static_assert(std::is_integral<Out>::value, "type must be integral");
7712 if (std::is_signed<X>::value && std::is_signed<Out>::value)
7713 {
7714 if (static_cast<std::int64_t>(x) <
7715 static_cast<std::int64_t>(std::numeric_limits<Out>::lowest()))
7716 {
7717 return std::numeric_limits<Out>::lowest();
7718 }
7719 if (static_cast<std::int64_t>(x) >
7720 static_cast<std::int64_t>(std::numeric_limits<Out>::max()))
7721 {
7722 return std::numeric_limits<Out>::max();
7723 }
7724 return static_cast<Out>(x);
7725 }
7726 else if (!std::is_signed<X>::value && !std::is_signed<Out>::value)
7727 {
7728 if (static_cast<std::uint64_t>(x) <
7729 static_cast<std::uint64_t>(std::numeric_limits<Out>::lowest()))
7730 {
7731 return std::numeric_limits<Out>::lowest();
7732 }
7733 if (static_cast<std::uint64_t>(x) >
7734 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7735 {
7736 return std::numeric_limits<Out>::max();
7737 }
7738 return static_cast<Out>(x);
7739 }
7740 else if (std::is_signed<X>::value && !std::is_signed<Out>::value)
7741 {
7742 if (x < 0)
7743 return 0;
7744 if (static_cast<std::uint64_t>(x) >
7745 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7746 {
7747 return std::numeric_limits<Out>::max();
7748 }
7749 return static_cast<Out>(x);
7750 }
7751 else if (!std::is_signed<X>::value && std::is_signed<Out>::value)
7752 {
7753 if (static_cast<std::uint64_t>(x) >
7754 static_cast<std::uint64_t>(std::numeric_limits<Out>::max()))
7755 {
7756 return std::numeric_limits<Out>::max();
7757 }
7758 return static_cast<Out>(x);
7759 }
7760 else
7761 {
7762 assert(false);
7763 return static_cast<Out>(x);
7764 }
7765 }
7766
7767 // API search type: round : a -> Int
7768 // fwd bind count: 0
7769 // Converts a value to the nearest integer.
7770 template <typename X, typename Out = int>
round(X x)7771 Out round(X x)
7772 {
7773 static_assert(!std::is_integral<X>::value, "type must be non-integral");
7774 static_assert(std::is_integral<Out>::value, "type must be integral");
7775 if (static_cast<double>(x) < static_cast<double>(std::numeric_limits<Out>::lowest()))
7776 return std::numeric_limits<Out>::lowest();
7777 if (static_cast<double>(x) > static_cast<double>(std::numeric_limits<Out>::max()))
7778 return std::numeric_limits<Out>::max();
7779 if (is_negative(x))
7780 x -= 1;
7781 return static_cast<Out>(x + 0.5);
7782 }
7783
7784 // API search type: floor : a -> b
7785 // fwd bind count: 0
7786 // Converts a value to the nearest smaller integer.
7787 template <typename X, typename Out = int>
floor(X x)7788 Out floor(X x)
7789 {
7790 static_assert(!std::is_integral<X>::value, "type must be non-integral");
7791 static_assert(std::is_integral<Out>::value, "type must be integral");
7792 if (is_negative(x))
7793 x -= 1;
7794 return static_cast<Out>(x);
7795 }
7796
7797 // API search type: floor_to_int_mult : (Int, Int) -> Int
7798 // fwd bind count: 1
7799 // Rounds an integer down to the nearest smaller or equal multiple of n.
7800 // n may not be zero.
7801 template <typename X>
floor_to_int_mult(X n,X x)7802 X floor_to_int_mult(X n, X x)
7803 {
7804 static_assert(std::is_integral<X>::value, "type must be integral");
7805 assert(n != 0);
7806 if (is_negative(n))
7807 n = abs(n);
7808 if (is_negative(x) && n != 1)
7809 x = static_cast<X>(x - 1);
7810 return static_cast<X>((x / n) * n);
7811 }
7812
7813 // API search type: ceil_to_int_mult : (Int, Int) -> Int
7814 // fwd bind count: 1
7815 // Rounds an integer up to the nearest greater or equal multiple of n.
7816 // n may not be zero.
7817 template <typename X>
ceil_to_int_mult(X n,X x)7818 X ceil_to_int_mult(X n, X x)
7819 {
7820 return floor_to_int_mult(n, static_cast<X>(x + abs(n) - 1));
7821 }
7822
7823 // API search type: ceil : a -> b
7824 // fwd bind count: 0
7825 // Converts a value to the nearest greater integer.
7826 template <typename X, typename Out = int>
ceil(X x)7827 Out ceil(X x)
7828 {
7829 static_assert(!std::is_integral<X>::value, "type must be non-integral");
7830 static_assert(std::is_integral<Out>::value, "type must be integral");
7831 return floor<X, Out>(x) + 1;
7832 }
7833
7834 // API search type: int_power : (Int, Int) -> Int
7835 // fwd bind count: 1
7836 // integer power, only exponents >= 0
7837 template <typename X>
int_power(X base,X exp)7838 X int_power(X base, X exp)
7839 {
7840 static_assert(std::is_integral<X>::value,
7841 "type must be unsigned integral");
7842 assert(!is_negative(exp));
7843 if (exp == 0)
7844 return 1;
7845 if (exp == 1)
7846 return base;
7847 return base * int_power(base, exp - 1);
7848 }
7849
7850 namespace internal
7851 {
7852 // minimum of x values after transformation
7853 // (has an overload for non-POD types)
7854 // min_on(mod2, 4, 3) == 4
7855 // min_on(mod7, 3, 5, 7, 3) == 7
7856 template <typename F, typename FirstT, typename... FIn>
helper_min_on(F f,const FirstT & first,const FIn &...v)7857 auto helper_min_on(F f, const FirstT& first, const FIn&... v) ->
7858 typename std::common_type<FirstT, FIn...>::type
7859 {
7860 using rettype = typename std::common_type<FirstT, FIn...>::type;
7861 using f_rettype = std::decay_t<internal::invoke_result_t<F, decltype(first)>>;
7862
7863 rettype result = first;
7864 f_rettype result_trans = internal::invoke(f, first);
7865 f_rettype v_trans;
7866 unused(result_trans);
7867 unused(v_trans);
7868
7869 (void)std::initializer_list<int>{
7870 ((v_trans = internal::invoke(f, v), v_trans < result_trans)
7871 ? (result = static_cast<rettype>(v), result_trans = v_trans, 0)
7872 : 0)...};
7873 return result;
7874 }
7875
7876 template <typename F>
7877 struct helper_min_on_t
7878 {
helper_min_on_tfplus::internal::helper_min_on_t7879 helper_min_on_t(F _f) : f(_f) {}
7880 template <typename T, typename... Ts>
operator ()fplus::internal::helper_min_on_t7881 auto operator()(T&& x, Ts&&... xs) -> typename std::common_type<T, Ts...>::type
7882 {
7883 return helper_min_on(std::forward<F>(f), std::forward<T>(x), std::forward<Ts>(xs)...);
7884 }
7885 private:
7886 F f;
7887 };
7888 }
7889
7890 // API search type: min_on : ((a -> b), a, a) -> a
7891 // minimum of x values after transformation (curried version)
7892 // min_on(mod2)(4, 3) == 4
7893 // min_on(mod7)(3, 5, 7, 3) == 7
7894 template <typename F>
min_on(F f)7895 auto min_on(F f) -> internal::helper_min_on_t<F>
7896 {
7897 return internal::helper_min_on_t<F>{f};
7898 }
7899
7900 // API search type: min_2_on : ((a -> b), a, a) -> a
7901 // fwd bind count: 2
7902 // minimum of 2 values after transformation
7903 // min_2_on(mod2, 4, 3) == 4
7904 template <typename F, typename T>
min_2_on(F f,const T & x,const T & y)7905 T min_2_on(F f, const T& x, const T& y)
7906 {
7907 return internal::invoke(f, y) < internal::invoke(f, x) ? y : x;
7908 }
7909
7910 namespace internal
7911 {
7912 // maximum of x values after transformation
7913 // (has an overload for non-POD types)
7914 // max_on(mod2, 4, 3) == 3
7915 // max_on(mod7, 3, 5, 7, 3) == 5
7916 template <typename F, typename FirstT, typename... FIn>
helper_max_on(F f,const FirstT & first,const FIn &...v)7917 auto helper_max_on(F f, const FirstT& first, const FIn&... v) ->
7918 typename std::common_type<FirstT, FIn...>::type
7919 {
7920 using rettype = typename std::common_type<FirstT, FIn...>::type;
7921 using f_rettype = decltype(f(first));
7922
7923 rettype result = first;
7924 f_rettype result_trans = internal::invoke(f, first);
7925 f_rettype v_trans;
7926 unused(result_trans);
7927 unused(v_trans);
7928
7929 (void)std::initializer_list<int>{
7930 ((v_trans = internal::invoke(f, v), v_trans > result_trans)
7931 ? (result = static_cast<rettype>(v), result_trans = v_trans, 0)
7932 : 0)...};
7933 return result;
7934 }
7935
7936 template <typename F>
7937 struct helper_max_on_t
7938 {
helper_max_on_tfplus::internal::helper_max_on_t7939 helper_max_on_t(F _f) : f(_f) {}
7940 template <typename T, typename... Ts>
operator ()fplus::internal::helper_max_on_t7941 auto operator()(T&& x, Ts&&... xs) -> typename std::common_type<T, Ts...>::type
7942 {
7943 return helper_max_on(std::forward<F>(f), std::forward<T>(x), std::forward<Ts>(xs)...);
7944 }
7945 private:
7946 F f;
7947 };
7948 }
7949
7950 // API search type: max_on : (a -> b) -> ((a, a) -> a)
7951 // maximum of x values after transformation (curried version)
7952 // (has an overload for non POD types)
7953 // max_on(mod2)(4, 3) == 3
7954 // max_on(mod7)(3, 5, 7, 3) == 5
7955 template <typename F>
max_on(F f)7956 auto max_on(F f) -> internal::helper_max_on_t<F>
7957 {
7958 return internal::helper_max_on_t<F>{f};
7959 }
7960
7961 // API search type: max_2_on : ((a -> b), a, a) -> a
7962 // fwd bind count: 2
7963 // maximum of 2 values after transformation
7964 // max_2_on(mod2, 4, 3) == 3
7965 template <typename F, typename T>
max_2_on(F f,const T & x,const T & y)7966 T max_2_on(F f, const T& x, const T& y)
7967 {
7968 return internal::invoke(f, y) > internal::invoke(f, x) ? y : x;
7969 }
7970
7971 // API search type: min : (a, a) -> a
7972 // Minimum of x number of values
7973 // min(4, 3) == 3
7974 // min(4, 3, 6, 2, 3) == 2
7975 template <typename U, typename... V>
min(const U & u,const V &...v)7976 auto min(const U& u, const V&... v) -> typename std::common_type<U, V...>::type
7977 {
7978 using rettype = typename std::common_type<U, V...>::type;
7979 rettype result = static_cast<rettype>(u);
7980 (void)std::initializer_list<int>{((v < result) ? (result = static_cast<rettype>(v), 0) : 0)...};
7981 return result;
7982 }
7983
7984 // API search type: min_2 : (a, a) -> a
7985 // fwd bind count: 1
7986 // minimum of 2 values
7987 // min_2(4, 3) == 3
7988 template <typename T>
min_2(const T & x,const T & y)7989 T min_2(const T& x, const T& y)
7990 {
7991 return y < x ? y : x;
7992 }
7993
7994 // API search type: max : (a, a) -> a
7995 // Maximum of x number of values.
7996 // max(4, 3) == 4
7997 // max(4, 3, 6, 2, 3) == 6
7998 template <typename U, typename... V>
max(const U & u,const V &...v)7999 auto max(const U& u, const V&... v) -> typename std::common_type<U, V...>::type
8000 {
8001 using rettype = typename std::common_type<U, V...>::type;
8002 rettype result = static_cast<rettype>(u);
8003 (void)std::initializer_list<int>{((v > result) ? (result = static_cast<rettype>(v), 0) : 0)...};
8004 return result;
8005 }
8006
8007 // API search type: max_2 : (a, a) -> a
8008 // fwd bind count: 1
8009 // maximum of 2 values
8010 // max_2(4, 3) == 4
8011 template <typename T>
max_2(const T & x,const T & y)8012 T max_2(const T& x, const T& y)
8013 {
8014 return y > x ? y : x;
8015 }
8016
8017 namespace internal
8018 {
8019 template <typename X>
8020 typename std::enable_if<std::is_floating_point<X>::value, X>::type
cyclic_value_helper_mod(X x,X y)8021 cyclic_value_helper_mod(X x, X y)
8022 {
8023 return std::fmod(x, y);
8024 }
8025
8026 template <typename X>
8027 typename std::enable_if<std::is_integral<X>::value, X>::type
cyclic_value_helper_mod(X x,X y)8028 cyclic_value_helper_mod(X x, X y)
8029 {
8030 return x % y;
8031 }
8032 }
8033
8034 // API search type: cyclic_value : a -> (a -> a)
8035 // Modulo for floating point values.
8036 // circumfence must be > 0
8037 // cyclic_value(8)(3) == 3
8038 // cyclic_value(8)(11) == 3
8039 // cyclic_value(8)(19) == 3
8040 // cyclic_value(8)(-2) == 6
8041 // cyclic_value(8)(-5) == 3
8042 // cyclic_value(8)(-13) == 3
8043 // Can be useful to normalize an angle into [0, 360]
8044 // For positive values it behaves like std::fmod with flipped arguments.
8045 template <typename X>
cyclic_value(X circumfence)8046 std::function<X(X)> cyclic_value(X circumfence)
8047 {
8048 assert(circumfence > 0);
8049 return [circumfence](X x) -> X
8050 {
8051 if (sign(x) < 0)
8052 return circumfence - internal::cyclic_value_helper_mod(
8053 abs(x), abs(circumfence));
8054 else
8055 return internal::cyclic_value_helper_mod(
8056 abs(x), abs(circumfence));
8057 };
8058 }
8059
8060 // API search type: cyclic_difference : a -> ((a, a) -> a)
8061 // Returns the distance the first value has to advance forward on a circle
8062 // to reach the second value.
8063 // circumfence must be > 0
8064 // cyclic_difference(100)(5, 2) == 3
8065 // cyclic_difference(100)(2, 5) == 97
8066 // cyclic_difference(100)(3, -2) == 5
8067 // cyclic_difference(100)(-2, 3) == 95
8068 // cyclic_difference(100)(90, 10) == 80
8069 // cyclic_difference(100)(10, 90) == 20
8070 template <typename X>
cyclic_difference(X circumfence)8071 std::function<X(X, X)> cyclic_difference(X circumfence)
8072 {
8073 assert(circumfence > 0);
8074 return [circumfence](X a, X b) -> X
8075 {
8076 auto cyclic_value_f = cyclic_value(circumfence);
8077 const auto c_v_a = cyclic_value_f(a);
8078 const auto c_v_b = cyclic_value_f(b);
8079 return c_v_a > c_v_b ?
8080 c_v_a - c_v_b :
8081 circumfence + c_v_a - c_v_b;
8082 };
8083 }
8084
8085 // API search type: cyclic_shortest_difference : a -> ((a, a) -> a)
8086 // Returns displacement (shortest way) the first value has to move on a circle
8087 // to reach the second value.
8088 // circumfence must be > 0
8089 // cyclic_shortest_difference(100)(5, 2) == 3
8090 // cyclic_shortest_difference(100)(2, 5) == -3
8091 // cyclic_shortest_difference(100)(3, -2) == 5
8092 // cyclic_shortest_difference(100)(-2, 3) == -5
8093 // cyclic_shortest_difference(100)(90, 10) == -20
8094 // cyclic_shortest_difference(100)(10, 90) == 20
8095 template <typename X>
cyclic_shortest_difference(X circumfence)8096 std::function<X(X, X)> cyclic_shortest_difference(X circumfence)
8097 {
8098 assert(circumfence > 0);
8099 return [circumfence](X a, X b) -> X
8100 {
8101 auto diff_func = cyclic_difference(circumfence);
8102 auto a_minus_b = diff_func(a, b);
8103 auto b_minus_a = diff_func(b, a);
8104 return a_minus_b <= b_minus_a ? a_minus_b : -b_minus_a;
8105 };
8106 }
8107
8108 // API search type: cyclic_distance : a -> ((a, a) -> a)
8109 // Returns distance (shortest way) the first value has to move on a circle
8110 // to reach the second value.
8111 // circumfence must be > 0
8112 // cyclic_distance(100)(2, 5) == 3
8113 // cyclic_distance(100)(5, 2) == 3
8114 // cyclic_distance(100)(-2, 3) == 5
8115 // cyclic_distance(100)(3, -2) == 5
8116 // cyclic_distance(100)(10, 90) == 20
8117 // cyclic_distance(100)(90, 10) == 20
8118 // Can be useful to calculate the difference of two angles;
8119 template <typename X>
cyclic_distance(X circumfence)8120 std::function<X(X, X)> cyclic_distance(X circumfence)
8121 {
8122 assert(circumfence > 0);
8123 return [circumfence](X a, X b) -> X
8124 {
8125 auto diff_func = cyclic_difference(circumfence);
8126 auto a_minus_b = diff_func(a, b);
8127 auto b_minus_a = diff_func(b, a);
8128 return a_minus_b <= b_minus_a ? a_minus_b : b_minus_a;
8129 };
8130 }
8131
8132 // API search type: pi : () -> Float
8133 // Pi.
pi()8134 constexpr inline double pi()
8135 {
8136 return 3.14159265358979323846;
8137 }
8138
8139 // API search type: deg_to_rad : Float -> Float
8140 // fwd bind count: 0
8141 // converts degrees to radians
8142 template <typename T>
deg_to_rad(T x)8143 T deg_to_rad(T x)
8144 {
8145 static_assert(std::is_floating_point<T>::value, "Please use a floating-point type.");
8146 return static_cast<T>(x * pi() / 180.0);
8147 }
8148
8149 // API search type: rad_to_deg : Float -> Float
8150 // fwd bind count: 0
8151 // converts radians to degrees
8152 template <typename T>
rad_to_deg(T x)8153 T rad_to_deg(T x)
8154 {
8155 static_assert(std::is_floating_point<T>::value, "Please use a floating-point type.");
8156 return static_cast<T>(x * 180.0 / pi());
8157 }
8158
8159 namespace internal
8160 {
8161
8162 template <typename Container, typename T>
8163 Container normalize_min_max(internal::reuse_container_t,
8164 const T& lower, const T& upper, Container&& xs)
8165 {
8166 assert(size_of_cont(xs) != 0);
8167 assert(lower <= upper);
8168 const auto minmax_it_p = std::minmax_element(std::begin(xs), std::end(xs));
8169 const T x_min = *minmax_it_p.first;
8170 const T x_max = *minmax_it_p.second;
8171 const auto f = [&](const T& x) -> T
__anon1e7ca4c43c02(const T& x) 8172 {
8173 return lower + (upper - lower) * (x - x_min) / (x_max - x_min);
8174 };
8175 std::transform(std::begin(xs), std::end(xs), std::begin(xs), f);
8176 return std::forward<Container>(xs);
8177 }
8178
8179 template <typename Container, typename T>
8180 Container normalize_min_max(internal::create_new_container_t,
8181 const T& lower, const T& upper, const Container& xs)
8182 {
8183 auto ys = xs;
8184 return normalize_min_max(internal::reuse_container_t(),
8185 lower, upper, std::move(ys));
8186 }
8187
8188 } // namespace internal
8189
8190 // API search type: normalize_min_max : (a, a, [a]) -> [a]
8191 // fwd bind count: 2
8192 // Linearly scales the values into the given interval.
8193 // normalize_min_max(0, 10, [1, 3, 6]) == [0, 4, 10]
8194 // It is recommended to convert integers to double beforehand.
8195 template <typename Container,
8196 typename T = typename internal::remove_const_and_ref_t<Container>::value_type>
normalize_min_max(const T & lower,const T & upper,Container && xs)8197 auto normalize_min_max(const T& lower, const T& upper, Container&& xs)
8198 {
8199 return internal::normalize_min_max(internal::can_reuse_v<Container>{},
8200 lower, upper, std::forward<Container>(xs));
8201 }
8202
8203 namespace internal
8204 {
8205
8206 template <typename Container, typename T>
8207 Container normalize_mean_stddev(internal::reuse_container_t,
8208 const T& mean, const T& stddev, Container&& xs)
8209 {
8210 assert(size_of_cont(xs) != 0);
8211 const auto mean_and_stddev = fplus::mean_stddev<T>(xs);
8212 const auto f = [&](const T& x) -> T
__anon1e7ca4c43d02(const T& x) 8213 {
8214 return mean +
8215 stddev * (x - mean_and_stddev.first) / mean_and_stddev.second;
8216 };
8217 std::transform(std::begin(xs), std::end(xs), std::begin(xs), f);
8218 return std::forward<Container>(xs);
8219 }
8220
8221 template <typename Container, typename T>
8222 Container normalize_mean_stddev(internal::create_new_container_t,
8223 const T& mean, const T& stddev, const Container& xs)
8224 {
8225 auto ys = xs;
8226 return normalize_mean_stddev(internal::reuse_container_t(),
8227 mean, stddev, std::move(ys));
8228 }
8229
8230 } // namespace internal
8231
8232 // API search type: normalize_mean_stddev : (a, a, [a]) -> [a]
8233 // fwd bind count: 2
8234 // Linearly scales the values
8235 // to match the given mean and population standard deviation.
8236 // normalize_mean_stddev(3, 2, [7, 8]) == [1, 5]
8237 template <typename Container,
8238 typename T = typename internal::remove_const_and_ref_t<Container>::value_type>
normalize_mean_stddev(const T & mean,const T & stddev,Container && xs)8239 auto normalize_mean_stddev(
8240 const T& mean, const T& stddev, Container&& xs)
8241 {
8242 return internal::normalize_mean_stddev(internal::can_reuse_v<Container>{},
8243 mean, stddev, std::forward<Container>(xs));
8244 }
8245
8246 // API search type: standardize : [a] -> [a]
8247 // fwd bind count: 0
8248 // Linearly scales the values to zero mean and population standard deviation 1.
8249 // standardize([7, 8]) == [-1, 1]
8250 template <typename Container>
standardize(Container && xs)8251 auto standardize(Container&& xs)
8252 {
8253 typedef typename internal::remove_const_and_ref_t<Container>::value_type T;
8254 T mean(0);
8255 T stddev(1);
8256 return normalize_mean_stddev(mean, stddev, std::forward<Container>(xs));
8257 }
8258
8259 // API search type: add_to : a -> (a -> a)
8260 // Provide a function adding to a given constant.
8261 // add_to(3)(2) == 5
8262 template <typename X>
add_to(const X & x)8263 std::function<X(X)> add_to(const X& x)
8264 {
8265 return [x](X y) -> X
8266 {
8267 return x + y;
8268 };
8269 }
8270
8271 // API search type: subtract_from : a -> (a -> a)
8272 // Provide a function subtracting from a given constant.
8273 // subtract_from(3)(2) == 1
8274 template <typename X>
subtract_from(const X & x)8275 std::function<X(X)> subtract_from(const X& x)
8276 {
8277 return [x](X y) -> X
8278 {
8279 return x - y;
8280 };
8281 }
8282
8283 // API search type: subtract : a -> (a -> a)
8284 // Provide a function subtracting a given constant.
8285 // subtract(2)(3) == 1
8286 template <typename X>
subtract(const X & x)8287 std::function<X(X)> subtract(const X& x)
8288 {
8289 return [x](X y) -> X
8290 {
8291 return y - x;
8292 };
8293 }
8294
8295 // API search type: multiply_with : a -> (a -> a)
8296 // Provide a function multiplying with a given constant.
8297 // multiply_with(3)(2) == 6
8298 template <typename X>
multiply_with(const X & x)8299 std::function<X(X)> multiply_with(const X& x)
8300 {
8301 return [x](X y) -> X
8302 {
8303 return y * x;
8304 };
8305 }
8306
8307 // API search type: divide_by : a -> (a -> a)
8308 // Provide a function dividing by a given constant.
8309 // divide_by(2)(6) == 3
8310 template <typename X>
divide_by(const X & x)8311 std::function<X(X)> divide_by(const X& x)
8312 {
8313 return [x](X y) -> X
8314 {
8315 return y / x;
8316 };
8317 }
8318
8319 // API search type: histogram_using_intervals : ([(a, a)], [a]) -> [((a, a), Int)]
8320 // fwd bind count: 1
8321 // Generate a histogram of a sequence with given bins.
8322 // histogram_using_intervals([(0,4), (4,5), (6,8)], [0,1,4,5,6,7,8,9]) ==
8323 // [((0, 4), 2), ((4, 5), 1), ((6, 8), 2)]
8324 template <typename ContainerIn,
8325 typename ContainerIntervals,
8326 typename ContainerOut =
8327 std::vector<
8328 std::pair<
8329 typename ContainerIntervals::value_type,
8330 std::size_t>>,
8331 typename T = typename ContainerIn::value_type>
8332 ContainerOut histogram_using_intervals(
8333 const ContainerIntervals& intervals, const ContainerIn& xs)
8334 {
8335 ContainerOut bins;
8336 internal::prepare_container(bins, size_of_cont(intervals));
8337 auto itOut = internal::get_back_inserter(bins);
8338 for (const auto& interval : intervals)
8339 {
8340 *itOut = std::make_pair(interval, 0);
8341 }
8342 for (const auto& x : xs)
8343 {
8344 for (auto& bin : bins)
8345 {
8346 if (x >= bin.first.first && x < bin.first.second)
8347 {
8348 ++bin.second;
8349 }
8350 }
8351 }
8352 return bins;
8353 }
8354
8355 // API search type: generate_consecutive_intervals : (a, a, a) -> [(a, a)]
8356 // fwd bind count: 2
8357 // Return intervals of a given size adjacent to each other
8358 // generate_consecutive_intervals(0, 2, 4) == [(0,2), (2,4), (4,6), (6,8)]
8359 template <typename T>
generate_consecutive_intervals(const T & first_lower_bound,const T & step,std::size_t count)8360 std::vector<std::pair<T, T>> generate_consecutive_intervals(
8361 const T& first_lower_bound, const T& step, std::size_t count)
8362 {
8363 const auto count_as_T = static_cast<T>(count);
8364 return zip(
8365 numbers_step<T>(
8366 first_lower_bound,
8367 first_lower_bound + count_as_T * step,
8368 step),
8369 numbers_step<T>(
8370 first_lower_bound + step,
8371 first_lower_bound + step + count_as_T * step,
8372 step));
8373 }
8374
8375 // API search type: histogram : (a, a, a, [a]) -> [((a, a), Int)]
8376 // fwd bind count: 3
8377 // Calculate the histogram of a sequence using a given bin width.
8378 // histogram(1, 2, 4, [0,1,4,5,7,8,9]) == [(1, 2), (3, 0), (5, 2), (7, 1)]
8379 template <typename ContainerIn,
8380 typename ContainerOut =
8381 std::vector<
8382 std::pair<
8383 typename ContainerIn::value_type,
8384 std::size_t>>,
8385 typename T = typename ContainerIn::value_type>
8386 ContainerOut histogram(
8387 const T& first_center, const T& bin_width, std::size_t count,
8388 const ContainerIn& xs)
8389 {
8390 const auto interval_histogram = histogram_using_intervals(
8391 generate_consecutive_intervals(
8392 first_center - bin_width / 2,
8393 bin_width,
8394 count),
8395 xs);
8396
8397 assert(size_of_cont(interval_histogram) == count);
8398
8399 ContainerOut histo;
8400 internal::prepare_container(histo, count);
8401 auto itOut = internal::get_back_inserter(histo);
8402 for (const auto& bin : interval_histogram)
8403 {
8404 const auto current_center = (bin.first.first + bin.first.second) / 2;
8405 *itOut = std::make_pair(current_center, bin.second);
8406 }
8407 return histo;
8408 }
8409
8410 // API search type: modulo_chain : ([Int], Int) -> [Int]
8411 // fwd bind count: 1
8412 // For every factor (value % factor) is pushed into the result,
8413 // and value is divided by this factor for the next iteration.
8414 // Can be useful to convert a time in seconds
8415 // into hours, minutes and seconds and similar calculations.
8416 // modulo_chain([24, 60, 60], 7223) == [0, 2, 0, 23]
8417 template <typename T>
modulo_chain(const std::vector<T> & factors,T val)8418 std::vector<T> modulo_chain(const std::vector<T>& factors, T val)
8419 {
8420 std::vector<T> result;
8421 result.reserve(factors.size());
8422 const auto factors_reversed = reverse(factors);
8423 for (const auto& factor : factors_reversed)
8424 {
8425 result.push_back(val % factor);
8426 val /= factor;
8427 }
8428 result.push_back(val);
8429 return reverse(result);
8430 }
8431
8432 // API search type: line_equation : ((Float, Float), (Float, Float), Float) -> Float
8433 // fwd bind count: 2
8434 // Can be used to interpolate and to extrapolate
8435 // based on two given two-dimensional points (x, y).
8436 // Using slope, return NaN if x_1 == x_2.
8437 // line_equation((0.0, 0.0), (2.0, 1.0), 3.0) == 1.5
8438 // line_equation((-1.0, 1.0), (-2.0, 4.0), 0.0) == -2.0
8439 template <typename T>
line_equation(const std::pair<T,T> & a,const std::pair<T,T> & b,T x)8440 T line_equation(const std::pair<T, T>& a, const std::pair<T, T>& b, T x)
8441 {
8442 static_assert(std::is_floating_point<T>::value, "Please use a floating-point type.");
8443 const double m = (b.second - a.second) / (b.first - a.first);
8444 return m * x + a.second - m * a.first;
8445 }
8446
8447 } // namespace fplus
8448
8449 //
8450 // search.hpp
8451 //
8452
8453 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
8454 // https://github.com/Dobiasd/FunctionalPlus
8455 // Distributed under the Boost Software License, Version 1.0.
8456 // (See accompanying file LICENSE_1_0.txt or copy at
8457 // http://www.boost.org/LICENSE_1_0.txt)
8458
8459
8460
8461 #include <algorithm>
8462
8463 namespace fplus
8464 {
8465
8466 // API search type: find_first_by : ((a -> Bool), [a]) -> Maybe a
8467 // fwd bind count: 1
8468 // Returns the first element fulfilling the predicate.
8469 // find_first_by(is_even, [1, 3, 4, 6, 9]) == Just(4)
8470 // find_first_by(is_even, [1, 3, 5, 7, 9]) == Nothing
8471 template <typename Container, typename UnaryPredicate,
8472 typename T = typename Container::value_type>
find_first_by(UnaryPredicate pred,const Container & xs)8473 maybe<T> find_first_by(UnaryPredicate pred, const Container& xs)
8474 {
8475 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8476 auto it = std::find_if(std::begin(xs), std::end(xs), pred);
8477 if (it == std::end(xs))
8478 return nothing<T>();
8479 return just<T>(*it);
8480 }
8481
8482 // API search type: find_last_by : ((a -> Bool), [a]) -> Maybe a
8483 // fwd bind count: 1
8484 // Returns the last element fulfilling the predicate.
8485 // find_last_by(is_even, [1, 3, 4, 6, 9]) == Just(6)
8486 // find_last_by(is_even, [1, 3, 5, 7, 9]) == Nothing
8487 template <typename Container, typename UnaryPredicate,
8488 typename T = typename Container::value_type>
find_last_by(UnaryPredicate pred,const Container & xs)8489 maybe<T> find_last_by(UnaryPredicate pred, const Container& xs)
8490 {
8491 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8492 return find_first_by(pred, reverse(xs));
8493 }
8494
8495 // API search type: find_first_idx_by : ((a -> Bool), [a]) -> Maybe Int
8496 // fwd bind count: 1
8497 // Returns the index of the first element fulfilling the predicate.
8498 // find_first_idx_by(is_even, [1, 3, 4, 6, 9]) == Just(2)
8499 // find_first_idx_by(is_even, [1, 3, 5, 7, 9]) == Nothing
8500 template <typename Container, typename UnaryPredicate>
find_first_idx_by(UnaryPredicate pred,const Container & xs)8501 maybe<std::size_t> find_first_idx_by
8502 (UnaryPredicate pred, const Container& xs)
8503 {
8504 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8505 auto it = std::find_if(std::begin(xs), std::end(xs), pred);
8506 if (it == std::end(xs))
8507 return nothing<std::size_t>();
8508 return static_cast<std::size_t>(std::distance(std::begin(xs), it));
8509 }
8510
8511 // API search type: find_last_idx_by : ((a -> Bool), [a]) -> Maybe Int
8512 // fwd bind count: 1
8513 // Returns the index of the last element fulfilling the predicate.
8514 // find_last_idx_by(is_even, [1, 3, 4, 6, 9]) == Just(3)
8515 // find_last_idx_by(is_even, [1, 3, 5, 7, 9]) == Nothing
8516 template <typename Container, typename UnaryPredicate>
find_last_idx_by(UnaryPredicate pred,const Container & xs)8517 maybe<std::size_t> find_last_idx_by
8518 (UnaryPredicate pred, const Container& xs)
8519 {
8520 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8521 auto calcRevIdx = [&](std::size_t idx)
8522 {
8523 return size_of_cont(xs) - (idx + 1);
8524 };
8525 return lift_maybe(calcRevIdx, find_first_idx_by(pred, reverse(xs)));
8526 }
8527
8528 // API search type: find_first_idx : (a, [a]) -> Maybe Int
8529 // fwd bind count: 1
8530 // Returns the index of the first element equal to x.
8531 // find_first_idx(4, [1, 3, 4, 4, 9]) == Just(2)
8532 // find_first_idx(4, [1, 3, 5, 7, 9]) == Nothing
8533 template <typename Container>
find_first_idx(const typename Container::value_type & x,const Container & xs)8534 maybe<std::size_t> find_first_idx
8535 (const typename Container::value_type& x, const Container& xs)
8536 {
8537 return find_first_idx_by(is_equal_to(x), xs);
8538 }
8539
8540 // API search type: find_last_idx : (a, [a]) -> Maybe Int
8541 // fwd bind count: 1
8542 // Returns the index of the last element equal to x.
8543 // find_last_idx(4, [1, 3, 4, 4, 9]) == Just(3)
8544 // find_last_idx(4, [1, 3, 5, 7, 9]) == Nothing
8545 template <typename Container>
find_last_idx(const typename Container::value_type & x,const Container & xs)8546 maybe<std::size_t> find_last_idx
8547 (const typename Container::value_type& x, const Container& xs)
8548 {
8549 return find_last_idx_by(is_equal_to(x), xs);
8550 }
8551
8552 // API search type: find_all_idxs_by : ((a -> Bool), [a]) -> [Int]
8553 // fwd bind count: 1
8554 // Returns the indices off all elements fulfilling the predicate.
8555 // find_all_idxs_by(is_even, [1, 3, 4, 6, 9]) == [2, 3]
8556 template <typename ContainerOut = std::vector<std::size_t>,
8557 typename UnaryPredicate, typename Container>
8558 ContainerOut find_all_idxs_by(UnaryPredicate p, const Container& xs)
8559 {
8560 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8561 std::size_t idx = 0;
8562 ContainerOut result;
8563 auto itOut = internal::get_back_inserter(result);
8564 for (const auto& x : xs)
8565 {
8566 if (internal::invoke(p, x))
8567 *itOut = idx;
8568 ++idx;
8569 }
8570 return result;
8571 }
8572
8573 // API search type: find_all_idxs_of : (a, [a]) -> [Int]
8574 // fwd bind count: 1
8575 // Returns the indices off all elements equal to x.
8576 // find_all_idxs_of(4, [1, 3, 4, 4, 9]) == [2, 3]
8577 template <typename ContainerOut = std::vector<std::size_t>,
8578 typename Container,
8579 typename T = typename Container::value_type>
8580 ContainerOut find_all_idxs_of
8581 (const T& x, const Container& xs)
8582 {
8583 return find_all_idxs_by(is_equal_to(x), xs);
8584 }
8585
8586 // API search type: find_all_instances_of_token : ([a], [a]) -> [Int]
8587 // fwd bind count: 1
8588 // Returns the starting indices of all segments matching token.
8589 // find_all_instances_of_token("haha", "oh, hahaha!") == [4, 6]
8590 template <typename ContainerOut =
8591 std::vector<std::size_t>, typename Container>
8592 ContainerOut find_all_instances_of_token(const Container& token,
8593 const Container& xs)
8594 {
8595 if (size_of_cont(token) > size_of_cont(xs))
8596 return ContainerOut();
8597
8598 auto itInBegin = std::begin(xs);
8599 auto itInEnd = itInBegin;
8600 internal::advance_iterator(itInEnd, size_of_cont(token));
8601 std::size_t idx = 0;
8602 ContainerOut result;
8603 auto outIt = internal::get_back_inserter(result);
8604 std::size_t last_possible_idx = size_of_cont(xs) - size_of_cont(token);
8605 auto check_and_push = [&]()
__anon1e7ca4c44402() 8606 {
8607 if (std::equal(itInBegin, itInEnd, std::begin(token)))
8608 {
8609 *outIt = idx;
8610 }
8611 };
8612 while (idx != last_possible_idx)
8613 {
8614 check_and_push();
8615 ++itInBegin;
8616 ++itInEnd;
8617 ++idx;
8618 }
8619 check_and_push();
8620 return result;
8621 }
8622
8623 // API search type: find_all_instances_of_token_non_overlapping : ([a], [a]) -> [Int]
8624 // fwd bind count: 1
8625 // Returns the starting indices
8626 // of all non-overlapping segments matching token.
8627 // find_all_instances_of_token_non_overlapping("haha", "oh, hahaha!") == [4]
8628 template <typename ContainerOut = std::vector<std::size_t>, typename Container>
8629 ContainerOut find_all_instances_of_token_non_overlapping
8630 (const Container& token, const Container& xs)
8631 {
8632 auto overlapping_instances = find_all_instances_of_token<ContainerOut>(
8633 token, xs);
8634 ContainerOut result;
8635 auto outIt = internal::get_back_inserter(result);
8636 std::size_t token_size = size_of_cont(token);
8637 for (const auto idx : overlapping_instances)
8638 {
8639 if (result.empty() || result.back() + token_size <= idx)
8640 {
8641 *outIt = idx;
8642 }
8643 }
8644 return result;
8645 }
8646
8647 // API search type: find_first_instance_of_token : ([a], [a]) -> Maybe Int
8648 // fwd bind count: 1
8649 // Returns the index of the first segment matching token.
8650 // find_first_instance_of_token("haha", "oh, hahaha!") == just 4
8651 template <typename Container>
find_first_instance_of_token(const Container & token,const Container & xs)8652 maybe<std::size_t> find_first_instance_of_token
8653 (const Container& token, const Container& xs)
8654 {
8655 if (size_of_cont(token) > size_of_cont(xs))
8656 return nothing<std::size_t>();
8657
8658 auto itInBegin = std::begin(xs);
8659 auto itInEnd = itInBegin;
8660 internal::advance_iterator(itInEnd, size_of_cont(token));
8661 std::size_t idx = 0;
8662 std::size_t last_possible_idx = size_of_cont(xs) - size_of_cont(token);
8663 while (idx != last_possible_idx)
8664 {
8665 if (std::equal(itInBegin, itInEnd, std::begin(token)))
8666 {
8667 return just(idx);
8668 }
8669 ++itInBegin;
8670 ++itInEnd;
8671 ++idx;
8672 }
8673 if (std::equal(itInBegin, itInEnd, std::begin(token)))
8674 {
8675 return just(idx);
8676 }
8677 return nothing<std::size_t>();
8678 }
8679
8680 } // namespace fplus
8681
8682 //
8683 // sets.hpp
8684 //
8685
8686 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
8687 // https://github.com/Dobiasd/FunctionalPlus
8688 // Distributed under the Boost Software License, Version 1.0.
8689 // (See accompanying file LICENSE_1_0.txt or copy at
8690 // http://www.boost.org/LICENSE_1_0.txt)
8691
8692
8693
8694 #include <algorithm>
8695 #include <set>
8696 #include <unordered_set>
8697
8698 namespace fplus
8699 {
8700
8701 // API search type: set_includes : (Set a, Set a) -> Bool
8702 // fwd bind count: 1
8703 // Checks if every element of the second set is also present in the first set.
8704 // Also known as is_subset_of.
8705 template <typename SetType>
set_includes(const SetType & set1,const SetType & set2)8706 bool set_includes(const SetType& set1, const SetType& set2)
8707 {
8708 return std::includes(std::begin(set1), std::end(set1),
8709 std::begin(set2), std::end(set2));
8710 }
8711
8712 // API search type: unordered_set_includes : (Unordered_Set a, Unordered_Set a) -> Bool
8713 // fwd bind count: 1
8714 // Checks if every element of the second unordered_set
8715 // is also present in the first unordered_set.
8716 // Also known as is_subset_of.
8717 template <typename UnorderSetType>
unordered_set_includes(const UnorderSetType & set1,const UnorderSetType & set2)8718 bool unordered_set_includes(const UnorderSetType& set1,
8719 const UnorderSetType& set2)
8720 {
8721 auto first_not_included = std::find_if(set2.begin(), set2.end(),
8722 [&](const typename UnorderSetType::value_type& x)
8723 -> bool { return set1.find(x) == set1.end();});
8724 return first_not_included == set2.end();
8725 }
8726
8727 // API search type: set_merge : (Set a, Set a) -> Set a
8728 // fwd bind count: 1
8729 // Returns the union of two given sets.
8730 template <typename SetType>
set_merge(const SetType & set1,const SetType & set2)8731 SetType set_merge(const SetType& set1, const SetType& set2)
8732 {
8733 SetType result;
8734 auto itOut = internal::get_back_inserter(result);
8735 std::merge(std::begin(set1), std::end(set1),
8736 std::begin(set2), std::end(set2),
8737 itOut);
8738 return result;
8739 }
8740
8741 // API search type: unordered_set_merge : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
8742 // fwd bind count: 1
8743 // Returns the union of two given sets.
8744 template <typename UnorderSetType>
unordered_set_merge(const UnorderSetType & set1,const UnorderSetType & set2)8745 UnorderSetType unordered_set_merge(const UnorderSetType& set1, const UnorderSetType& set2)
8746 {
8747 UnorderSetType result;
8748 auto itOut = internal::get_back_inserter(result);
8749 std::copy(std::begin(set1), std::end(set1), itOut);
8750 std::copy(std::begin(set2), std::end(set2), itOut);
8751 return result;
8752 }
8753
8754 // API search type: set_intersection : (Set a, Set a) -> Set a
8755 // fwd bind count: 1
8756 // Returns the intersection of both sets.
8757 template <typename SetType>
set_intersection(const SetType & set1,const SetType & set2)8758 SetType set_intersection(const SetType& set1, const SetType& set2)
8759 {
8760 SetType result;
8761 auto itOut = internal::get_back_inserter(result);
8762 std::set_intersection(std::begin(set1), std::end(set1),
8763 std::begin(set2), std::end(set2),
8764 itOut);
8765 return result;
8766 }
8767
8768 // API search type: unordered_set_intersection : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
8769 // fwd bind count: 1
8770 // Returns the intersection of both unordered_sets.
8771 template <typename UnorderSetType>
unordered_set_intersection(const UnorderSetType & set1,const UnorderSetType & set2)8772 UnorderSetType unordered_set_intersection(
8773 const UnorderSetType& set1, const UnorderSetType& set2)
8774 {
8775 UnorderSetType result;
8776 auto itOut = internal::get_back_inserter(result);
8777 std::copy_if(std::begin(set2), std::end(set2),
8778 itOut, [&](const typename UnorderSetType::value_type &x)
8779 -> bool {return set1.find(x) != set1.end();});
8780 return result;
8781 }
8782
8783 // API search type: set_is_disjoint : (Set a, Set a) -> Bool
8784 // fwd bind count: 1
8785 // Checks if two sets are disjoint.
8786 template <typename SetType>
set_is_disjoint(const SetType & set1,const SetType & set2)8787 bool set_is_disjoint(const SetType& set1, const SetType& set2)
8788 {
8789 return set_intersection(set1, set2).empty();
8790 }
8791
8792 // API search type: unordered_set_is_disjoint : (Unordered_Set a, Unordered_Set a) -> Bool
8793 // fwd bind count: 1
8794 // Checks if two unordered_sets are disjoint.
8795 template <typename UnorderSetType>
unordered_set_is_disjoint(const UnorderSetType & set1,const UnorderSetType & set2)8796 bool unordered_set_is_disjoint(
8797 const UnorderSetType& set1, const UnorderSetType& set2)
8798 {
8799 return unordered_set_intersection(set1, set2).empty();
8800 }
8801
8802 // API search type: set_difference : (Set a, Set a) -> Set a
8803 // fwd bind count: 1
8804 // Returns the elements in set1 that are not present in set2.
8805 template <typename SetType>
set_difference(const SetType & set1,const SetType & set2)8806 SetType set_difference(const SetType& set1, const SetType& set2)
8807 {
8808 SetType result;
8809 auto itOut = internal::get_back_inserter(result);
8810 std::set_difference(std::begin(set1), std::end(set1),
8811 std::begin(set2), std::end(set2),
8812 itOut);
8813 return result;
8814 }
8815
8816 // API search type: unordered_set_difference : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
8817 // fwd bind count: 1
8818 // Returns the elements in unordered_set1
8819 // that are not present in unordered_set2.
8820 template <typename UnorderSetType>
unordered_set_difference(const UnorderSetType & set1,const UnorderSetType & set2)8821 UnorderSetType unordered_set_difference(const UnorderSetType& set1,
8822 const UnorderSetType& set2)
8823 {
8824 UnorderSetType result;
8825 auto itOut = internal::get_back_inserter(result);
8826 std::copy_if(std::begin(set1), std::end(set1),
8827 itOut, [&](const typename UnorderSetType::value_type &x)
8828 -> bool {return set2.find(x) == set2.end();});
8829 return result;
8830 }
8831
8832 // API search type: set_symmetric_difference : (Set a, Set a) -> Set a
8833 // fwd bind count: 1
8834 // Returns the symmetric difference of both sets.
8835 template <typename SetType>
set_symmetric_difference(const SetType & set1,const SetType & set2)8836 SetType set_symmetric_difference(const SetType& set1, const SetType& set2)
8837 {
8838 SetType result;
8839 auto itOut = internal::get_back_inserter(result);
8840 std::set_symmetric_difference(std::begin(set1), std::end(set1),
8841 std::begin(set2), std::end(set2),
8842 itOut);
8843 return result;
8844 }
8845
8846 // API search type: unordered_set_symmetric_difference : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
8847 // fwd bind count: 1
8848 // Returns the symmetric difference of both unordered_sets.
8849 template <typename UnorderSetType>
unordered_set_symmetric_difference(const UnorderSetType & set1,const UnorderSetType & set2)8850 UnorderSetType unordered_set_symmetric_difference(
8851 const UnorderSetType& set1, const UnorderSetType& set2)
8852 {
8853 UnorderSetType result;
8854 auto itOut = internal::get_back_inserter(result);
8855 std::copy_if(std::begin(set1), std::end(set1),
8856 itOut, [&](const typename UnorderSetType::value_type &x)
8857 -> bool {return set2.find(x) == set2.end();});
8858 std::copy_if(std::begin(set2), std::end(set2),
8859 itOut, [&](const typename UnorderSetType::value_type &x)
8860 -> bool {return set1.find(x) == set1.end();});
8861 return result;
8862 }
8863
8864 // API search type: sets_intersection : [Set a] -> Set a
8865 // fwd bind count: 0
8866 // Returns the intersection of the given sets.
8867 // Also known as intersect_many.
8868 // For performance try to sort the inputs sets prior, ascendending by size.
8869 template <typename ContainerIn,
8870 typename SetType = typename ContainerIn::value_type>
sets_intersection(const ContainerIn & sets)8871 SetType sets_intersection(const ContainerIn& sets)
8872 {
8873 return fold_left_1(set_intersection<SetType>, sets);
8874 }
8875
8876 // API search type: unordered_sets_intersection : [Unordered_Set a] -> Unordered_Set a
8877 // fwd bind count: 0
8878 // Returns the intersection of the given unordered_sets.
8879 // Also known as intersect_many.
8880 template <typename ContainerIn,
8881 typename UnordSetType = typename ContainerIn::value_type>
unordered_sets_intersection(const ContainerIn & sets)8882 UnordSetType unordered_sets_intersection(const ContainerIn& sets)
8883 {
8884 return fold_left_1(unordered_set_intersection<UnordSetType>, sets);
8885 }
8886
8887 } // namespace fplus
8888
8889
8890 #include <algorithm>
8891 #include <numeric>
8892 #include <type_traits>
8893
8894 namespace fplus
8895 {
8896
8897 // API search type: any_by : ((a -> Bool), [a]) -> Bool
8898 // fwd bind count: 1
8899 // Check if all elements in a container fulfill a predicate.
8900 // any_by(is_odd, [2, 4, 6]) == false
8901 template <typename UnaryPredicate, typename Container>
any_by(UnaryPredicate p,const Container & xs)8902 bool any_by(UnaryPredicate p, const Container& xs)
8903 {
8904 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8905 return std::any_of(std::begin(xs), std::end(xs), p);
8906 }
8907
8908 // API search type: any : [Bool] -> Bool
8909 // fwd bind count: 0
8910 // Checks if all elements in a container are true.
8911 // any([false, true, false]) == true
8912 template <typename Container>
any(const Container & xs)8913 bool any(const Container& xs)
8914 {
8915 typedef typename Container::value_type T;
8916 return any_by(identity<T>, xs);
8917 }
8918
8919 // API search type: none_by : ((a -> Bool), [a]) -> Bool
8920 // fwd bind count: 1
8921 // Check no element in a container fulfills a predicate.
8922 // none_by(is_even, [3, 4, 5]) == false
8923 template <typename UnaryPredicate, typename Container>
none_by(UnaryPredicate p,const Container & xs)8924 bool none_by(UnaryPredicate p, const Container& xs)
8925 {
8926 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
8927 return std::none_of(std::begin(xs), std::end(xs), p);
8928 }
8929
8930 // API search type: none : [Bool] -> Bool
8931 // fwd bind count: 0
8932 // Checks if all elements in a container are false.
8933 // none([false, true, false]) == false
8934 template <typename Container>
none(const Container & xs)8935 bool none(const Container& xs)
8936 {
8937 typedef typename Container::value_type T;
8938 return none_by(identity<T>, xs);
8939 }
8940
8941
8942 // API search type: minimum_idx_by : (((a, a) -> Bool), [a]) -> Int
8943 // fwd bind count: 1
8944 // Return the index of the first minimum element using a less comparator.
8945 // minimum_idx_by(lessLength, ["123", "12", "1234", "123"]) -> "1"
8946 // Unsafe! Crashes on an empty sequence.
8947 template <typename Compare, typename Container>
minimum_idx_by(Compare comp,const Container & xs)8948 typename std::size_t minimum_idx_by(Compare comp,
8949 const Container& xs)
8950 {
8951 internal::check_compare_for_container<Compare, Container>();
8952 assert(is_not_empty(xs));
8953 return static_cast<std::size_t>(std::distance(std::begin(xs),
8954 std::min_element(std::begin(xs), std::end(xs), comp)));
8955 }
8956
8957 // API search type: minimum_idx_by_maybe : (((a, a) -> Bool), [a]) -> Int
8958 // fwd bind count: 1
8959 // Return the index of the first minimum element using a less comparator
8960 // if sequence is not empty.
8961 // minimum_idx_by_maybe(lessLength, ["123", "12", "1234", "123"]) -> Just "1"
8962 // minimum_idx_by_maybe(lessLength, []) -> Nothing
8963 template <typename Compare, typename Container>
minimum_idx_by_maybe(Compare comp,const Container & xs)8964 maybe<typename std::size_t> minimum_idx_by_maybe(Compare comp,
8965 const Container& xs)
8966 {
8967 if (is_empty(xs))
8968 return {};
8969 else
8970 return minimum_idx_by(comp, xs);
8971 }
8972
8973 // API search type: maximum_idx_by : (((a, a) -> Bool), [a]) -> Int
8974 // fwd bind count: 1
8975 // Return the index of the first maximum element using a less comparator.
8976 // maximum_idx_by(lessLength, ["123", "12", "1234", "123"]) == "2"
8977 // Unsafe! Crashes on an empty sequence.
8978 template <typename Compare, typename Container>
maximum_idx_by(Compare comp,const Container & xs)8979 typename std::size_t maximum_idx_by(Compare comp,
8980 const Container& xs)
8981 {
8982 internal::check_compare_for_container<Compare, Container>();
8983 assert(is_not_empty(xs));
8984 return static_cast<std::size_t>(std::distance(std::begin(xs),
8985 std::max_element(std::begin(xs), std::end(xs), comp)));
8986 }
8987
8988 // API search type: maximum_idx_by_maybe : (((a, a) -> Bool), [a]) -> Maybe Int
8989 // fwd bind count: 1
8990 // Return the index of the first maximum element using a less comparator
8991 // if sequence is not empty.
8992 // maximum_idx_by_maybe(lessLength, ["123", "12", "1234", "123"]) == Just "2"
8993 // maximum_idx_by_maybe(lessLength, []) == Nothing
8994 template <typename Compare, typename Container>
maximum_idx_by_maybe(Compare comp,const Container & xs)8995 maybe<typename std::size_t> maximum_idx_by_maybe(Compare comp,
8996 const Container& xs)
8997 {
8998 if (is_empty(xs))
8999 return {};
9000 else
9001 return maximum_idx_by(comp, xs);
9002 }
9003
9004
9005 // API search type: minimum_idx : [a] -> Int
9006 // fwd bind count: 0
9007 // Return the index of the first minimum element.
9008 // minimum_idx([3, 1, 4, 2]) == 1
9009 // Unsafe! Crashes on an empty sequence.
9010 template <typename Container>
minimum_idx(const Container & xs)9011 typename std::size_t minimum_idx(const Container& xs)
9012 {
9013 return minimum_idx_by(is_less<typename Container::value_type>, xs);
9014 }
9015
9016 // API search type: minimum_idx_maybe : [a] -> Maybe Int
9017 // fwd bind count: 0
9018 // Return the index of the first minimum element if sequence is not empty.
9019 // minimum_idx_maybe([3, 1, 4, 2]) == Just 1
9020 // minimum_idx_maybe([]) == Nothing
9021 template <typename Container>
minimum_idx_maybe(const Container & xs)9022 maybe<typename std::size_t> minimum_idx_maybe(const Container& xs)
9023 {
9024 if (is_empty(xs))
9025 return {};
9026 else
9027 return minimum_idx(xs);
9028 }
9029
9030 // API search type: maximum_idx : [a] -> Int
9031 // fwd bind count: 0
9032 // Return the index of the first maximum element.
9033 // maximum_idx([3, 1, 4, 2]) == 2
9034 // Unsafe! Crashes on an empty sequence.
9035 template <typename Container>
maximum_idx(const Container & xs)9036 typename std::size_t maximum_idx(const Container& xs)
9037 {
9038 return maximum_idx_by(is_less<typename Container::value_type>, xs);
9039 }
9040
9041 // API search type: maximum_idx_maybe : [a] -> Maybe Int
9042 // fwd bind count: 0
9043 // Return the index of the first maximum element if sequence is not empty.
9044 // maximum_idx_maybe([3, 1, 4, 2]) == Just 2
9045 // maximum_imaximum_idx_maybedx([]) == Nothing
9046 template <typename Container>
maximum_idx_maybe(const Container & xs)9047 maybe<typename std::size_t> maximum_idx_maybe(const Container& xs)
9048 {
9049 if (is_empty(xs))
9050 return {};
9051 else
9052 return maximum_idx(xs);
9053 }
9054
9055
9056 // API search type: minimum_idx_on : ((a -> b), [a]) -> Int
9057 // fwd bind count: 1
9058 // Return the index of the first minimum element using a transformer.
9059 // minimum_idx_on(length, ["123", "12", "1234", "123"]) -> "1"
9060 // Unsafe! Crashes on an empty sequence.
9061 template <typename F, typename Container>
minimum_idx_on(F f,const Container & xs)9062 std::size_t minimum_idx_on(F f, const Container& xs)
9063 {
9064 using Result = internal::invoke_result_t<F, typename Container::value_type>;
9065 auto transformed = transform_convert<std::vector<std::decay_t<Result>>>(f, xs);
9066 return minimum_idx(transformed);
9067 }
9068
9069 // API search type: minimum_idx_on_maybe : ((a -> b), [a]) -> Just Int
9070 // fwd bind count: 1
9071 // Return the index of the first minimum element using a transformer
9072 // if sequence is not empty.
9073 // minimum_idx_on_maybe(length, ["123", "12", "1234", "123"]) -> Just "1"
9074 // minimum_idx_on_maybe(length, []) -> Nothing"
9075 template <typename F, typename Container>
minimum_idx_on_maybe(F f,const Container & xs)9076 maybe<typename std::size_t> minimum_idx_on_maybe(F f, const Container& xs)
9077 {
9078 if (is_empty(xs))
9079 return {};
9080 else
9081 return minimum_idx_on(f, xs);
9082 }
9083
9084 // API search type: maximum_idx_on : ((a -> b), [a]) -> Int
9085 // fwd bind count: 1
9086 // Return the index of the first maximum element using a transformer.
9087 // maximum_idx_on(length, ["123", "12", "1234", "123"]) == "2"
9088 // Unsafe! Crashes on an empty sequence.
9089 template <typename F, typename Container>
maximum_idx_on(F f,const Container & xs)9090 std::size_t maximum_idx_on(F f, const Container& xs)
9091 {
9092 using Result = internal::invoke_result_t<F, typename Container::value_type>;
9093 auto transformed = transform_convert<std::vector<std::decay_t<Result>>>(f, xs);
9094 return maximum_idx(transformed);
9095 }
9096
9097 // API search type: maximum_idx_on_maybe : ((a -> b), [a]) -> Maybe Int
9098 // fwd bind count: 1
9099 // Return the index of the first maximum element using a transformer
9100 // if sequence is not empty.
9101 // maximum_idx_on_maybe(length, ["123", "12", "1234", "123"]) == Just "2"
9102 // maximum_idx_on_maybe(length, []) == Nothing
9103 template <typename F, typename Container>
maximum_idx_on_maybe(F f,const Container & xs)9104 maybe<typename std::size_t> maximum_idx_on_maybe(F f, const Container& xs)
9105 {
9106 if (is_empty(xs))
9107 return {};
9108 else
9109 return maximum_idx_on(f, xs);
9110 }
9111
9112 // API search type: minimum_by : (((a, a) -> Bool), [a]) -> a
9113 // fwd bind count: 1
9114 // Return the first minimum element using a less comparator.
9115 // minimum_by(lessLength, ["123", "12", "1234", "123"]) -> "12"
9116 // Unsafe! Crashes on an empty sequence.
9117 template <typename Compare, typename Container>
minimum_by(Compare comp,const Container & xs)9118 typename Container::value_type minimum_by(Compare comp,
9119 const Container& xs)
9120 {
9121 internal::check_compare_for_container<Compare, Container>();
9122 assert(is_not_empty(xs));
9123 return *std::min_element(std::begin(xs), std::end(xs), comp);
9124 }
9125
9126 // API search type: minimum_by_maybe : (((a, a) -> Bool), [a]) -> a
9127 // fwd bind count: 1
9128 // Return the first minimum element using a less comparator
9129 // if sequence is not empty.
9130 // minimum_by_maybe(lessLength, ["123", "12", "1234", "123"]) -> Just "12"
9131 // minimum_by_maybe(lessLength, []) -> Nothing
9132 template <typename Compare, typename Container>
minimum_by_maybe(Compare comp,const Container & xs)9133 maybe<typename Container::value_type> minimum_by_maybe(Compare comp,
9134 const Container& xs)
9135 {
9136 if (is_empty(xs))
9137 return {};
9138 else
9139 return minimum_by(comp, xs);
9140 }
9141
9142 // API search type: maximum_by : (((a, a) -> Bool), [a]) -> a
9143 // fwd bind count: 1
9144 // Return the first maximum element using a less comparator.
9145 // maximum_by(lessLength, ["123", "12", "1234", "123"]) == "1234"
9146 // Unsafe! Crashes on an empty sequence.
9147 template <typename Compare, typename Container>
maximum_by(Compare comp,const Container & xs)9148 typename Container::value_type maximum_by(Compare comp,
9149 const Container& xs)
9150 {
9151 internal::check_compare_for_container<Compare, Container>();
9152 assert(is_not_empty(xs));
9153 return *std::max_element(std::begin(xs), std::end(xs), comp);
9154 }
9155
9156 // API search type: maximum_by_maybe : (((a, a) -> Bool), [a]) -> Maybe a
9157 // fwd bind count: 1
9158 // Return the first maximum element using a less comparator
9159 // if sequence is not empty.
9160 // maximum_by_maybe(lessLength, ["123", "12", "1234", "123"]) == Just "1234"
9161 // maximum_by_maybe(lessLength, []) == Nothing
9162 template <typename Compare, typename Container>
maximum_by_maybe(Compare comp,const Container & xs)9163 maybe<typename Container::value_type> maximum_by_maybe(Compare comp,
9164 const Container& xs)
9165 {
9166 if (is_empty(xs))
9167 return {};
9168 else
9169 return maximum_by(comp, xs);
9170 }
9171
9172
9173 // API search type: minimum : [a] -> a
9174 // fwd bind count: 0
9175 // Return the first minimum element.
9176 // minimum([3, 1, 4, 2]) == 1
9177 // Unsafe! Crashes on an empty sequence.
9178 template <typename Container>
minimum(const Container & xs)9179 typename Container::value_type minimum(const Container& xs)
9180 {
9181 return minimum_by(is_less<typename Container::value_type>, xs);
9182 }
9183
9184 // API search type: minimum_maybe : [a] -> Maybe a
9185 // fwd bind count: 0
9186 // Return the first minimum element if sequence is not empty
9187 // if sequence is not empty.
9188 // minimum_maybe([3, 1, 4, 2]) == Just 1
9189 // minimum_maybe([]) == Nothing
9190 template <typename Container>
minimum_maybe(const Container & xs)9191 maybe<typename Container::value_type> minimum_maybe(const Container& xs)
9192 {
9193 if (is_empty(xs))
9194 return {};
9195 else
9196 return minimum(xs);
9197 }
9198
9199 // API search type: maximum : [a] -> a
9200 // fwd bind count: 0
9201 // Return the first maximum element.
9202 // maximum([3, 1, 4, 2]) == 4
9203 // Unsafe! Crashes on an empty sequence.
9204 template <typename Container>
maximum(const Container & xs)9205 typename Container::value_type maximum(const Container& xs)
9206 {
9207 return maximum_by(is_less<typename Container::value_type>, xs);
9208 }
9209
9210 // API search type: maximum_maybe : [a] -> Maybe a
9211 // fwd bind count: 0
9212 // Return the first maximum element if sequence is not empty
9213 // if sequence is not empty.
9214 // maximum_maybe([3, 1, 4, 2]) == Just 4
9215 // maximum_maybe([]) == Nothing
9216 template <typename Container>
maximum_maybe(const Container & xs)9217 maybe<typename Container::value_type> maximum_maybe(const Container& xs)
9218 {
9219 if (is_empty(xs))
9220 return {};
9221 else
9222 return maximum(xs);
9223 }
9224
9225
9226 // API search type: minimum_on : ((a -> b), [a]) -> a
9227 // fwd bind count: 1
9228 // Return the first minimum element using a transformer.
9229 // minimum_on(length, ["123", "12", "1234", "123"]) -> "12"
9230 // Unsafe! Crashes on an empty sequence.
9231 template <typename F, typename Container>
minimum_on(F f,const Container & xs)9232 typename Container::value_type minimum_on(F f, const Container& xs)
9233 {
9234 internal::trigger_static_asserts<internal::unary_function_tag, F, typename Container::value_type>();
9235 return elem_at_idx(minimum_idx_on(f, xs), xs);
9236 }
9237
9238 // API search type: minimum_on_maybe : ((a -> b), [a]) -> Maybe a
9239 // fwd bind count: 1
9240 // Return the first minimum element using a transformer
9241 // if sequence is not empty.
9242 // minimum_on_maybe(length, ["123", "12", "1234", "123"]) -> Just "12"
9243 // minimum_on_maybe(length, []) -> Nothing
9244 template <typename F, typename Container>
minimum_on_maybe(F f,const Container & xs)9245 maybe<typename Container::value_type> minimum_on_maybe(
9246 F f, const Container& xs)
9247 {
9248 if (is_empty(xs))
9249 return {};
9250 else
9251 return minimum_on(f, xs);
9252 }
9253
9254 // API search type: maximum_on : ((a -> b), [a]) -> a
9255 // fwd bind count: 1
9256 // Return the first maximum element using a transformer.
9257 // maximum_on(length, ["123", "12", "1234", "123"]) == "1234"
9258 // Unsafe! Crashes on an empty sequence.
9259 template <typename F, typename Container>
maximum_on(F f,const Container & xs)9260 typename Container::value_type maximum_on(F f, const Container& xs)
9261 {
9262 internal::trigger_static_asserts<internal::unary_function_tag, F, typename Container::value_type>();
9263 return elem_at_idx(maximum_idx_on(f, xs), xs);
9264 }
9265
9266 // API search type: maximum_on_maybe : ((a -> b), [a]) -> Maybe a
9267 // fwd bind count: 1
9268 // Return the first maximum element using a transformer
9269 // if sequence is not empty.
9270 // maximum_on_maybe(length, ["123", "12", "1234", "123"]) == Just "1234"
9271 // maximum_on_maybe(length, ["123", "12", "1234", "123"]) == Nothing
9272 template <typename F, typename Container>
maximum_on_maybe(F f,const Container & xs)9273 maybe<typename Container::value_type> maximum_on_maybe(
9274 F f, const Container& xs)
9275 {
9276 if (is_empty(xs))
9277 return {};
9278 else
9279 return maximum_on(f, xs);
9280 }
9281
9282 // API search type: mean : [a] -> a
9283 // fwd bind count: 0
9284 // mean([1, 4, 4]) == 3
9285 // Also known as average.
9286 // xs must have at least one element.
9287 // Use mean_using_doubles if overflow errors for sum(xs) can occur.
9288 // Unsafe! Crashes on an empty sequence.
9289 template <typename Result, typename Container>
9290 Result mean(const Container& xs)
9291 {
9292 assert(size_of_cont(xs) != 0);
9293 typedef typename Container::value_type T;
9294 return static_cast<Result>(sum(xs) / static_cast<T>(size_of_cont(xs)));
9295 }
9296
9297 // API search type: mean_obj_div_size_t : [a] -> a
9298 // fwd bind count: 0
9299 // mean_obj_div_size_t([B 1, B 4, B 4]) == B 3
9300 // The provided objects must support division by a std::size_t.
9301 // Unsafe! Crashes on an empty sequence.
9302 // Also Make sure sum(xs) does not overflow.
9303 template <typename Container,
9304 typename T = typename Container::value_type>
mean_obj_div_size_t(const Container & xs)9305 T mean_obj_div_size_t(const Container& xs)
9306 {
9307 assert(size_of_cont(xs) != 0);
9308 return sum(xs) / size_of_cont(xs);
9309 }
9310
9311 // API search type: mean_obj_div_double : [a] -> a
9312 // fwd bind count: 0
9313 // mean_obj_div_double([B 1, B 4, B 4]) == B 3
9314 // The provided objects must support division by a double.
9315 // Unsafe! Crashes on an empty sequence.
9316 // Also Make sure sum(xs) does not overflow.
9317 template <typename Container,
9318 typename T = typename Container::value_type>
mean_obj_div_double(const Container & xs)9319 T mean_obj_div_double(const Container& xs)
9320 {
9321 assert(size_of_cont(xs) != 0);
9322 return sum(xs) / static_cast<double>(size_of_cont(xs));
9323 }
9324
9325 // API search type: mean_using_doubles : [a] -> a
9326 // fwd bind count: 0
9327 // mean_using_doubles([1, 4, 4]) == 3
9328 // Converts elements to double before calculating the sum
9329 // to prevent overflows.
9330 // Unsafe! Crashes on an empty sequence.
9331 template <typename Result, typename Container>
9332 Result mean_using_doubles(const Container& xs)
9333 {
9334 assert(size_of_cont(xs) != 0);
9335 auto xs_as_doubles = convert_elems<double>(xs);
9336 auto result_as_double = mean<double>(xs_as_doubles);
9337 if (!std::is_integral<Result>::value)
9338 return static_cast<Result>(result_as_double);
9339 else
9340 return round<double, Result>(result_as_double);
9341 }
9342
9343 // API search type: median : [a] -> a
9344 // fwd bind count: 0
9345 // median([5, 6, 4, 3, 2, 6, 7, 9, 3]) == 5
9346 // Unsafe! Crashes on an empty sequence.
9347 template <typename Container,
9348 typename Result = typename Container::value_type>
median(const Container & xs)9349 Result median(const Container& xs)
9350 {
9351 assert(is_not_empty(xs));
9352
9353 if (size_of_cont(xs) == 1)
9354 return static_cast<Result>(xs.front());
9355
9356 // std::nth_element (instead of sorting)
9357 // would be faster for random-access containers
9358 // but not work at all on other containers like std::list.
9359 auto xsSorted = sort(xs);
9360 if (is_odd(size_of_cont(xsSorted)))
9361 {
9362 auto it = std::begin(xsSorted);
9363 internal::advance_iterator(it, size_of_cont(xsSorted) / 2);
9364 return static_cast<Result>(*it);
9365 }
9366 else
9367 {
9368 auto it1 = std::begin(xsSorted);
9369 internal::advance_iterator(it1, size_of_cont(xsSorted) / 2 - 1);
9370 auto it2 = it1;
9371 ++it2;
9372 return static_cast<Result>(*it1 + *it2) / static_cast<Result>(2);
9373 }
9374 }
9375
9376 // API search type: all_unique_by_less : (((a, a) -> Bool), [a]) -> Bool
9377 // fwd bind count: 1
9378 // Returns true for empty containers.
9379 // O(n*log(n))
9380 template <typename Container, typename Compare>
all_unique_by_less(Compare comp,const Container & xs)9381 bool all_unique_by_less(Compare comp, const Container& xs)
9382 {
9383 internal::check_compare_for_container<Compare, Container>();
9384 if (size_of_cont(xs) < 2)
9385 return true;
9386 return size_of_cont(unique(sort_by(comp, xs))) == size_of_cont(xs);
9387 }
9388
9389 // API search type: all_unique_less : [a] -> Bool
9390 // fwd bind count: 0
9391 // Returns true for empty containers.
9392 // O(n*log(n))
9393 template <typename Container>
all_unique_less(const Container & xs)9394 bool all_unique_less(const Container& xs)
9395 {
9396 typedef typename Container::value_type T;
9397 auto comp = std::less<T>();
9398 return all_unique_by_less(comp, xs);
9399 }
9400
9401 // API search type: is_infix_of : ([a], [a]) -> Bool
9402 // fwd bind count: 1
9403 // is_infix_of("ion", "FunctionalPlus") == true
9404 template <typename Container>
is_infix_of(const Container & token,const Container & xs)9405 bool is_infix_of(const Container& token, const Container& xs)
9406 {
9407 return is_just(find_first_instance_of_token(token, xs));
9408 }
9409
9410 // API search type: is_subsequence_of : ([a], [a]) -> Bool
9411 // fwd bind count: 1
9412 // is_subsequence_of("Final", "FunctionalPlus") == true
9413 template <typename Container>
is_subsequence_of(const Container & seq,const Container & xs)9414 bool is_subsequence_of(const Container& seq, const Container& xs)
9415 {
9416 if (is_empty(seq))
9417 return true;
9418 if (size_of_cont(seq) > size_of_cont(xs))
9419 return false;
9420 typedef typename Container::value_type T;
9421 auto remaining = convert_container_and_elems<std::list<T>>(seq);
9422 for (const auto& x : xs)
9423 {
9424 if (x == remaining.front())
9425 {
9426 remaining.pop_front();
9427 if (is_empty(remaining))
9428 return true;
9429 }
9430 }
9431 return false;
9432 }
9433
9434 // API search type: count_if : ((a -> Bool), [a]) -> Int
9435 // fwd bind count: 1
9436 // count_if(is_even, [1, 2, 3, 5, 7, 8]) == 2
9437 template <typename UnaryPredicate, typename Container>
count_if(UnaryPredicate p,const Container & xs)9438 std::size_t count_if(UnaryPredicate p, const Container& xs)
9439 {
9440 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
9441 return size_of_cont(find_all_idxs_by(p, xs));
9442 }
9443
9444 // API search type: count : (a, [a]) -> Int
9445 // fwd bind count: 1
9446 // count(2, [1, 2, 3, 5, 7, 2, 2]) == 3
9447 template <typename Container>
count(const typename Container::value_type & x,const Container & xs)9448 std::size_t count
9449 (const typename Container::value_type& x, const Container& xs)
9450 {
9451 return size_of_cont(find_all_idxs_of(x, xs));
9452 }
9453
9454 // API search type: is_unique_in_by : ((a -> bool), [a]) -> Bool
9455 // fwd bind count: 1
9456 // is_unique_in_by((==2), [1, 2, 3, 5, 7, 2, 2]) == false
9457 // is_unique_in_by((==5), [1, 2, 3, 5, 7, 2, 2]) == true
9458 template <typename UnaryPredicate, typename Container>
is_unique_in_by(UnaryPredicate pred,const Container & xs)9459 bool is_unique_in_by
9460 (UnaryPredicate pred, const Container& xs)
9461 {
9462 std::size_t count = 0;
9463 for (const auto& x : xs)
9464 {
9465 if (internal::invoke(pred, x))
9466 {
9467 ++count;
9468 if (count > 1)
9469 {
9470 return false;
9471 }
9472 }
9473 }
9474 return true;
9475 }
9476
9477 // API search type: is_unique_in : (a, [a]) -> Bool
9478 // fwd bind count: 1
9479 // is_unique_in(2, [1, 2, 3, 5, 7, 2, 2]) == false
9480 // is_unique_in(5, [1, 2, 3, 5, 7, 2, 2]) == true
9481 template <typename Container>
is_unique_in(const typename Container::value_type & x,const Container & xs)9482 bool is_unique_in
9483 (const typename Container::value_type& x, const Container& xs)
9484 {
9485 return is_unique_in_by(is_equal_to(x), xs);
9486 }
9487
9488 // API search type: is_permutation_of : ([a], [a]) -> Bool
9489 // fwd bind count: 1
9490 // Checks if one container is a permuation of the other one.
9491 // is_permutation_of([2,3,1], [1,2,3]) == true
9492 // O(log(n))
9493 template <typename Container>
is_permutation_of(const Container & xs,const Container & ys)9494 bool is_permutation_of(const Container& xs, const Container& ys)
9495 {
9496 return size_of_cont(xs) == size_of_cont(ys) &&
9497 sort(xs) == sort(ys);
9498 }
9499
9500 // API search type: fill_pigeonholes_to : (Int, [Int]) -> [Int]
9501 // fwd bind count: 1
9502 // Returns a list containing the count for every element in xs
9503 // with the value corresponding to the index in the result list.
9504 // fill_pigeonholes_to(5, [0,1,3,1]) == [1,2,0,1,0]
9505 // fill_pigeonholes_to(3, [0,1,3,1]) == [1,2,0]
9506 template <typename ContainerIn,
9507 typename ContainerOut = std::vector<std::size_t>,
9508 typename T = typename ContainerIn::value_type>
9509 ContainerOut fill_pigeonholes_to(std::size_t idx_end, const ContainerIn& xs)
9510 {
9511 static_assert(std::is_integral<T>::value,
9512 "Type must be integral.");
9513
9514 if (is_empty(xs))
9515 return {};
9516
9517 ContainerOut result(idx_end, 0);
9518 for (const auto& x : xs)
9519 {
9520 if (x >= 0)
9521 {
9522 const auto idx = static_cast<std::size_t>(x);
9523 if (idx < result.size())
9524 {
9525 ++result[idx];
9526 }
9527 }
9528 }
9529 return result;
9530 }
9531
9532 // API search type: fill_pigeonholes : [Int] -> [Int]
9533 // fwd bind count: 0
9534 // Returns a list containing the count for every element in xs
9535 // with the value corresponding to the index in the result list.
9536 // fill_pigeonholes([0,1,3,1]) == [1,2,0,1]
9537 template <typename ContainerIn,
9538 typename ContainerOut = std::vector<std::size_t>,
9539 typename T = typename ContainerIn::value_type>
9540 ContainerOut fill_pigeonholes(const ContainerIn& xs)
9541 {
9542 static_assert(std::is_integral<T>::value,
9543 "Type must be integral.");
9544
9545 if (is_empty(xs))
9546 return {};
9547
9548 return(fill_pigeonholes_to<ContainerIn, ContainerOut>(
9549 maximum(xs) + 1, xs));
9550 }
9551
9552 // API search type: fill_pigeonholes_bool_to : (Int, [Int]) -> [Int]
9553 // fwd bind count: 1
9554 // Returns a list telling if the element corresponding to the index
9555 // is present in xs.
9556 // fill_pigeonholes_bool_to(5, [0,1,3,1]) == [1,1,0,1,0]
9557 // fill_pigeonholes_bool_to(3, [0,1,3,1]) == [1,1,0]
9558 template <typename ContainerIn,
9559 typename ContainerOut = std::vector<std::uint8_t>,
9560 typename T = typename ContainerIn::value_type>
9561 ContainerOut fill_pigeonholes_bool_to(std::size_t idx_end, const ContainerIn& xs)
9562 {
9563 static_assert(std::is_integral<T>::value,
9564 "Type must be integral.");
9565
9566 if (is_empty(xs))
9567 return {};
9568
9569 ContainerOut result(idx_end, 0);
9570 for (const auto& x : xs)
9571 {
9572 if (x >= 0)
9573 {
9574 const auto idx = static_cast<std::size_t>(x);
9575 if (idx < result.size())
9576 {
9577 result[idx] = 1;
9578 }
9579 }
9580 }
9581 return result;
9582 }
9583
9584 // API search type: fill_pigeonholes_bool : [Int] -> [Int]
9585 // fwd bind count: 0
9586 // Returns a list telling if the element corresponding to the index
9587 // is present in xs.
9588 // fill_pigeonholes_bool([0,1,3,1]) == [1,2,0,1]
9589 template <typename ContainerIn,
9590 typename ContainerOut = std::vector<std::uint8_t>,
9591 typename T = typename ContainerIn::value_type>
9592 ContainerOut fill_pigeonholes_bool(const ContainerIn& xs)
9593 {
9594 static_assert(std::is_integral<T>::value,
9595 "Type must be integral.");
9596
9597 if (is_empty(xs))
9598 return {};
9599
9600 return(fill_pigeonholes_bool_to<ContainerIn, ContainerOut>(
9601 maximum(xs) + 1, xs));
9602 }
9603
9604 // API search type: present_in_all : [[a]] -> [a]
9605 // fwd bind count: 0
9606 // Returns a list containing only the elements present in all sublists of xs.
9607 // Also known as gemstones.
9608 // present_in_all([[4,1,2], [5,2,1], [2,4,1]]) == [1,2]
9609 template <typename ContainerIn,
9610 typename SubContainerIn = typename ContainerIn::value_type,
9611 typename T = typename SubContainerIn::value_type,
9612 typename ContainerOut = std::vector<T>>
present_in_all(const ContainerIn & xs)9613 ContainerOut present_in_all(const ContainerIn& xs)
9614 {
9615 return convert_container<ContainerOut>(
9616 fplus::sets_intersection(
9617 transform(
9618 convert_container<std::set<T>, SubContainerIn>,
9619 xs)));
9620 }
9621
9622 } // namespace fplus
9623
9624 //
9625 // extrapolate.hpp
9626 //
9627
9628 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
9629 // https://github.com/Dobiasd/FunctionalPlus
9630 // Distributed under the Boost Software License, Version 1.0.
9631 // (See accompanying file LICENSE_1_0.txt or copy at
9632 // http://www.boost.org/LICENSE_1_0.txt)
9633
9634
9635
9636 namespace fplus
9637 {
9638
9639 // API search type: elem_at_idx_or_nothing : (Int, [a]) -> Maybe a
9640 // fwd bind count: 1
9641 // Return nth element of a sequence.
9642 // Returns nothing if index is outside of xs.
9643 template <typename Container,
9644 typename T = typename Container::value_type>
elem_at_idx_or_nothing(signed int idx,const Container & xs)9645 maybe<T> elem_at_idx_or_nothing(signed int idx, const Container& xs)
9646 {
9647 if (idx < 0 || idx >= static_cast<signed int>(size_of_cont(xs)))
9648 {
9649 return {};
9650 }
9651 auto it = std::begin(xs);
9652 internal::advance_iterator(it, static_cast<std::size_t>(idx));
9653 return *it;
9654 }
9655
9656 // API search type: elem_at_idx_or_constant : (a, Int, [a]) -> a
9657 // fwd bind count: 2
9658 // Return nth element of a sequence.
9659 // Interpolate outside of sequence with a constant value.
9660 // iiiiii|abcdefgh|iiiiiii
9661 template <typename Container,
9662 typename T = typename Container::value_type>
elem_at_idx_or_constant(const T & c,signed int idx,const Container & xs)9663 T elem_at_idx_or_constant(const T& c, signed int idx, const Container& xs)
9664 {
9665 if (idx < 0 || idx >= static_cast<signed int>(size_of_cont(xs)))
9666 {
9667 return c;
9668 }
9669 auto it = std::begin(xs);
9670 internal::advance_iterator(it, static_cast<std::size_t>(idx));
9671 return *it;
9672 }
9673
9674 // API search type: elem_at_idx_or_replicate : (Int, [a]) -> a
9675 // fwd bind count: 1
9676 // Return nth element of a sequence.
9677 // Interpolate outside of sequence by replicating the nearest inside value.
9678 // aaaaaa|abcdefgh|hhhhhhh
9679 // xs must be non-empty.
9680 template <typename Container,
9681 typename T = typename Container::value_type>
elem_at_idx_or_replicate(signed int idx,const Container & xs)9682 T elem_at_idx_or_replicate(signed int idx, const Container& xs)
9683 {
9684 assert(is_not_empty(xs));
9685 if (idx < 0)
9686 {
9687 return xs.front();
9688 }
9689 if (idx >= static_cast<signed int>(size_of_cont(xs)))
9690 {
9691 return xs.back();
9692 }
9693 auto it = std::begin(xs);
9694 internal::advance_iterator(it, static_cast<std::size_t>(idx));
9695 return *it;
9696 }
9697
9698 // API search type: elem_at_idx_or_wrap : (Int, [a]) -> a
9699 // fwd bind count: 1
9700 // Return nth element of a sequence.
9701 // Interpolate outside of sequence by replicating the sequence.
9702 // For cyclic element access.
9703 // cdefgh|abcdefgh|abcdefg
9704 // xs must be non-empty.
9705 template <typename Container,
9706 typename T = typename Container::value_type>
elem_at_idx_or_wrap(signed int idx,const Container & xs)9707 T elem_at_idx_or_wrap(signed int idx, const Container& xs)
9708 {
9709 assert(is_not_empty(xs));
9710 const signed int cont_size = static_cast<signed int>(size_of_cont(xs));
9711 if (idx < 0)
9712 idx = cont_size - (std::abs(idx) % cont_size);
9713 else
9714 idx = idx % cont_size;
9715 auto it = std::begin(xs);
9716 internal::advance_iterator(it, static_cast<std::size_t>(idx));
9717 return *it;
9718 }
9719
9720 // API search type: extrapolate_replicate : (Int, Int, [a]) -> [a]
9721 // fwd bind count: 2
9722 // Extrapolate a sequence by replicating the border values.
9723 // count_begin determines the number of elements to be prepended.
9724 // count_end determines the number of elements to be appended.
9725 // aaaaaa|abcdefgh|hhhhhhh
9726 // xs must be non-empty.
9727 template <typename Container,
9728 typename T = typename Container::value_type>
9729 Container extrapolate_replicate(std::size_t count_begin, std::size_t count_end,
9730 const Container& xs)
9731 {
9732 assert(is_not_empty(xs));
9733 Container ys;
9734 const auto xs_size = size_of_cont(xs);
9735 internal::prepare_container(ys, xs_size + count_begin + count_end);
9736 auto it = internal::get_back_inserter<Container>(ys);
9737 const signed int idx_end = static_cast<signed int>(xs_size + count_end);
9738 const signed int idx_start = -static_cast<signed int>(count_begin);
9739 for (signed int idx = idx_start; idx < idx_end; ++idx)
9740 {
9741 *it = elem_at_idx_or_replicate(idx, xs);
9742 }
9743 return ys;
9744 }
9745
9746 // API search type: extrapolate_wrap : (Int, Int, [a]) -> [a]
9747 // fwd bind count: 2
9748 // Extrapolate a sequence by accessing the elements in cyclic fashion.
9749 // count_begin determines the number of elements to be prepended.
9750 // count_end determines the number of elements to be appended.
9751 // cdefgh|abcdefgh|abcdefg
9752 // xs must be non-empty.
9753 template <typename Container,
9754 typename T = typename Container::value_type>
9755 Container extrapolate_wrap(std::size_t count_begin, std::size_t count_end,
9756 const Container& xs)
9757 {
9758 assert(is_not_empty(xs));
9759 Container ys;
9760 const auto xs_size = size_of_cont(xs);
9761 internal::prepare_container(ys, xs_size + count_begin + count_end);
9762 auto it = internal::get_back_inserter<Container>(ys);
9763 const signed int idx_end = static_cast<signed int>(xs_size + count_end);
9764 const signed int idx_start = -static_cast<signed int>(count_begin);
9765 for (signed int idx = idx_start; idx < idx_end; ++idx)
9766 {
9767 *it = elem_at_idx_or_wrap(idx, xs);
9768 }
9769 return ys;
9770 }
9771
9772 } // namespace fplus
9773
9774 //
9775 // interpolate.hpp
9776 //
9777
9778 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
9779 // https://github.com/Dobiasd/FunctionalPlus
9780 // Distributed under the Boost Software License, Version 1.0.
9781 // (See accompanying file LICENSE_1_0.txt or copy at
9782 // http://www.boost.org/LICENSE_1_0.txt)
9783
9784
9785
9786 #include <cmath>
9787
9788 namespace fplus
9789 {
9790
9791 // API search type: elem_at_float_idx : (Float, [a]) -> a
9792 // fwd bind count: 1
9793 // Interpolates linearly between elements.
9794 // xs must be non-empty.
9795 template <typename Container,
9796 typename T = typename Container::value_type>
elem_at_float_idx(double idx,const Container & xs)9797 T elem_at_float_idx(double idx, const Container& xs)
9798 {
9799 assert(is_not_empty(xs));
9800 if (idx <= 0.0)
9801 {
9802 return xs.front();
9803 }
9804 std::size_t idx_floor = static_cast<std::size_t>(floor(idx));
9805 std::size_t idx_ceil = static_cast<std::size_t>(ceil(idx));
9806 if (idx_ceil >= size_of_cont(xs))
9807 {
9808 return xs.back();
9809 }
9810 double idx_floor_float = static_cast<double>(idx_floor);
9811 double idx_ceil_float = static_cast<double>(idx_ceil);
9812 double weight_floor = idx_ceil_float - idx;
9813 double weight_ceil = idx - idx_floor_float;
9814 return
9815 (weight_floor * elem_at_idx(idx_floor, xs) +
9816 weight_ceil * elem_at_idx(idx_ceil, xs));
9817 }
9818
9819 } // namespace fplus
9820
9821 //
9822 // maps.hpp
9823 //
9824
9825 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
9826 // https://github.com/Dobiasd/FunctionalPlus
9827 // Distributed under the Boost Software License, Version 1.0.
9828 // (See accompanying file LICENSE_1_0.txt or copy at
9829 // http://www.boost.org/LICENSE_1_0.txt)
9830
9831
9832
9833
9834 #include <map>
9835 #include <unordered_map>
9836
9837 namespace fplus
9838 {
9839
9840 // API search type: pairs_to_map : [(key, val)] -> Map key val
9841 // fwd bind count: 0
9842 // Converts a Container of pairs (key, value) into a dictionary.
9843 template <typename MapOut, typename ContainerIn>
9844 MapOut pairs_to_map(const ContainerIn& pairs)
9845 {
9846 return convert_container_and_elems<MapOut>(pairs);
9847 }
9848
9849 // API search type: pairs_to_map_grouped : [(key, val)] -> Map key [val]
9850 // fwd bind count: 0
9851 // Convert a list of key-value pairs to a dictionary
9852 // while pushing values having the same key into a vector.
9853 // pairs_to_map_grouped([("a", 1), ("a", 2), ("b", 6), ("a", 4)])
9854 // -> {"a": [1, 2, 4], "b": [6]}
9855 template <typename ContainerIn,
9856 typename Key = typename ContainerIn::value_type::first_type,
9857 typename SingleValue = typename ContainerIn::value_type::second_type,
9858 typename MapOut = std::map<Key, std::vector<SingleValue>>>
pairs_to_map_grouped(const ContainerIn & pairs)9859 MapOut pairs_to_map_grouped(const ContainerIn& pairs)
9860 {
9861 MapOut result;
9862 for (const auto& p : pairs)
9863 {
9864 result[p.first].push_back(p.second);
9865 }
9866 return result;
9867 }
9868
9869 // API search type: pairs_to_unordered_map_grouped : [(key, val)] -> Map key [val]
9870 // fwd bind count: 0
9871 // Convert a list of key-value pairs to a dictionary
9872 // while pushing values having the same key into a vector.
9873 // pairs_to_unordered_map_grouped([("a", 1), ("a", 2), ("b", 6), ("a", 4)])
9874 // -> {"a": [1, 2, 4], "b": [6]}
9875 template <typename ContainerIn,
9876 typename Key = typename ContainerIn::value_type::first_type,
9877 typename SingleValue = typename ContainerIn::value_type::second_type,
9878 typename MapOut = std::unordered_map<Key, std::vector<SingleValue>>>
pairs_to_unordered_map_grouped(const ContainerIn & pairs)9879 MapOut pairs_to_unordered_map_grouped(const ContainerIn& pairs)
9880 {
9881 MapOut result;
9882 for (const auto& p : pairs)
9883 {
9884 result[p.first].push_back(p.second);
9885 }
9886 return result;
9887 }
9888
9889 // API search type: map_to_pairs : Map key val -> [(key, val)]
9890 // fwd bind count: 0
9891 // Converts a dictionary into a Container of pairs (key, value).
9892 template <typename MapType,
9893 typename MapPair = typename MapType::value_type,
9894 typename Key = typename std::remove_const<typename MapPair::first_type>::type,
9895 typename Val = typename std::remove_const<typename MapPair::second_type>::type,
9896 typename OutPair = std::pair<Key, Val>,
9897 typename ContainerOut = std::vector<OutPair>>
map_to_pairs(const MapType & dict)9898 ContainerOut map_to_pairs(const MapType& dict)
9899 {
9900 return convert_container_and_elems<ContainerOut>(dict);
9901 }
9902
9903 // API search type: transform_map_values : ((old_val -> new_val), Map key old_val) -> Map key new_val
9904 // fwd bind count: 1
9905 // Manipulate the values in a dictionary, keeping the key-value relationship.
9906 // transform_map_values((*2), {0: 2, 1: 3}) == {0: 4, 1: 6}
9907 template <typename F, typename MapIn>
transform_map_values(F f,const MapIn & map)9908 auto transform_map_values(F f, const MapIn& map)
9909 {
9910 using MapInPair = typename MapIn::value_type;
9911 using Key = std::remove_const_t<typename MapInPair::first_type>;
9912 using InVal = std::remove_const_t<typename MapInPair::second_type>;
9913 using OutVal = std::decay_t<internal::invoke_result_t<F, InVal>>;
9914 using MapOut = typename internal::SameMapTypeNewTypes<MapIn, Key, OutVal>::type;
9915
9916 return pairs_to_map<MapOut>(
9917 transform(
9918 bind_1st_of_2(transform_snd<Key, InVal, F>, f),
9919 map_to_pairs(map)));
9920 }
9921
9922 // API search type: map_union_with : (((val, val) -> val), Map key val, Map key val) -> Map key val
9923 // fwd bind count: 2
9924 // Combine two dictionaries using a binary function for the values.
9925 // map_union_with((++), {0: a, 1: b}, {0: c, 2: d}) == {0: ac, 1: b, 2: d}
9926 template <typename F, typename MapIn>
map_union_with(F f,const MapIn & dict1,const MapIn & dict2)9927 auto map_union_with(F f, const MapIn& dict1, const MapIn& dict2)
9928 {
9929 const auto both = append(map_to_pairs(dict1), map_to_pairs(dict2));
9930 using Key = typename decltype(both)::value_type::first_type;
9931 using SingleValue = typename decltype(both)::value_type::second_type;
9932 auto full_map = pairs_to_map_grouped<decltype(both), Key, SingleValue,
9933 typename internal::SameMapTypeNewTypes<MapIn, Key, std::vector<SingleValue>>::type>(both);
9934 const auto group_f = [f](const auto& vals)
9935 {
9936 return fold_left_1(f, vals);
9937 };
9938 return transform_map_values(group_f, full_map);
9939 }
9940
9941 // API search type: map_union : (Map key val, Map key val) -> Map key val
9942 // fwd bind count: 1
9943 // Combine two dictionaries keeping the value of the first map
9944 // in case of key collisions.
9945 // map_union({0: a, 1: b}, {0: c, 2: d}) == {0: a, 1: b, 2: d}
9946 template <typename MapType>
map_union(const MapType & dict1,const MapType & dict2)9947 MapType map_union(const MapType& dict1, const MapType& dict2)
9948 {
9949 using Value = typename MapType::value_type::second_type;
9950
9951 const auto get_first = [](const Value& a, const Value&) -> Value
9952 {
9953 return a;
9954 };
9955 return map_union_with(get_first, dict1, dict2);
9956 }
9957
9958 // API search type: map_grouped_to_pairs : Map key [val] -> [(key, val)]
9959 // fwd bind count: 0
9960 // Convert a dictionary with sequence values to a list of key-value pairs.
9961 // Inverse operation of pairs_to_map_grouped.
9962 // map_grouped_to_pairs({"a": [1, 2, 4], "b": [6]})
9963 // -> [("a", 1), ("a", 2), ("a", 4), ("b", 6)]
9964 template<typename MapType>
map_grouped_to_pairs(const MapType & dict)9965 auto map_grouped_to_pairs(const MapType &dict)
9966 {
9967 using Key = typename MapType::key_type;
9968 using Group = typename MapType::mapped_type;
9969
9970 auto fn = [](const auto &pair)
9971 {
9972 const auto f = zip_repeat<std::vector<Key>, Group>;
9973 return apply_to_pair(f, transform_fst(singleton_seq < Key > , pair));
9974 };
9975 return concat(transform(fn, map_to_pairs(dict)));
9976 }
9977
9978 // API search type: get_map_keys : Map key val -> [key]
9979 // fwd bind count: 0
9980 // Returns all keys used in a map.
9981 template <typename MapType,
9982 typename ContainerOut =
9983 std::vector<typename std::remove_const<typename MapType::key_type>::type>>
get_map_keys(const MapType & dict)9984 ContainerOut get_map_keys(const MapType& dict)
9985 {
9986 auto pairs = map_to_pairs(dict);
9987 typedef typename decltype(pairs)::value_type::first_type FirstType;
9988 typedef typename decltype(pairs)::value_type::second_type SecondType;
9989 return transform_convert<ContainerOut>(
9990 fst<FirstType, SecondType>, map_to_pairs(dict));
9991 }
9992
9993 // API search type: get_map_values : Map key val -> [val]
9994 // fwd bind count: 0
9995 // Returns all values present in a map.
9996 template <typename MapType,
9997 typename ContainerOut =
9998 std::vector<typename std::remove_const<typename MapType::mapped_type>::type>>
get_map_values(const MapType & dict)9999 ContainerOut get_map_values(const MapType& dict)
10000 {
10001 auto pairs = map_to_pairs(dict);
10002 typedef typename decltype(pairs)::value_type::first_type FirstType;
10003 typedef typename decltype(pairs)::value_type::second_type SecondType;
10004 return transform_convert<ContainerOut>(
10005 snd<FirstType, SecondType>, map_to_pairs(dict));
10006 }
10007
10008 // API search type: swap_keys_and_values : Map a b -> Map b a
10009 // fwd bind count: 0
10010 // Swaps keys and Values of a dict:
10011 // swap_keys_and_values({1: "a", 2: "b"}) == {"a": 1, "b": 2}
10012 template <typename MapIn,
10013 typename MapInPair = typename MapIn::value_type,
10014 typename InKey = typename MapInPair::first_type,
10015 typename InVal = typename MapInPair::second_type,
10016 typename OutKey = InVal,
10017 typename OutVal = typename std::remove_const<InKey>::type,
10018 typename MapOut = typename internal::SameMapTypeNewTypes<MapIn, OutKey, OutVal>::type>
swap_keys_and_values(const MapIn & dict)10019 MapOut swap_keys_and_values(const MapIn& dict)
10020 {
10021 auto inAsPairs = map_to_pairs(dict);
10022 auto outAsPairs = transform(swap_pair_elems<InKey, InVal>, inAsPairs);
10023 return pairs_to_map<MapOut>(outAsPairs);
10024 }
10025
10026 // API search type: create_map : ([key], [val]) -> Map key val
10027 // fwd bind count: 1
10028 // Zip a sequence of keys with a sequence of values to obtain a dictionary.
10029 // create_map([1,2,3], ["one", "two"]) == {1: "one", 2: "two"}
10030 template <typename ContainerIn1, typename ContainerIn2,
10031 typename Key = typename std::remove_const<typename ContainerIn1::value_type>::type,
10032 typename Val = typename std::remove_const<typename ContainerIn2::value_type>::type,
10033 typename MapOut = std::map<Key, Val>>
create_map(const ContainerIn1 & keys,const ContainerIn2 & values)10034 MapOut create_map(const ContainerIn1& keys, const ContainerIn2& values)
10035 {
10036 auto pairs = zip(keys, values);
10037 return pairs_to_map<MapOut>(pairs);
10038 }
10039
10040 // API search type: create_map_with : ((key -> val), [key]) -> Map key val
10041 // fwd bind count: 1
10042 // Take a list of keys and create a dictionary
10043 // generating the values by applying f to each key.
10044 // create_map_with(show, [1,2]) == {1: "1", 2: "2"}
10045 template <typename ContainerIn, typename F>
create_map_with(F f,const ContainerIn & keys)10046 auto create_map_with(F f, const ContainerIn& keys)
10047 {
10048 return create_map(keys, transform(f, keys));
10049 }
10050
10051 // API search type: create_map_grouped : ((val -> key), [val]) -> Map key val
10052 // fwd bind count: 1
10053 // Take a list of values and create a grouped dictionary
10054 // generating the keys by applying f to each key.
10055 // create_map_grouped(length, ["one", "three", "two"]) == {3: ["one", "two"], 5: ["three"]}
10056 // Also known as group_by
10057 template <typename ContainerIn, typename F>
create_map_grouped(F f,const ContainerIn & values)10058 auto create_map_grouped(F f, const ContainerIn& values)
10059 {
10060 return pairs_to_map_grouped(zip(transform(f, values), values));
10061 }
10062
10063 // API search type: create_unordered_map : ([key], [val]) -> Map key val
10064 // fwd bind count: 1
10065 // Zip a sequence of keys with a sequence of values to obtain a dictionary.
10066 // create_unordered_map([1,2,3], ["one", "two"]) == {1: "one", 2: "two"}
10067 template <typename ContainerIn1, typename ContainerIn2,
10068 typename Key = typename std::remove_const<typename ContainerIn1::value_type>::type,
10069 typename Val = typename std::remove_const<typename ContainerIn2::value_type>::type,
10070 typename MapOut = std::unordered_map<Key, Val >>
create_unordered_map(const ContainerIn1 & keys,const ContainerIn2 & values)10071 MapOut create_unordered_map(
10072 const ContainerIn1& keys,
10073 const ContainerIn2& values)
10074 {
10075 auto pairs = zip(keys, values);
10076 return pairs_to_map<MapOut>(pairs);
10077 }
10078
10079 // API search type: create_unordered_map_with : ((key -> val), [key]) -> Map key val
10080 // fwd bind count: 1
10081 // Take a list of keys and create a dictionary
10082 // generating the values by applying f to each key.
10083 // create_unordered_map_with(show, [1,2]) == {1: "1", 2: "2"}
10084 template <typename ContainerIn, typename F>
create_unordered_map_with(F f,const ContainerIn & keys)10085 auto create_unordered_map_with(F f, const ContainerIn& keys)
10086 {
10087 return create_unordered_map(keys, transform(f, keys));
10088 }
10089
10090 // API search type: create_unordered_map_grouped : ((val -> key), [val]) -> Map key val
10091 // fwd bind count: 1
10092 // Take a list of values and create a grouped dictionary
10093 // generating the keys by applying f to each key.
10094 // create_unordered_map_grouped(length, ["one", "three", "two"]) == {3: ["one", "two"], 5: ["three"]}
10095 // Also known as group_by
10096 template <typename ContainerIn, typename F>
create_unordered_map_grouped(F f,const ContainerIn & values)10097 auto create_unordered_map_grouped(F f, const ContainerIn& values)
10098 {
10099 return pairs_to_unordered_map_grouped(zip(transform(f, values), values));
10100 }
10101
10102 // API search type: get_from_map : (Map key val, key) -> Maybe val
10103 // fwd bind count: 1
10104 // Returns just the value of a key if key is present.
10105 // Otherwise returns nothing.
10106 template <typename MapType,
10107 typename Key = typename MapType::key_type,
10108 typename Val = typename MapType::mapped_type>
get_from_map(const MapType & map,const Key & key)10109 maybe<Val> get_from_map(const MapType& map, const Key& key)
10110 {
10111 auto it = map.find(key);
10112 if (it == std::end(map))
10113 return nothing<Val>();
10114 return just(it->second);
10115 }
10116
10117 // API search type: get_from_map_unsafe : (Map key val, key) -> val
10118 // fwd bind count: 1
10119 // Returns the value of a key if key is present.
10120 // Crashes otherwise.
10121 template <typename MapType,
10122 typename Key = typename MapType::key_type,
10123 typename Val = typename MapType::mapped_type>
get_from_map_unsafe(const MapType & map,const Key & key)10124 Val get_from_map_unsafe(const MapType& map, const Key& key)
10125 {
10126 return unsafe_get_just(get_from_map(map, key));
10127 }
10128
10129 // API search type: get_from_map_with_def : (Map key val, val, key) -> val
10130 // fwd bind count: 2
10131 // Returns the value of a key if key is present.
10132 // Otherwise returns the provided default.
10133 // Also known as prop_or.
10134 template <typename MapType,
10135 typename Key = typename MapType::key_type,
10136 typename Val = typename MapType::mapped_type>
get_from_map_with_def(const MapType & map,const Val & defVal,const Key & key)10137 Val get_from_map_with_def(const MapType& map, const Val& defVal,
10138 const Key& key)
10139 {
10140 return just_with_default(defVal, get_from_map(map, key));
10141 }
10142
10143 // API search type: get_first_from_map : (Map key val, [key]) -> Maybe val
10144 // fwd bind count: 1
10145 // Returns just the value of the first key present.
10146 // Otherwise returns nothing.
10147 template <typename MapType,
10148 typename KeysContainer,
10149 typename Key = typename MapType::key_type,
10150 typename Val = typename MapType::mapped_type>
get_first_from_map(const MapType & map,const KeysContainer & keys)10151 maybe<Val> get_first_from_map(const MapType& map, const KeysContainer& keys)
10152 {
10153 static_assert(std::is_same<typename KeysContainer::value_type, Key>::value,
10154 "Key type does not match.");
10155 for (const auto& key: keys)
10156 {
10157 auto it = map.find(key);
10158 if (it != std::end(map))
10159 return just(it->second);
10160 }
10161 return nothing<Val>();
10162 }
10163
10164 // API search type: get_first_from_map_unsafe : (Map key val, [key]) -> val
10165 // fwd bind count: 1
10166 // Returns the value of the first key present.
10167 // Crashes otherwise.
10168 template <typename MapType,
10169 typename KeysContainer,
10170 typename Key = typename MapType::key_type,
10171 typename Val = typename MapType::mapped_type>
get_first_from_map_unsafe(const MapType & map,const KeysContainer & keys)10172 Val get_first_from_map_unsafe(const MapType& map, const KeysContainer& keys)
10173 {
10174 return unsafe_get_just(get_first_from_map(map, keys));
10175 }
10176
10177 // API search type: get_first_from_map_with_def : (Map key val, val, [key]) -> val
10178 // fwd bind count: 2
10179 // Returns the value of the first key present.
10180 // Otherwise returns the provided default.
10181 template <typename MapType,
10182 typename KeysContainer,
10183 typename Key = typename MapType::key_type,
10184 typename Val = typename MapType::mapped_type>
get_first_from_map_with_def(const MapType & map,const Val & defVal,const KeysContainer & keys)10185 Val get_first_from_map_with_def(const MapType& map, const Val& defVal,
10186 const KeysContainer& keys)
10187 {
10188 return just_with_default(defVal, get_first_from_map(map, keys));
10189 }
10190
10191 // API search type: map_contains : (Map key val, key) -> Bool
10192 // fwd bind count: 1
10193 // Checks if a map contains a key.
10194 template <typename MapType, typename Key = typename MapType::key_type>
map_contains(const MapType & map,const Key & key)10195 bool map_contains(const MapType& map, const Key& key)
10196 {
10197 auto it = map.find(key);
10198 return it != std::end(map);
10199 }
10200
10201 // API search type: map_keep_if : ((key -> Bool), Map key val) -> Map key val
10202 // fwd bind count: 1
10203 // Filters the map by keys.
10204 // map_keep_if(is_upper_case, {a: 1, b: 2, A: 3, C: 4}) == {A: 3, C: 4}
10205 // Also known as pick_by.
10206 template <typename MapType, typename Pred>
10207 MapType map_keep_if(Pred pred, const MapType& map)
10208 {
10209 MapType result;
10210 for (const auto& key_and_value : map)
10211 {
10212 if (internal::invoke(pred, key_and_value.first))
10213 {
10214 result.insert(key_and_value);
10215 }
10216 }
10217 return result;
10218 }
10219
10220 // API search type: map_drop_if : ((key -> Bool), Map key val) -> Map key val
10221 // fwd bind count: 1
10222 // Filters the map by keys.
10223 // map_drop_if(is_lower_case, {a: 1, b: 2, A: 3, C: 4}) == {A: 3, C: 4}
10224 // Inverse of map_keep_if.
10225 template <typename MapType, typename Pred>
10226 MapType map_drop_if(Pred pred, const MapType& map)
10227 {
10228 return map_keep_if(logical_not(pred), map);
10229 }
10230
10231 // API search type: map_keep : ([key], Map key val) -> Map key val
10232 // fwd bind count: 1
10233 // Keeps only the pairs of the map found in the key list.
10234 // map_keep([a, d], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
10235 // map_keep([a, e, f], {a: 1, b: 2, c: 3, d: 4}) == {a: 1}
10236 // Also known as pick.
10237 template <typename MapType, typename KeyContainer>
10238 MapType map_keep(const KeyContainer& keys, const MapType& map)
10239 {
10240 static_assert(std::is_same<
10241 typename KeyContainer::value_type,
10242 typename MapType::key_type>::value,
10243 "Key types do not match.");
10244 return map_keep_if(bind_2nd_of_2(is_elem_of<KeyContainer>, keys), map);
10245 }
10246
10247 // API search type: map_drop : ([key], Map key val) -> Map key val
10248 // fwd bind count: 1
10249 // Keeps only the pairs of the map not found in the key list.
10250 // Inverse of map_keep.
10251 // map_drop([b, c], {a: 1, b: 2, c: 3, d: 4}); == {a: 1, d: 4}
10252 template <typename MapType, typename KeyContainer>
10253 MapType map_drop(const KeyContainer& keys, const MapType& map)
10254 {
10255 static_assert(std::is_same<
10256 typename KeyContainer::value_type,
10257 typename MapType::key_type>::value,
10258 "Key types do not match.");
10259 return map_drop_if(bind_2nd_of_2(is_elem_of<KeyContainer>, keys), map);
10260 }
10261
10262 // API search type: map_keep_if_value : ((val -> Bool), Map key val) -> Map key val
10263 // fwd bind count: 1
10264 // Filters the map by values.
10265 // map_keep_if_value(is_upper_case, {1: a, 2: b, 3: A, 4: C}) == {3: A, 4: C}
10266 // Also known as filter_values.
10267 template <typename MapType, typename Pred>
10268 MapType map_keep_if_value(Pred pred, const MapType& map)
10269 {
10270 MapType result;
10271 for (const auto& key_and_value : map)
10272 {
10273 if (internal::invoke(pred, key_and_value.second))
10274 {
10275 result.insert(key_and_value);
10276 }
10277 }
10278 return result;
10279 }
10280
10281 // API search type: map_drop_if_value : ((value -> Bool), Map key val) -> Map key val
10282 // fwd bind count: 1
10283 // Filters the map by values.
10284 // map_drop_if_value(is_lower_case, {1: a, 2: b, 3: A, 4: C}) == {3: A, 4: C}
10285 // Inverse of map_keep_if_value.
10286 template <typename MapType, typename Pred>
10287 MapType map_drop_if_value(Pred pred, const MapType& map)
10288 {
10289 return map_keep_if_value(logical_not(pred), map);
10290 }
10291
10292 // API search type: map_keep_values : ([value], Map key val) -> Map key val
10293 // fwd bind count: 1
10294 // Keeps only the pairs of the map found in the value list.
10295 // map_keep_values([1, 4], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
10296 // map_keep_values([1, 5, 6], {a: 1, b: 2, c: 3, d: 4}) == {a: 1}
10297 template <typename MapType, typename ValueContainer>
10298 MapType map_keep_values(const ValueContainer& values, const MapType& map)
10299 {
10300 static_assert(std::is_same<
10301 typename ValueContainer::value_type,
10302 typename MapType::mapped_type>::value,
10303 "Value types do not match.");
10304 return map_keep_if_value(
10305 bind_2nd_of_2(is_elem_of<ValueContainer>, values), map);
10306 }
10307
10308 // API search type: map_drop_values : ([value], Map key val) -> Map key val
10309 // fwd bind count: 1
10310 // Keeps only the pairs of the map not found in the value list.
10311 // Inverse of map_keep_values.
10312 // map_drop_values([2, 3], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
10313 template <typename MapType, typename ValueContainer>
10314 MapType map_drop_values(const ValueContainer& values, const MapType& map)
10315 {
10316 static_assert(std::is_same<
10317 typename ValueContainer::value_type,
10318 typename MapType::mapped_type>::value,
10319 "Value types do not match.");
10320 return map_drop_if_value(
10321 bind_2nd_of_2(is_elem_of<ValueContainer>, values), map);
10322 }
10323
10324 // API search type: map_pluck : (key, [Map key val]) -> [val]
10325 // fwd bind count: 1
10326 // Extracts values to a specific key from a list of maps.
10327 // map_pluck('a', [{a: 1, b: 2}, {a: 3}, {c: 4}]) == [Just 1, Just 3, Nothing]
10328 template <typename MapContainer,
10329 typename ContainerOut =
10330 std::vector<maybe<typename MapContainer::value_type::mapped_type>>,
10331 typename MapType = typename MapContainer::value_type,
10332 typename Key = typename MapType::key_type,
10333 typename Val = typename MapType::mapped_type>
10334 ContainerOut map_pluck(const Key& key, const MapContainer& maps)
10335 {
10336 return transform_convert<ContainerOut>(
10337 bind_2nd_of_2(get_from_map<MapType>, key), maps);
10338 }
10339
10340 // API search type: choose : ([(a, b)], a) -> Maybe b
10341 // fwd bind count: 1
10342 // Selects a value assigned to a key iff the key exists exactly once.
10343 // choose([(1,a), (2,b)], 2) == Just b;
10344 // choose([(1,a), (1,b)], 2) == Nothing;
10345 // choose([(1,a), (2,b)], 3) == Nothing;
10346 template<typename Key, typename Val>
choose(const std::vector<std::pair<Key,Val>> & pairs,const Key & x)10347 maybe<Val> choose(const std::vector<std::pair<Key, Val>>& pairs, const Key& x)
10348 {
10349 if (count(x, transform(fst<Key, Val>, pairs)) != 1)
10350 return {};
10351 return get_from_map(pairs_to_map<std::unordered_map<Key, Val>>(pairs), x);
10352 }
10353
10354 // API search type: choose_by : ([((a -> Bool), b)], a) -> Maybe b
10355 // fwd bind count: 2
10356 // Iff exactly one predicate is fulfilled
10357 // the value assigned to this predicate is selected.
10358 // choose_by([(is_even,a), (is_bigger_than_3,b)], 2) == Just a;
10359 // choose_by([(is_even,a), (is_bigger_than_3,b)], 5) == Just b;
10360 // choose_by([(is_even,a), (is_bigger_than_3,b)], 1) == Nothing;
10361 // choose_by([(is_even,a), (is_bigger_than_3,b)], 4) == Nothing;
10362 template<typename Key, typename Val>
choose_by(const std::vector<std::pair<std::function<bool (const Key &)>,Val>> & pairs,const Key & x)10363 maybe<Val> choose_by(
10364 const std::vector<std::pair<std::function<bool(const Key&)>, Val>>& pairs,
10365 const Key& x)
10366 {
10367 maybe<Val> result;
10368 for (const auto& p : pairs)
10369 {
10370 if (internal::invoke(p.first, x))
10371 {
10372 if (is_just(result))
10373 {
10374 return nothing<Val>();
10375 }
10376 result = p.second;
10377 }
10378 }
10379 return result;
10380 }
10381
10382 // API search type: choose_lazy : ([(a, (() -> b))], a) -> Maybe b
10383 // fwd bind count: 1
10384 // Evaluates a lazy value assigned to a key iff the key exists exactly once.
10385 // choose_lazy([(1,a), (2,b)], 2) == Just b();
10386 // choose_lazy([(1,a), (1,b)], 2) == Nothing;
10387 // choose_lazy([(1,a), (2,b)], 3) == Nothing;
10388 template <typename Key, typename ValStub>
choose_lazy(const std::vector<std::pair<Key,ValStub>> & pairs,const Key & x)10389 auto choose_lazy(const std::vector<std::pair<Key, ValStub>>& pairs,
10390 const Key& x)
10391 {
10392 using Ret = maybe<std::decay_t<internal::invoke_result_t<ValStub>>>;
10393 const auto res = choose(pairs, x);
10394 if (res.is_nothing())
10395 return Ret{};
10396 else
10397 return Ret{res.unsafe_get_just()()};
10398 }
10399
10400 // API search type: choose_by_lazy : ([((a -> Bool), (() -> b))], a) -> Maybe b
10401 // fwd bind count: 2
10402 // Iff exactly one predicate is fulfilled
10403 // the lazy value assigned to this predicate is evaluated.
10404 // choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 2) == Just a();
10405 // choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 5) == Just b();
10406 // choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 1) == Nothing;
10407 // choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 4) == Nothing;
10408 template <typename Key, typename ValStub>
choose_by_lazy(const std::vector<std::pair<std::function<bool (const Key &)>,ValStub>> & pairs,const Key & x)10409 auto choose_by_lazy(
10410 const std::vector<std::pair<std::function<bool(const Key&)>, ValStub>>& pairs,
10411 const Key& x)
10412 {
10413 using Ret = maybe<std::decay_t<internal::invoke_result_t<ValStub>>>;
10414
10415 const auto res = choose_by(pairs, x);
10416 if (res.is_nothing())
10417 return Ret{};
10418 else
10419 return Ret{res.unsafe_get_just()()};
10420 }
10421
10422 // API search type: choose_def : (b, [(a, b)], a) -> b
10423 // fwd bind count: 1
10424 // Selects a value assigned to a key iff the key exists exactly once,
10425 // otherwise returns the given default value.
10426 // choose_def(c, [(1,a), (2,b)], 2) == b;
10427 // choose_def(c, [(1,a), (1,b)], 2) == c;
10428 // choose_def(c, [(1,a), (2,b)], 3) == c;
10429 template<typename Key, typename Val>
choose_def(const Val & def,const std::vector<std::pair<Key,Val>> & pairs,const Key & x)10430 Val choose_def(const Val& def,
10431 const std::vector<std::pair<Key, Val>>& pairs, const Key& x)
10432 {
10433 if (count(x, transform(fst<Key, Val>, pairs)) != 1)
10434 return def;
10435 return get_from_map_with_def(
10436 pairs_to_map<std::unordered_map<Key, Val>>(pairs), def, x);
10437 }
10438
10439 // API search type: choose_by_def : (b, [((a -> Bool), b)], a) -> b
10440 // fwd bind count: 2
10441 // Iff exactly one predicate is fulfilled
10442 // the value assigned to this predicate is selected.
10443 // Otherwise the given default value is returned.
10444 // choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 2) == Just a;
10445 // choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 5) == Just b;
10446 // choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 1) == c;
10447 // choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 4) == c;
10448 template<typename Key, typename Val>
choose_by_def(const Val & def,const std::vector<std::pair<std::function<bool (const Key &)>,Val>> & pairs,const Key & x)10449 Val choose_by_def(const Val& def,
10450 const std::vector<std::pair<std::function<bool(const Key&)>, Val>>& pairs,
10451 const Key& x)
10452 {
10453 return just_with_default(def, choose_by(pairs, x));
10454 }
10455
10456 // API search type: choose_def_lazy : ((() -> b), [(a, (() -> b))], a) -> b
10457 // fwd bind count: 1
10458 // Evaluates a lazy value assigned to a key iff the key exists exactly once,
10459 // otherwise evaluates the given default lazy value.
10460 // choose_def_lazy(c, [(1,a), (2,b)], 2) == b();
10461 // choose_def_lazy(c, [(1,a), (1,b)], 2) == c();
10462 // choose_def_lazy(c, [(1,a), (2,b)], 3) == c();
10463 template <typename Key, typename ValStub>
choose_def_lazy(const ValStub & def,const std::vector<std::pair<Key,ValStub>> & pairs,const Key & x)10464 auto choose_def_lazy(const ValStub& def,
10465 const std::vector<std::pair<Key, ValStub>>& pairs,
10466 const Key& x)
10467 {
10468 return choose_def(def, pairs, x)();
10469 }
10470
10471 // API search type: choose_by_def_lazy : ((() -> b), [((a -> Bool), (() -> b))], a) -> b
10472 // fwd bind count: 2
10473 // Iff exactly one predicate is fulfilled
10474 // the value assigned to this predicate is evaluated.
10475 // Otherwise the given default value is evaluated and returned.
10476 // choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 2) == Just a();
10477 // choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 5) == Just b();
10478 // choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 1) == c();
10479 // choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 4) == c();
10480 template <typename Key, typename ValStub>
choose_by_def_lazy(const ValStub & def,const std::vector<std::pair<std::function<bool (const Key &)>,ValStub>> & pairs,const Key & x)10481 auto choose_by_def_lazy(
10482 const ValStub& def,
10483 const std::vector<std::pair<std::function<bool(const Key&)>, ValStub>>& pairs,
10484 const Key& x)
10485 {
10486 return choose_by_def(def, pairs, x)();
10487 }
10488
10489 } // namespace fplus
10490
10491 //
10492 // optimize.hpp
10493 //
10494
10495 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
10496 // https://github.com/Dobiasd/FunctionalPlus
10497 // Distributed under the Boost Software License, Version 1.0.
10498 // (See accompanying file LICENSE_1_0.txt or copy at
10499 // http://www.boost.org/LICENSE_1_0.txt)
10500
10501
10502
10503 //
10504 // transform.hpp
10505 //
10506
10507 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
10508 // https://github.com/Dobiasd/FunctionalPlus
10509 // Distributed under the Boost Software License, Version 1.0.
10510 // (See accompanying file LICENSE_1_0.txt or copy at
10511 // http://www.boost.org/LICENSE_1_0.txt)
10512
10513
10514
10515 //
10516 // split.hpp
10517 //
10518
10519 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
10520 // https://github.com/Dobiasd/FunctionalPlus
10521 // Distributed under the Boost Software License, Version 1.0.
10522 // (See accompanying file LICENSE_1_0.txt or copy at
10523 // http://www.boost.org/LICENSE_1_0.txt)
10524
10525
10526
10527
10528 //
10529 // internal/split.hpp
10530 //
10531
10532 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
10533 // https://github.com/Dobiasd/FunctionalPlus
10534 // Distributed under the Boost Software License, Version 1.0.
10535 // (See accompanying file LICENSE_1_0.txt or copy at
10536 // http://www.boost.org/LICENSE_1_0.txt)
10537
10538
10539 #include <iterator>
10540 #include <utility>
10541
10542
10543
10544 namespace fplus
10545 {
10546 namespace internal
10547 {
10548 template <typename GroupByCallable, typename F, typename ContainerIn>
group_on_labeled_impl(GroupByCallable group,F f,const ContainerIn & xs)10549 auto group_on_labeled_impl(GroupByCallable group, F f, const ContainerIn& xs)
10550 {
10551 const auto grouped = group(is_equal_by(f), xs);
10552 const auto attach_label = [f](const auto& g)
10553 {
10554 using std::begin;
10555 return std::make_pair(internal::invoke(f, *begin(g)), g);
10556 };
10557 return fplus::transform(attach_label, grouped);
10558 }
10559 }
10560 }
10561
10562 namespace fplus
10563 {
10564
10565 // API search type: group_by : (((a, a) -> Bool), [a]) -> [[a]]
10566 // fwd bind count: 1
10567 // Arrange the elements into groups using a given predicate.
10568 // Only groups of consecutive elements are formed.
10569 // For a version scanning the whole container see group_globally_by.
10570 // group_by((==), [1,2,2,2,3,2,2,4,5,5]) == [[1],[2,2,2],[3],[2,2],[4],[5,5]]
10571 // BinaryPredicate p is a (not neccessarily transitive) connectivity check.
10572 // O(n)
10573 template <typename BinaryPredicate, typename ContainerIn,
10574 typename ContainerOut = typename std::vector<ContainerIn>>
group_by(BinaryPredicate p,const ContainerIn & xs)10575 ContainerOut group_by(BinaryPredicate p, const ContainerIn& xs)
10576 {
10577 // ContainerOut is not deduced to
10578 // SameContNewType(ContainerIn, ContainerIn)
10579 // here, since ContainerIn could be a std::string.
10580 internal::check_binary_predicate_for_container<BinaryPredicate, ContainerIn>();
10581 static_assert(std::is_same<ContainerIn,
10582 typename ContainerOut::value_type>::value,
10583 "Containers do not match.");
10584 ContainerOut result;
10585 if (is_empty(xs))
10586 return result;
10587 typedef typename ContainerOut::value_type InnerContainerOut;
10588 *internal::get_back_inserter(result) = InnerContainerOut(1, xs.front());
10589 for (auto it = ++std::begin(xs); it != std::end(xs); ++it)
10590 {
10591 if (internal::invoke(p, result.back().back(), *it))
10592 *internal::get_back_inserter(result.back()) = *it;
10593 else
10594 *internal::get_back_inserter(result) = InnerContainerOut(1, *it);
10595 }
10596 return result;
10597 }
10598
10599 // API search type: group_on : ((a -> b), [a]) -> [[a]]
10600 // fwd bind count: 1
10601 // Arrange elements equal after applying a transformer into groups.
10602 // Only groups of consecutive elements are formed.
10603 // For a version scanning the whole container see group_globally_on.
10604 // group_on((mod 10), [12,22,34]) == [[12,22],[34]]
10605 // O(n)
10606 template <typename F, typename ContainerIn>
group_on(F f,const ContainerIn & xs)10607 auto group_on(F f, const ContainerIn& xs)
10608 {
10609 return group_by(is_equal_by(f), xs);
10610 }
10611
10612 // API search type: group_on_labeled : ((a -> b), [a]) -> [(b, [a])]
10613 // fwd bind count: 1
10614 // Arrange elements equal after applying a transformer into groups,
10615 // adding the transformation result as a label to the group.
10616 // Only groups of consecutive elements are formed.
10617 // For a version scanning the whole container see group_globally_on_labeled.
10618 // group_on_labeled((mod 10), [12,22,34]) == [(2,[12,22]), (4,[34])]
10619 // O(n)
10620 template <typename F, typename ContainerIn>
group_on_labeled(F f,const ContainerIn & xs)10621 auto group_on_labeled(F f, const ContainerIn& xs)
10622 {
10623 const auto group = [](auto f1, const auto& xs1)
10624 {
10625 return group_by(f1, xs1);
10626 };
10627
10628 return internal::group_on_labeled_impl(group, f, xs);
10629 }
10630
10631 // API search type: group : [a] -> [[a]]
10632 // fwd bind count: 0
10633 // Arrange equal elements into groups.
10634 // Only groups of consecutive elements are formed.
10635 // For a version scanning the whole container see group_globally.
10636 // group([1,2,2,2,3,2,2,4,5,5]) == [[1],[2,2,2],[3],[2,2],[4],[5,5]]
10637 // O(n)
10638 template <typename ContainerIn,
10639 typename ContainerOut = typename std::vector<ContainerIn>>
group(const ContainerIn & xs)10640 ContainerOut group(const ContainerIn& xs)
10641 {
10642 static_assert(std::is_same<ContainerIn,
10643 typename ContainerOut::value_type>::value,
10644 "Containers do not match.");
10645 typedef typename ContainerIn::value_type T;
10646 auto pred = [](const T& x, const T& y) { return x == y; };
10647 return group_by<decltype(pred), ContainerIn, ContainerOut>(pred, xs);
10648 }
10649
10650 // API search type: group_globally_by : (((a, a) -> Bool), [a]) -> [[a]]
10651 // fwd bind count: 1
10652 // Arrange equal elements into groups.
10653 // group_globally_by((==), [1,2,2,2,3,2,2,4,5,5])
10654 // == [[1],[2,2,2,2,2],[3],[4],[5,5]]
10655 // BinaryPredicate p is a
10656 // transitive (whenever p(x,y) and p(y,z), then also p(x,z)) equality check.
10657 // O(n^2)
10658 // If you need O(n*log(n)), sort and then use group_by
10659 template <typename BinaryPredicate, typename ContainerIn,
10660 typename ContainerOut = typename std::vector<ContainerIn>>
group_globally_by(BinaryPredicate p,const ContainerIn & xs)10661 ContainerOut group_globally_by(BinaryPredicate p, const ContainerIn& xs)
10662 {
10663 internal::check_binary_predicate_for_container<BinaryPredicate, ContainerIn>();
10664 static_assert(std::is_same<ContainerIn,
10665 typename ContainerOut::value_type>::value,
10666 "Containers do not match.");
10667 typedef typename ContainerOut::value_type InnerContainerOut;
10668 ContainerOut result;
10669 for (const auto& x : xs)
10670 {
10671 bool found = false;
10672 for (auto& ys : result)
10673 {
10674 if (internal::invoke(p, x, ys.back()))
10675 {
10676 *internal::get_back_inserter(ys) = x;
10677 found = true;
10678 break;
10679 }
10680 }
10681 if (!found)
10682 {
10683 *internal::get_back_inserter(result) = InnerContainerOut(1, x);
10684 }
10685 }
10686 return result;
10687 }
10688
10689 // API search type: group_globally_on : ((a -> b), [a]) -> [[a]]
10690 // fwd bind count: 1
10691 // Arrange elements equal after applying a transformer into groups.
10692 // group_globally_on((mod 10), [12,34,22]) == [[12,22],[34]]
10693 // O(n^2)
10694 // If you need O(n*log(n)), sort and then use group_on
10695 template <typename F, typename ContainerIn>
group_globally_on(F f,const ContainerIn & xs)10696 auto group_globally_on(F f, const ContainerIn& xs)
10697 {
10698 return group_globally_by(is_equal_by(f), xs);
10699 }
10700
10701 // API search type: group_globally_on_labeled : ((a -> b), [a]) -> [(b, [a])]
10702 // fwd bind count: 1
10703 // Arrange elements equal after applying a transformer into groups,
10704 // adding the transformation result as a label to the group.
10705 // group_globally_on_labeled((mod 10), [12,34,22]) == [(2,[12,22]),(4, [34])]
10706 // O(n^2)
10707 // If you need O(n*log(n)), sort and then use group_on_labeled
10708 template <typename F, typename ContainerIn>
group_globally_on_labeled(F f,const ContainerIn & xs)10709 auto group_globally_on_labeled(F f, const ContainerIn& xs)
10710 {
10711 const auto group = [](auto f1, const auto& xs1)
10712 {
10713 return group_globally_by(f1, xs1);
10714 };
10715
10716 return internal::group_on_labeled_impl(group, f, xs);
10717 }
10718
10719 // API search type: group_globally : [a] -> [[a]]
10720 // fwd bind count: 0
10721 // Arrange equal elements into groups.
10722 // group_globally([1,2,2,2,3,2,2,4,5,5]) == [[1],[2,2,2,2,2],[3],[4],[5,5]]
10723 // O(n^2)
10724 // If you need O(n*log(n)), sort and then use group
10725 template <typename ContainerIn,
10726 typename ContainerOut = typename std::vector<ContainerIn>>
group_globally(const ContainerIn & xs)10727 ContainerOut group_globally(const ContainerIn& xs)
10728 {
10729 static_assert(std::is_same<ContainerIn,
10730 typename ContainerOut::value_type>::value,
10731 "Containers do not match.");
10732 typedef typename ContainerIn::value_type T;
10733 auto pred = [](const T& x, const T& y) { return x == y; };
10734 return group_globally_by(pred, xs);
10735 }
10736
10737 // API search type: cluster_by : (((a, a) -> Bool), [a]) -> [[a]]
10738 // fwd bind count: 1
10739 // Groups connected components, stable regarding initial order.
10740 // cluster_by(\x y -> abs (y - x) <= 3), [2,3,6,4,12,11,20,23,8,4])
10741 // == [[2,3,6,4,12,11,8,4],[20,23]]
10742 // BinaryPredicate p is a connectivity check, being
10743 // a) commutative (p(x,y) = p(y,x))
10744 // b) reflexive (p(x,x) = true)
10745 // c) not neccessarily transitive, but can be
10746 // O(n^2), memory complexity also O(n^2)
10747 template <typename BinaryPredicate, typename ContainerIn,
10748 typename ContainerOut = typename std::vector<ContainerIn>>
cluster_by(BinaryPredicate p,const ContainerIn & xs)10749 ContainerOut cluster_by(BinaryPredicate p, const ContainerIn& xs)
10750 {
10751 internal::check_binary_predicate_for_container<BinaryPredicate, ContainerIn>();
10752 static_assert(std::is_same<ContainerIn,
10753 typename ContainerOut::value_type>::value,
10754 "Containers do not match.");
10755
10756 typedef std::vector<unsigned char> bools;
10757 bools zero_filled_row(size_of_cont(xs), 0);
10758
10759 // adjecency matrix
10760 typedef std::vector<bools> boolss;
10761 boolss adj_mat(size_of_cont(xs), zero_filled_row);
10762
10763 for (const auto& idx_and_val_y : enumerate(xs))
10764 {
10765 auto idx_y = idx_and_val_y.first;
10766 auto val_y = idx_and_val_y.second;
10767 for (const auto& idx_and_val_x : enumerate(xs))
10768 {
10769 auto idx_x = idx_and_val_x.first;
10770 auto val_x = idx_and_val_x.second;
10771 if (internal::invoke(p, val_y, val_x))
10772 {
10773 adj_mat[idx_y][idx_x] = 1;
10774 }
10775 }
10776 }
10777
10778 bools already_used = zero_filled_row;
10779 auto is_already_used = [&](std::size_t i) -> bool
10780 {
10781 return already_used[i] != 0;
10782 };
10783
10784 typedef std::vector<std::size_t> idxs;
10785 typedef std::vector<idxs> idxss;
10786
10787 auto bools_to_idxs = [](const bools& activations) -> idxs
10788 {
10789 auto unsigned_char_to_bool = [](unsigned char x)
10790 {
10791 return x != 0;
10792 };
10793 return find_all_idxs_by(unsigned_char_to_bool, activations);
10794 };
10795
10796 idxss idx_clusters;
10797 std::function<void(std::size_t)> process_idx = [&](std::size_t idx) -> void
10798 {
10799 auto connected_idxs = bools_to_idxs(adj_mat[idx]);
10800 auto new_connected_idxs = drop_if(is_already_used, connected_idxs);
10801 if (is_empty(new_connected_idxs))
10802 {
10803 return;
10804 }
10805 idx_clusters.back() = append(idx_clusters.back(), new_connected_idxs);
10806 for (const auto& new_idx : new_connected_idxs)
10807 {
10808 already_used[new_idx] = 1;
10809 }
10810 for (const auto& new_idx : new_connected_idxs)
10811 {
10812 process_idx(new_idx);
10813 }
10814 };
10815
10816 typedef typename ContainerOut::value_type InnerContainerOut;
10817
10818 for (const auto& idx : all_idxs(xs))
10819 {
10820 if (is_already_used(idx))
10821 {
10822 continue;
10823 }
10824 *internal::get_back_inserter(idx_clusters) = idxs();
10825 *internal::get_back_inserter(idx_clusters.back()) = idx;
10826 already_used[idx] = 1;
10827 process_idx(idx);
10828 }
10829
10830 typedef typename ContainerIn::value_type T;
10831
10832 auto idx_to_val = [&](std::size_t idx) -> T
10833 {
10834 return elem_at_idx(idx, xs);
10835 };
10836
10837 auto idxs_to_vals = [&](const idxs& val_idxs) -> InnerContainerOut
10838 {
10839 return transform_convert<InnerContainerOut>(idx_to_val, sort(val_idxs));
10840 };
10841
10842 return transform_convert<ContainerOut>(idxs_to_vals, idx_clusters);
10843 }
10844
10845 // API search type: split_by : ((a -> Bool), Bool, [a]) -> [[a]]
10846 // fwd bind count: 2
10847 // Split a sequence at every element fulfilling a predicate.
10848 // The splitting elements are discarded.
10849 // split_by(is_even, true, [1,3,2,2,5,5,3,6,7,9]) == [[1,3],[],[5,5,3],[7,9]]
10850 // also known as split_when
10851 // O(n)
10852 template <typename UnaryPredicate, typename ContainerIn,
10853 typename ContainerOut = typename std::vector<ContainerIn>>
split_by(UnaryPredicate pred,bool allow_empty,const ContainerIn & xs)10854 ContainerOut split_by
10855 (UnaryPredicate pred, bool allow_empty, const ContainerIn& xs)
10856 {
10857 internal::check_unary_predicate_for_container<UnaryPredicate, ContainerIn>();
10858 static_assert(std::is_same<ContainerIn,
10859 typename ContainerOut::value_type>::value,
10860 "Containers do not match.");
10861
10862 if (allow_empty && is_empty(xs))
10863 {
10864 return {{}};
10865 }
10866
10867 ContainerOut result;
10868 auto itOut = internal::get_back_inserter(result);
10869 auto start = std::begin(xs);
10870
10871 while (start != std::end(xs))
10872 {
10873 const auto stop = std::find_if(start, std::end(xs), pred);
10874 if (start != stop || allow_empty)
10875 {
10876 *itOut = { start, stop };
10877 }
10878 if (stop == std::end(xs))
10879 {
10880 break;
10881 }
10882 start = internal::add_to_iterator(stop);
10883 if (allow_empty && start == std::end(xs))
10884 {
10885 *itOut = typename ContainerOut::value_type();
10886 }
10887 }
10888 return result;
10889 }
10890
10891 // API search type: split_by_keep_separators : ((a -> Bool), [a]) -> [[a]]
10892 // fwd bind count: 1
10893 // Split a sequence at every element fulfilling a predicate.
10894 // The splitting elements are kept.
10895 // split_by_keep_separators(is_even, true, [1,3,2,2,5,5,3,6,7,9])
10896 // == [[1,3],[2],[2,5,5,3],[6,7,9]]
10897 // O(n)
10898 template <typename UnaryPredicate, typename ContainerIn,
10899 typename ContainerOut = typename std::vector<ContainerIn>>
split_by_keep_separators(UnaryPredicate pred,const ContainerIn & xs)10900 ContainerOut split_by_keep_separators
10901 (UnaryPredicate pred, const ContainerIn& xs)
10902 {
10903 internal::check_unary_predicate_for_container<UnaryPredicate, ContainerIn>();
10904 static_assert(std::is_same<ContainerIn,
10905 typename ContainerOut::value_type>::value,
10906 "Containers do not match.");
10907 ContainerOut result;
10908 if (is_empty(xs))
10909 return result;
10910 auto itOut = internal::get_back_inserter(result);
10911 auto start = std::begin(xs);
10912 while (start != std::end(xs))
10913 {
10914 const auto stop = std::find_if(
10915 internal::add_to_iterator(start), std::end(xs), pred);
10916 *itOut = { start, stop };
10917 if (stop == std::end(xs))
10918 {
10919 break;
10920 }
10921 start = stop;
10922 }
10923 return result;
10924 }
10925
10926 // API search type: split : (a, Bool, [a]) -> [[a]]
10927 // fwd bind count: 2
10928 // Split a sequence at every element equal to x.
10929 // The splitting elements are discarded.
10930 // split(0, true, [1,3,2,0,0,6,0,7,5]) == [[1,3,2],[],[6],[7,5]]
10931 // O(n)
10932 template <typename ContainerIn,
10933 typename T = typename ContainerIn::value_type>
split(const T & x,bool allow_empty,const ContainerIn & xs)10934 auto split(const T& x, bool allow_empty, const ContainerIn& xs)
10935 {
10936 return split_by(is_equal_to(x), allow_empty, xs);
10937 }
10938
10939 // API search type: split_one_of : ([a], Bool, [a]) -> [[a]]
10940 // fwd bind count: 2
10941 // Split a sequence at every element present in delimiters.
10942 // The splitting elements are discarded.
10943 // Also known as split_words_by_many.
10944 // split_one_of([0,3], true [1,3,2,0,0,6,0,7,5]) == [[1],[2],[],[6],[7,5]]
10945 // split_one_of(" o", false, "How are u?") == ["H","w","are","u?"]
10946 // O(n)
10947 template <typename ContainerIn,
10948 typename ContainerDelims>
split_one_of(const ContainerDelims delimiters,bool allow_empty,const ContainerIn & xs)10949 auto split_one_of(
10950 const ContainerDelims delimiters, bool allow_empty, const ContainerIn& xs)
10951 {
10952 const auto pred = [&](const typename ContainerIn::value_type& x) -> bool
10953 {
10954 return is_elem_of(x, delimiters);
10955 };
10956 return split_by(pred, allow_empty, xs);
10957 }
10958
10959 // API search type: split_keep_separators : ((a -> Bool), [a]) -> [[a]]
10960 // fwd bind count: 1
10961 // Split a sequence at every element equal to x.
10962 // The splitting elements are kept.
10963 // split_keep_separators(2, true, [1,3,2,2,5,5,3,2,7,9])
10964 // == [[1,3],[2],[2,5,5,3],[6,7,9]]
10965 // O(n)
10966 template <typename ContainerIn,
10967 typename T = typename ContainerIn::value_type>
split_keep_separators(const T & x,const ContainerIn & xs)10968 auto split_keep_separators(const T& x, const ContainerIn& xs)
10969 {
10970 return split_by_keep_separators(is_equal_to(x), xs);
10971 }
10972
10973 // API search type: split_at_idx : (Int, [a]) -> ([a], [a])
10974 // fwd bind count: 1
10975 // Split a sequence at a specific position.
10976 // split_at_idx(2, [0,1,2,3,4]) == ([0,1],[2,3,4])
10977 template <typename Container>
split_at_idx(std::size_t idx,const Container & xs)10978 std::pair<Container, Container> split_at_idx
10979 (std::size_t idx, const Container& xs)
10980 {
10981 assert(idx <= size_of_cont(xs));
10982 return make_pair(get_segment(0, idx, xs),
10983 get_segment(idx, size_of_cont(xs), xs));
10984 }
10985
10986 // API search type: insert_at_idx : (Int, a, [a]) -> [a]
10987 // fwd bind count: 2
10988 // Insert an element into a sequence at a specific position.
10989 // insert_at_idx(2, 0, [1,2,3,4]) == [1,2,0,3,4].
10990 template <typename Container,
10991 typename T = typename Container::value_type>
10992 Container insert_at_idx(std::size_t idx, const T& x, const Container& xs)
10993 {
10994 const auto splitted = split_at_idx(idx, xs);
10995 return concat(std::vector<Container>(
10996 {
10997 splitted.first,
10998 singleton_seq<T, Container>(x),
10999 splitted.second
11000 }));
11001 }
11002
11003 // API search type: partition : ((a -> Bool), [a]) -> ([a], [a])
11004 // fwd bind count: 1
11005 // Split a sequence into two groups.
11006 // The first group contains all elements fulfilling the predicate.
11007 // The second group contains the remaining elements.
11008 // partition(is_even, [0,1,1,3,7,2,3,4]) == ([0,2,4],[1,1,3,7,3])
11009 template <typename UnaryPredicate, typename Container>
partition(UnaryPredicate pred,const Container & xs)11010 std::pair<Container, Container> partition
11011 (UnaryPredicate pred, const Container& xs)
11012 {
11013 internal::check_unary_predicate_for_container<UnaryPredicate, Container>();
11014 Container matching;
11015 Container notMatching;
11016 auto itOutMatching = internal::get_back_inserter(matching);
11017 auto itOutNotMatching = internal::get_back_inserter(notMatching);
11018 for (const auto& x : xs)
11019 {
11020 if (internal::invoke(pred, x))
11021 *itOutMatching = x;
11022 else
11023 *itOutNotMatching = x;
11024 }
11025 return make_pair(matching, notMatching);
11026 }
11027
11028 // API search type: split_at_idxs : ([Int], [a]) -> [[a]]
11029 // fwd bind count: 1
11030 // Split a sequence at specific indices.
11031 // split_at_idxs([2,5], [0,1,2,3,4,5,6,7]) == [[0,1],[2,3,4],[5,6,7]]
11032 // split_at_idxs([2,5,5], [0,1,2,3,4,5,6,7]) == [[0,1],[2,3,4],[],[5,6,7]]
11033 template <typename ContainerIdxs, typename ContainerIn,
11034 typename ContainerOut = std::vector<ContainerIn>>
split_at_idxs(const ContainerIdxs & idxsIn,const ContainerIn & xs)11035 ContainerOut split_at_idxs(const ContainerIdxs& idxsIn, const ContainerIn& xs)
11036 {
11037 static_assert(std::is_same<typename ContainerIdxs::value_type, std::size_t>::value,
11038 "Indices must be std::size_t");
11039 static_assert(std::is_same<ContainerIn,
11040 typename ContainerOut::value_type>::value,
11041 "Containers do not match.");
11042 ContainerIdxs idxStartC = {0};
11043 ContainerIdxs idxEndC = {size_of_cont(xs)};
11044 std::vector<ContainerIdxs> containerIdxss = {idxStartC, idxsIn, idxEndC};
11045 auto idxs = concat(containerIdxss);
11046 auto idxsClean = sort(idxs);
11047 ContainerOut result;
11048 internal::prepare_container(result, size_of_cont(idxsClean) - 1);
11049 auto itOut = internal::get_back_inserter(result);
11050 auto idxPairs = overlapping_pairs(idxsClean);
11051 for (const auto& idxPair : idxPairs)
11052 {
11053 *itOut = get_segment(idxPair.first, idxPair.second, xs);
11054 }
11055 return result;
11056 }
11057
11058 // API search type: split_every : (Int, [a]) -> [[a]]
11059 // fwd bind count: 1
11060 // Split a sequence every n elements.
11061 // split_every(3, [0,1,2,3,4,5,6,7]) == [[0,1,2],[3,4,5],[6,7]]
11062 // Also known as chunk or chunks.
11063 template <typename ContainerIn,
11064 typename ContainerOut = std::vector<ContainerIn>>
split_every(std::size_t n,const ContainerIn & xs)11065 ContainerOut split_every(std::size_t n, const ContainerIn& xs)
11066 {
11067 return split_at_idxs<
11068 std::vector<std::size_t>,
11069 ContainerIn,
11070 ContainerOut>(
11071 numbers_step<std::size_t>(
11072 n, size_of_cont(xs), n),
11073 xs);
11074 }
11075
11076 // API search type: split_by_token : ([a], Bool, [a]) -> [[a]]
11077 // fwd bind count: 2
11078 // Split a sequence at every segment matching a token.
11079 // split_by_token(", ", true, "foo, bar, baz") == ["foo", "bar", "baz"]
11080 template <typename ContainerIn,
11081 typename ContainerOut = typename std::vector<ContainerIn>>
split_by_token(const ContainerIn & token,bool allow_empty,const ContainerIn & xs)11082 ContainerOut split_by_token(const ContainerIn& token,
11083 bool allow_empty, const ContainerIn& xs)
11084 {
11085 static_assert(std::is_same<ContainerIn,
11086 typename ContainerOut::value_type>::value,
11087 "Containers do not match.");
11088 const auto token_begins =
11089 find_all_instances_of_token_non_overlapping(token, xs);
11090 const auto token_ends =
11091 transform(add_to<std::size_t>(size_of_cont(token)), token_begins);
11092 assert(is_sorted(interweave(token_begins, token_ends)));
11093
11094 typedef std::vector<std::size_t> idx_vec;
11095 const auto segments = zip(
11096 fplus::append(idx_vec(1, 0), token_ends),
11097 fplus::append(token_begins, idx_vec(1, size_of_cont(xs))));
11098
11099 ContainerOut result;
11100 auto itOut = internal::get_back_inserter(result);
11101 for (const auto& segment : segments)
11102 {
11103 if (segment.first != segment.second || allow_empty)
11104 *itOut = get_segment(segment.first, segment.second, xs);
11105 }
11106 return result;
11107 }
11108
11109 // API search type: run_length_encode_by : (((a, a) -> Bool), [a]) -> [(Int, a)]
11110 // fwd bind count: 1
11111 // RLE using a specific binary predicate as equality check.
11112 // run_length_encode_by((==),[1,2,2,2,2,3,3,2)) == [(1,1),(4,2),(2,3),(1,2)]
11113 template <typename BinaryPredicate,
11114 typename ContainerIn,
11115 typename T = typename ContainerIn::value_type,
11116 typename ContainerOut =
11117 typename std::vector<std::pair<std::size_t, T>>>
run_length_encode_by(BinaryPredicate pred,const ContainerIn & xs)11118 ContainerOut run_length_encode_by(BinaryPredicate pred, const ContainerIn& xs)
11119 {
11120 internal::check_binary_predicate_for_container<BinaryPredicate, ContainerIn>();
11121 ContainerOut result;
11122 auto groups = group_by(pred, xs);
11123 auto group_to_pair = [](const ContainerIn& group) -> std::pair<std::size_t, T>
11124 {
11125 return std::make_pair(size_of_cont(group), group.front());
11126 };
11127 return transform(group_to_pair, groups);
11128 }
11129
11130 // API search type: run_length_encode : [a] -> [(Int, a)]
11131 // fwd bind count: 0
11132 // RLE.
11133 // run_length_encode([1,2,2,2,2,3,3,2)) == [(1,1),(4,2),(2,3),(1,2)]
11134 template <typename ContainerIn,
11135 typename T = typename ContainerIn::value_type>
run_length_encode(const ContainerIn & xs)11136 auto run_length_encode(const ContainerIn& xs)
11137 {
11138 return run_length_encode_by(is_equal<T>, xs);
11139 }
11140
11141 // API search type: run_length_decode : [(Int, a)] -> [a]
11142 // fwd bind count: 0
11143 // Inverse operation to run_length_encode.
11144 // run_length_decode([(1,1),(4,2),(2,3),(1,2)]) == [1,2,2,2,2,3,3,2)
11145 template <typename ContainerIn,
11146 typename Pair = typename ContainerIn::value_type,
11147 typename Cnt = typename Pair::first_type>
run_length_decode(const ContainerIn & pairs)11148 auto run_length_decode(const ContainerIn& pairs)
11149 {
11150 static_assert(std::is_convertible<Cnt, std::size_t>::value,
11151 "Count type must be convertible to std::size_t.");
11152 const auto pair_to_vec =
11153 [](const Pair& p)
11154 {
11155 return replicate(p.first, p.second);
11156 };
11157 return concat(transform(pair_to_vec, pairs));
11158 }
11159
11160 // API search type: span : ((a -> Bool), [a]) -> ([a], [a])
11161 // fwd bind count: 1
11162 // span, applied to a predicate p and a list xs,
11163 // returns a tuple where first element is longest prefix (possibly empty)
11164 // of xs of elements that satisfy p
11165 // and second element is the remainder of the list.
11166 // span(is_even, [0,2,4,5,6,7,8]) == ([0,2,4], [5,6,7,8])
11167 template <typename Container, typename UnaryPredicate>
span(UnaryPredicate pred,const Container & xs)11168 std::pair<Container, Container> span(UnaryPredicate pred, const Container& xs)
11169 {
11170 auto maybeIdx = find_first_idx_by(logical_not(pred), xs);
11171 return {
11172 take(just_with_default<std::size_t>(size_of_cont(xs), maybeIdx), xs),
11173 drop(just_with_default<std::size_t>(size_of_cont(xs), maybeIdx), xs)
11174 };
11175 }
11176
11177 // API search type: divvy : (Int, Int, [a]) -> [[a]]
11178 // fwd bind count: 2
11179 // Generates subsequences overlapping with a specific step.
11180 // divvy(5, 2, [0,1,2,3,4,5,6,7,8,9]) == [[0,1,2,3,4],[2,3,4,5,6],[4,5,6,7,8]]
11181 // divvy(length, 1, xs) is also known as aperture
11182 // divvy(1, step, xs) is also known as stride
11183 // (but withouts the nested lists in the result)
11184 template <typename ContainerIn,
11185 typename ContainerOut = std::vector<ContainerIn>>
divvy(std::size_t length,std::size_t step,const ContainerIn & xs)11186 ContainerOut divvy(std::size_t length, std::size_t step, const ContainerIn& xs)
11187 {
11188 assert(length > 0);
11189 assert(step > 0);
11190 const auto start_idxs =
11191 numbers_step<std::size_t>(
11192 0, size_of_cont(xs) - (length - 1), step);
11193
11194 ContainerOut result;
11195 internal::prepare_container(result, size_of_cont(start_idxs));
11196 auto itOut = internal::get_back_inserter(result);
11197
11198 for (const auto start_idx : start_idxs)
11199 {
11200 *itOut = get_segment(start_idx, start_idx + length, xs);
11201 }
11202 return result;
11203 }
11204
11205 // API search type: aperture : (Int, [a]) -> [[a]]
11206 // fwd bind count: 1
11207 // Generates overlapping subsequences.
11208 // aperture(5, [0,1,2,3,4,5,6]) == [[0,1,2,3,4],[1,2,3,4,5],[2,3,4,5,6]]
11209 template <typename ContainerIn,
11210 typename ContainerOut = std::vector<ContainerIn>>
aperture(std::size_t length,const ContainerIn & xs)11211 ContainerOut aperture(std::size_t length, const ContainerIn& xs)
11212 {
11213 assert(length > 0);
11214 const auto start_idxs =
11215 numbers<std::size_t>(
11216 0, size_of_cont(xs) - (length - 1));
11217
11218 ContainerOut result;
11219 internal::prepare_container(result, size_of_cont(start_idxs));
11220 auto itOut = internal::get_back_inserter(result);
11221
11222 for (const auto start_idx : start_idxs)
11223 {
11224 *itOut = get_segment(start_idx, start_idx + length, xs);
11225 }
11226 return result;
11227 }
11228
11229 // API search type: stride : (Int, [a]) -> [a]
11230 // fwd bind count: 1
11231 // Keeps every nth element.
11232 // stride(3, [0,1,2,3,4,5,6,7]) == [0,3,6]
11233 template <typename Container>
stride(std::size_t step,const Container & xs)11234 Container stride(std::size_t step, const Container& xs)
11235 {
11236 assert(step > 0);
11237 Container ys;
11238 auto it = internal::get_back_inserter<Container>(ys);
11239 auto it_in = std::begin(xs);
11240 std::size_t i = 0;
11241 const auto xs_size = size_of_cont(xs);
11242 while(it_in != std::end(xs))
11243 {
11244 *it = *it_in;
11245 std::size_t increment = std::min(step, xs_size - i);
11246 internal::advance_iterator(it_in, increment);
11247 i += increment;
11248 }
11249 return ys;
11250 }
11251
11252 // API search type: winsorize : (Float, [Float]) -> [Float]
11253 // fwd bind count: 1
11254 // Winsorizing
11255 // winsorize(0.1, [1,3,4,4,4,4,4,4,6,8]) == [3,3,4,4,4,4,4,4,6,6]
11256 template <typename Container>
winsorize(double trim_ratio,const Container & xs)11257 Container winsorize(double trim_ratio, const Container& xs)
11258 {
11259 if (size_of_cont(xs) < 2)
11260 {
11261 return xs;
11262 }
11263 trim_ratio = std::max(trim_ratio, 0.0);
11264 const auto xs_sorted = sort(xs);
11265 std::size_t amount =
11266 floor<double, std::size_t>(
11267 trim_ratio * static_cast<double>(size_of_cont(xs_sorted)));
11268 amount = std::min(size_of_cont(xs_sorted) / 2, amount);
11269 const auto parts = split_at_idxs(
11270 std::vector<std::size_t>({amount, size_of_cont(xs_sorted) - amount}),
11271 xs_sorted);
11272 assert(size_of_cont(parts) == 3);
11273 typedef typename Container::value_type T;
11274 if (is_empty(parts[1]))
11275 {
11276 return Container(size_of_cont(xs_sorted), median(xs_sorted));
11277 }
11278 else
11279 {
11280 const T lower = parts[1].front();
11281 const T upper = parts[1].back();
11282 const auto result = concat(std::vector<Container>({
11283 Container(amount, lower),
11284 parts[1],
11285 Container(amount, upper)}));
11286 assert(size_of_cont(result) == size_of_cont(xs_sorted));
11287 return result;
11288 }
11289 }
11290
11291 // API search type: separate_on : ((a -> b), [a]) -> [[a]]
11292 // fwd bind count: 1
11293 // Separate elements equal after applying a transformer into groups.
11294 // separate_on((mod 10), [12,22,34]) == [[12,34],[22]]
11295 template <typename F, typename ContainerIn,
11296 typename ContainerOut = typename std::vector<ContainerIn>>
separate_on(F f,const ContainerIn & xs)11297 ContainerOut separate_on(F f, const ContainerIn& xs)
11298 {
11299 static_assert(std::is_same<ContainerIn,
11300 typename ContainerOut::value_type>::value,
11301 "Containers do not match.");
11302
11303 ContainerOut result;
11304 if (is_empty(xs)) {
11305 return result;
11306 }
11307
11308 const auto groups = group_globally_on(f, xs);
11309 bool found = true;
11310 auto itOut = internal::get_back_inserter(result);
11311 std::size_t index = 0;
11312 while (found) {
11313 typename ContainerOut::value_type sub_result;
11314 found = false;
11315 auto itOutInner = internal::get_back_inserter(sub_result);
11316 for (auto& group: groups) {
11317 if (size_of_cont(group) > index)
11318 {
11319 *itOutInner = group[index];
11320 found = true;
11321 }
11322 }
11323 if (found) {
11324 *itOut = sub_result;
11325 ++index;
11326 }
11327 }
11328 return result;
11329 }
11330
11331 // API search type: separate : [a] -> [[a]]
11332 // fwd bind count: 0
11333 // Separate equal elements into groups.
11334 // separate([1, 2, 2, 3, 3, 4, 4, 4]) == [[1, 2, 3, 4], [2, 3, 4], [4]]
11335 template <typename ContainerIn,
11336 typename ContainerOut = typename std::vector<ContainerIn>>
separate(const ContainerIn & xs)11337 ContainerOut separate(const ContainerIn& xs)
11338 {
11339 static_assert(std::is_same<ContainerIn,
11340 typename ContainerOut::value_type>::value,
11341 "Containers do not match.");
11342 typedef typename ContainerIn::value_type T;
11343 return separate_on(identity<T>, xs);
11344 }
11345
11346 } // namespace fplus
11347
11348
11349 #include <algorithm>
11350 #include <future>
11351 #include <iterator>
11352 #include <mutex>
11353 #include <random>
11354
11355 namespace fplus
11356 {
11357
11358 // API search type: transform_with_idx : (((Int, a) -> b), [a]) -> [b]
11359 // fwd bind count: 1
11360 // Apply a function to every index and corresponding element of a sequence.
11361 // transform_with_idx(f, [6, 4, 7]) == [f(0, 6), f(1, 4), f(2, 7)]
11362 template <typename F, typename ContainerIn,
11363 typename ContainerOut = typename internal::same_cont_new_t_from_binary_f<
11364 ContainerIn, F, std::size_t, typename ContainerIn::value_type, 0>::type>
transform_with_idx(F f,const ContainerIn & xs)11365 ContainerOut transform_with_idx(F f, const ContainerIn& xs)
11366 {
11367 internal::trigger_static_asserts<internal::binary_function_tag, F>();
11368 ContainerOut ys;
11369 internal::prepare_container(ys, size_of_cont(xs));
11370 auto it = internal::get_back_inserter<ContainerOut>(ys);
11371 std::size_t idx = 0;
11372 for (const auto& x : xs)
11373 {
11374 *it = internal::invoke(f, idx++, x);
11375 }
11376 return ys;
11377 }
11378
11379 // API search type: transform_and_keep_justs : ((a -> Maybe b), [a]) -> [b]
11380 // fwd bind count: 1
11381 // Map function over values and drop resulting nothings.
11382 // Also known as filter_map.
11383 template <typename F, typename ContainerIn>
transform_and_keep_justs(F f,const ContainerIn & xs)11384 auto transform_and_keep_justs(F f, const ContainerIn& xs)
11385 {
11386 using X = typename ContainerIn::value_type;
11387 internal::
11388 trigger_static_asserts<internal::unary_function_tag, F, X>();
11389
11390 using ContainerOut = typename internal::same_cont_new_t<
11391 ContainerIn,
11392 typename std::decay_t<internal::invoke_result_t<F, X>>::type>::type;
11393
11394 auto transformed = transform(f, xs);
11395 return justs<decltype(transformed), ContainerOut>(transformed);
11396 }
11397
11398 // API search type: transform_and_keep_oks : ((a -> Result b), [a]) -> [b]
11399 // fwd bind count: 1
11400 // Map function over values and drop resulting errors.
11401 template <typename F, typename ContainerIn>
transform_and_keep_oks(F f,const ContainerIn & xs)11402 auto transform_and_keep_oks(F f, const ContainerIn& xs)
11403 {
11404 using X = typename ContainerIn::value_type;
11405 internal::
11406 trigger_static_asserts<internal::unary_function_tag, F, X>();
11407
11408 using ContainerOut = typename internal::same_cont_new_t<
11409 ContainerIn,
11410 typename std::decay_t<internal::invoke_result_t<F, X>>::ok_t>::type;
11411 auto transformed = transform(f, xs);
11412 return oks<decltype(transformed), ContainerOut>(transformed);
11413 }
11414
11415 // API search type: transform_and_concat : ((a -> [b]), [a]) -> [b]
11416 // fwd bind count: 1
11417 // Map function over values and concat results.
11418 // Also known as flat_map or concat_map.
11419 template <typename F, typename ContainerIn>
transform_and_concat(F f,const ContainerIn & xs)11420 auto transform_and_concat(F f, const ContainerIn& xs)
11421 {
11422 internal::trigger_static_asserts<internal::unary_function_tag, F, typename ContainerIn::value_type>();
11423 return concat(transform(f, xs));
11424 }
11425
11426 // API search type: replicate_elems : (Int, [a]) -> [a]
11427 // fwd bind count: 1
11428 // Replicate every element n times, concatenate the result.
11429 // replicate_elems(3, [1,2]) == [1, 1, 1, 2, 2, 2]
11430 template <typename Container>
replicate_elems(std::size_t n,const Container & xs)11431 Container replicate_elems(std::size_t n, const Container& xs)
11432 {
11433 typedef typename Container::value_type T;
11434 return transform_and_concat(bind_1st_of_2(replicate<T, Container>, n), xs);
11435 }
11436
11437 // API search type: interleave : [[a]] -> [a]
11438 // fwd bind count: 0
11439 // Return a sequence that contains elements from the provided sequences
11440 // in alternating order. If one list runs out of items,
11441 // appends the items from the remaining list.
11442 // interleave([[1,2,3],[4,5],[6,7,8]]) == [1,4,6,2,5,7,3,8]
11443 template <typename ContainerIn,
11444 typename ContainerOut = typename ContainerIn::value_type>
interleave(const ContainerIn & xss)11445 ContainerOut interleave(const ContainerIn& xss)
11446 {
11447 typedef typename ContainerIn::value_type inner_t;
11448 typedef std::vector<typename inner_t::const_iterator> its_t;
11449 const auto inner_cbegin = [](const inner_t& xs) { return xs.cbegin(); };
11450 const auto inner_cend = [](const inner_t& xs) { return xs.cend(); };
11451 auto it_pairs = zip(
11452 transform_convert<its_t>(inner_cbegin, xss),
11453 transform_convert<its_t>(inner_cend, xss));
11454
11455 ContainerOut result;
11456 const std::size_t length = sum(transform(size_of_cont<inner_t>, xss));
11457 internal::prepare_container(result, length);
11458 auto it_out = internal::get_back_inserter<ContainerOut>(result);
11459 bool still_appending = true;
11460 while (still_appending)
11461 {
11462 still_appending = false;
11463 for (auto& it_pair : it_pairs)
11464 {
11465 if (it_pair.first != it_pair.second)
11466 {
11467 *it_out = *it_pair.first;
11468 still_appending = true;
11469 ++it_pair.first;
11470 }
11471 }
11472 }
11473 return result;
11474 }
11475
11476 // API search type: transpose : [[a]] -> [[a]]
11477 // fwd bind count: 0
11478 // Transpose a nested sequence aka. table aka. two-dimensional matrix.
11479 // transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]
11480 // transpose([[1,2,3],[4,5],[7,8,9]]) == [[1,4,7],[2,5,8],[3,9]]
11481 template <typename Container>
transpose(const Container & rows)11482 Container transpose(const Container& rows)
11483 {
11484 if (is_empty(rows))
11485 {
11486 return {};
11487 }
11488 return split_every<typename Container::value_type, Container>(
11489 size_of_cont(rows), interleave(rows));
11490 }
11491
11492 namespace internal
11493 {
11494
11495 template <typename Container>
shuffle(internal::reuse_container_t,std::uint_fast32_t seed,Container && xs)11496 Container shuffle(internal::reuse_container_t,
11497 std::uint_fast32_t seed, Container&& xs)
11498 {
11499 std::mt19937 g(seed);
11500 std::shuffle(std::begin(xs), std::end(xs), g);
11501 return std::forward<Container>(xs);
11502 }
11503
11504 template <typename Container>
shuffle(internal::create_new_container_t,std::uint_fast32_t seed,const Container & xs)11505 Container shuffle(internal::create_new_container_t,
11506 std::uint_fast32_t seed, const Container& xs)
11507 {
11508 Container ys = xs;
11509 return internal::shuffle(internal::reuse_container_t(), seed, std::move(ys));
11510 }
11511
11512 } // namespace internal
11513
11514 // API search type: shuffle : (Int, [a]) -> [a]
11515 // fwd bind count: 1
11516 // Returns a randomly shuffled version of xs.
11517 // Example call: shuffle(std::mt19937::default_seed, xs);
11518 // Example call: shuffle(std::random_device()(), xs);
11519 template <typename Container>
shuffle(std::uint_fast32_t seed,Container && xs)11520 auto shuffle(std::uint_fast32_t seed, Container&& xs)
11521 {
11522 return(internal::shuffle(internal::can_reuse_v<Container>{},
11523 seed, std::forward<Container>(xs)));
11524 }
11525
11526 // API search type: sample : (Int, Int, [a]) -> [a]
11527 // fwd bind count: 2
11528 // Returns n random elements from xs without replacement.
11529 // n has to be smaller than or equal to the number of elements in xs.
11530 // Also known as rnd_select.
11531 // Example call: sample(std::mt19937::default_seed, 3, xs);
11532 // Example call: sample(std::random_device()(), 3, xs);
11533 template <typename Container>
sample(std::uint_fast32_t seed,std::size_t n,const Container & xs)11534 Container sample(std::uint_fast32_t seed, std::size_t n, const Container& xs)
11535 {
11536 assert(n <= size_of_cont(xs));
11537 return get_segment(0, n, shuffle(seed, xs));
11538 }
11539
11540 // API search type: random_element : (Int, [a]) -> a
11541 // fwd bind count: 1
11542 // Returns one random element from xs.
11543 // xs must be non-empty.
11544 // Example call: random_element(std::mt19937::default_seed, xs)
11545 // Example call: random_element(std::random_device()(), xs)
11546 // Also known as choice.
11547 template <typename Container>
random_element(std::uint_fast32_t seed,const Container & xs)11548 typename Container::value_type random_element(
11549 std::uint_fast32_t seed, const Container& xs)
11550 {
11551 assert(is_not_empty(xs));
11552 std::mt19937 gen(seed);
11553 std::uniform_int_distribution<std::size_t> dis(0, size_of_cont(xs) - 1);
11554 return elem_at_idx(dis(gen), xs);
11555 }
11556
11557 // API search type: random_elements : (Int, Int, [a]) -> a
11558 // fwd bind count: 2
11559 // Returns random elements from xs with replacement.
11560 // xs must be non-empty.
11561 // Example call: random_elements(std::mt19937::default_seed, 10, xs)
11562 // Example call: random_elements(std::random_device()(), 10, xs)
11563 template <typename Container>
random_elements(std::uint_fast32_t seed,std::size_t n,const Container & xs)11564 Container random_elements(
11565 std::uint_fast32_t seed, std::size_t n, const Container& xs)
11566 {
11567 assert(is_not_empty(xs));
11568 std::mt19937 gen(seed);
11569 std::uniform_int_distribution<std::size_t> dis(0, size_of_cont(xs) - 1);
11570 const auto draw = [&]() -> typename Container::value_type
11571 {
11572 return elem_at_idx(dis(gen), xs);
11573 };
11574 return generate<Container>(draw, n);
11575 }
11576
11577 // API search type: apply_functions : ([(a -> b)], a) -> [b]
11578 // fwd bind count: 1
11579 // Applies a list of functions to a value.
11580 template <typename FunctionContainer,
11581 typename F = typename FunctionContainer::value_type,
11582 typename FIn>
apply_functions(const FunctionContainer & functions,const FIn & x)11583 auto apply_functions(const FunctionContainer& functions, const FIn& x)
11584 {
11585 internal::trigger_static_asserts<internal::unary_function_tag, F, FIn>();
11586
11587 using FOut = std::decay_t<internal::invoke_result_t<F, FIn>>;
11588 using ContainerOut =
11589 typename internal::same_cont_new_t<FunctionContainer, FOut, 0>::type;
11590
11591 ContainerOut ys;
11592 internal::prepare_container(ys, size_of_cont(functions));
11593 auto it = internal::get_back_inserter<ContainerOut>(ys);
11594 for (const auto& f : functions)
11595 {
11596 *it = internal::invoke(f, x);
11597 }
11598 return ys;
11599 }
11600
11601 // API search type: apply_function_n_times : ((a -> a), Int, a) -> a
11602 // fwd bind count: 2
11603 // Applies a functional n times in a row.
11604 template <typename F, typename FIn>
apply_function_n_times(F f,std::size_t n,const FIn & x)11605 auto apply_function_n_times(F f, std::size_t n, const FIn& x)
11606 {
11607 internal::trigger_static_asserts<internal::unary_function_tag, F, FIn>();
11608 using FOut = std::decay_t<internal::invoke_result_t<F, FIn>>;
11609 static_assert(std::is_same<FOut, FIn>::value,
11610 "Input and output of F must be the same type.");
11611 if (n == 0)
11612 {
11613 return x;
11614 }
11615 FOut y = internal::invoke(f, x);
11616 for (std::size_t i = 1; i < n; ++i)
11617 {
11618 y = internal::invoke(f, y);
11619 }
11620 return y;
11621 }
11622
11623 // API search type: transform_parallelly : ((a -> b), [a]) -> [b]
11624 // fwd bind count: 1
11625 // transform_parallelly((*2), [1, 3, 4]) == [2, 6, 8]
11626 // Same as transform, but can utilize multiple CPUs by using std::launch::async.
11627 // Only makes sense if one run of the provided function
11628 // takes enough time to justify the synchronization overhead.
11629 // One thread per container element is spawned.
11630 // Check out transform_parallelly_n_threads to limit the number of threads.
11631 template <typename F, typename ContainerIn>
transform_parallelly(F f,const ContainerIn & xs)11632 auto transform_parallelly(F f, const ContainerIn& xs)
11633 {
11634 using ContainerOut = typename internal::
11635 same_cont_new_t_from_unary_f<ContainerIn, F, 0>::type;
11636 using X = typename ContainerIn::value_type;
11637 internal::trigger_static_asserts<internal::unary_function_tag, F, X>();
11638 auto handles = transform([&f](const X& x)
11639 {
11640 return std::async(std::launch::async, [&x, &f]()
11641 {
11642 return internal::invoke(f, x);
11643 });
11644 }, xs);
11645
11646 ContainerOut ys;
11647 internal::prepare_container(ys, size_of_cont(xs));
11648 auto it = internal::get_back_inserter<ContainerOut>(ys);
11649 for (auto& handle : handles)
11650 {
11651 *it = handle.get();
11652 }
11653 return ys;
11654 }
11655
11656 // API search type: transform_parallelly_n_threads : (Int, (a -> b), [a]) -> [b]
11657 // fwd bind count: 2
11658 // transform_parallelly_n_threads(4, (*2), [1, 3, 4]) == [2, 6, 8]
11659 // Same as transform, but uses n threads in parallel.
11660 // Only makes sense if one run of the provided function
11661 // takes enough time to justify the synchronization overhead.
11662 // Can be used for applying the MapReduce pattern.
11663 template <typename F, typename ContainerIn>
transform_parallelly_n_threads(std::size_t n,F f,const ContainerIn & xs)11664 auto transform_parallelly_n_threads(std::size_t n, F f, const ContainerIn& xs)
11665 {
11666 using ContainerOut = typename internal::
11667 same_cont_new_t_from_unary_f<ContainerIn, F, 0>::type;
11668 using X = typename ContainerIn::value_type;
11669 using Y = internal::invoke_result_t<F, X>;
11670 using x_ptr_t = const X*;
11671 auto queue = transform_convert<std::vector<x_ptr_t>>(
11672 [](const X& x) -> x_ptr_t
11673 {
11674 return &x;
11675 }, xs);
11676
11677 std::mutex queue_mutex;
11678 std::mutex thread_results_mutex;
11679 std::map<std::size_t, std::decay_t<Y>> thread_results;
11680 std::size_t queue_idx = 0;
11681
11682 const auto worker_func = [&]()
11683 {
11684 for (;;)
11685 {
11686 std::size_t idx = std::numeric_limits<std::size_t>::max();
11687 x_ptr_t x_ptr = nullptr;
11688 {
11689 std::lock_guard<std::mutex> queue_lock(queue_mutex);
11690 if (queue_idx == queue.size())
11691 {
11692 return;
11693 }
11694 idx = queue_idx;
11695 x_ptr = queue[idx];
11696 ++queue_idx;
11697 }
11698
11699 const auto y = internal::invoke(f, *x_ptr);
11700
11701 {
11702 std::lock_guard<std::mutex> thread_results_lock(
11703 thread_results_mutex);
11704 thread_results.insert(std::make_pair(idx, y));
11705 }
11706 }
11707 };
11708
11709 const auto create_thread = [&]() -> std::thread
11710 {
11711 return std::thread(worker_func);
11712 };
11713 auto threads = generate<std::vector<std::thread>>(create_thread, n);
11714
11715 for (auto& thread : threads)
11716 {
11717 thread.join();
11718 }
11719
11720 return get_map_values<decltype(thread_results), ContainerOut>(
11721 thread_results);
11722 }
11723
11724 // API search type: reduce_parallelly : (((a, a) -> a), a, [a]) -> a
11725 // fwd bind count: 2
11726 // reduce_parallelly((+), 0, [1, 2, 3]) == (0+1+2+3) == 6
11727 // Same as reduce, but can utilize multiple CPUs by using std::launch::async.
11728 // Combines the initial value and all elements of the sequence
11729 // using the given function in unspecified order.
11730 // The set of f, init and value_type should form a commutative monoid.
11731 // One thread per container element is spawned.
11732 // Check out reduce_parallelly_n_threads to limit the number of threads.
11733 template <typename F, typename Container>
reduce_parallelly(F f,const typename Container::value_type & init,const Container & xs)11734 typename Container::value_type reduce_parallelly(
11735 F f, const typename Container::value_type& init, const Container& xs)
11736 {
11737 if (is_empty(xs))
11738 {
11739 return init;
11740 }
11741 else if (size_of_cont(xs) == 1)
11742 {
11743 return internal::invoke(f, init, xs.front());
11744 }
11745 else
11746 {
11747 typedef typename Container::value_type T;
11748 const auto f_on_pair = [f](const std::pair<T, T>& p) -> T
11749 {
11750 return internal::invoke(f, p.first, p.second);
11751 };
11752 auto transform_result =
11753 transform_parallelly(f_on_pair, adjacent_pairs(xs));
11754 if (is_odd(size_of_cont(xs)))
11755 {
11756 transform_result.push_back(last(xs));
11757 }
11758 return reduce_parallelly(f, init, transform_result);
11759 }
11760 }
11761
11762 // API search type: reduce_parallelly_n_threads : (Int, ((a, a) -> a), a, [a]) -> a
11763 // fwd bind count: 3
11764 // reduce_parallelly_n_threads(2, (+), 0, [1, 2, 3]) == (0+1+2+3) == 6
11765 // Same as reduce, but can utilize multiple CPUs by using std::launch::async.
11766 // Combines the initial value and all elements of the sequence
11767 // using the given function in unspecified order.
11768 // The set of f, init and value_type should form a commutative monoid.
11769 template <typename F, typename Container>
reduce_parallelly_n_threads(std::size_t n,F f,const typename Container::value_type & init,const Container & xs)11770 typename Container::value_type reduce_parallelly_n_threads(
11771 std::size_t n,
11772 F f, const typename Container::value_type& init, const Container& xs)
11773 {
11774 if (is_empty(xs))
11775 {
11776 return init;
11777 }
11778 else if (size_of_cont(xs) == 1)
11779 {
11780 return internal::invoke(f, init, xs.front());
11781 }
11782 else
11783 {
11784 typedef typename Container::value_type T;
11785 const auto f_on_pair = [f](const std::pair<T, T>& p) -> T
11786 {
11787 return internal::invoke(f, p.first, p.second);
11788 };
11789 auto transform_result =
11790 transform_parallelly_n_threads(n, f_on_pair, adjacent_pairs(xs));
11791 if (is_odd(size_of_cont(xs)))
11792 {
11793 transform_result.push_back(last(xs));
11794 }
11795 return reduce_parallelly_n_threads(n, f, init, transform_result);
11796 }
11797 }
11798
11799 // API search type: reduce_1_parallelly : (((a, a) -> a), [a]) -> a
11800 // fwd bind count: 1
11801 // reduce_1_parallelly((+), [1, 2, 3]) == (1+2+3) == 6
11802 // Same as reduce_1, but can utilize multiple CPUs by using std::launch::async.
11803 // Joins all elements of the sequence using the given function
11804 // in unspecified order.
11805 // The set of f and value_type should form a commutative semigroup.
11806 // One thread per container element is spawned.
11807 // Check out reduce_1_parallelly_n_threads to limit the number of threads.
11808 template <typename F, typename Container>
reduce_1_parallelly(F f,const Container & xs)11809 typename Container::value_type reduce_1_parallelly(F f, const Container& xs)
11810 {
11811 assert(is_not_empty(xs));
11812 if (size_of_cont(xs) == 1)
11813 {
11814 return xs.front();
11815 }
11816 else
11817 {
11818 typedef typename Container::value_type T;
11819 const auto f_on_pair = [f](const std::pair<T, T>& p) -> T
11820 {
11821 return internal::invoke(f, p.first, p.second);
11822 };
11823 auto transform_result =
11824 transform_parallelly(f_on_pair, adjacent_pairs(xs));
11825 if (is_odd(size_of_cont(xs)))
11826 {
11827 transform_result.push_back(last(xs));
11828 }
11829 return reduce_1_parallelly(f, transform_result);
11830 }
11831 }
11832
11833 // API search type: reduce_1_parallelly_n_threads : (Int, ((a, a) -> a), [a]) -> a
11834 // fwd bind count: 2
11835 // reduce_1_parallelly_n_threads(2, (+), [1, 2, 3]) == (1+2+3) == 6
11836 // Same as reduce_1, but can utilize multiple CPUs by using std::launch::async.
11837 // Joins all elements of the sequence using the given function
11838 // in unspecified order.
11839 // The set of f and value_type should form a commutative semigroup.
11840 template <typename F, typename Container>
reduce_1_parallelly_n_threads(std::size_t n,F f,const Container & xs)11841 typename Container::value_type reduce_1_parallelly_n_threads(
11842 std::size_t n, F f, const Container& xs)
11843 {
11844 assert(is_not_empty(xs));
11845 if (size_of_cont(xs) == 1)
11846 {
11847 return xs.front();
11848 }
11849 else
11850 {
11851 typedef typename Container::value_type T;
11852 const auto f_on_pair = [f](const std::pair<T, T>& p) -> T
11853 {
11854 return internal::invoke(f, p.first, p.second);
11855 };
11856 auto transform_result =
11857 transform_parallelly_n_threads(n, f_on_pair, adjacent_pairs(xs));
11858 if (is_odd(size_of_cont(xs)))
11859 {
11860 transform_result.push_back(last(xs));
11861 }
11862 return reduce_1_parallelly_n_threads(n, f, transform_result);
11863 }
11864 }
11865
11866 // API search type: keep_if_parallelly : ((a -> Bool), [a]) -> [a]
11867 // fwd bind count: 1
11868 // Same as keep_if but using multiple threads.
11869 // Can be useful if calling the predicate takes some time.
11870 // keep_if_parallelly(is_even, [1, 2, 3, 2, 4, 5]) == [2, 2, 4]
11871 // One thread per container element is spawned.
11872 // Check out keep_if_parallelly_n_threads to limit the number of threads.
11873 template <typename Pred, typename Container>
keep_if_parallelly(Pred pred,const Container & xs)11874 Container keep_if_parallelly(Pred pred, const Container& xs)
11875 {
11876 // Avoid a temporary std::vector<bool>.
11877 const auto idxs = find_all_idxs_by(
11878 is_equal_to<std::uint8_t>(1),
11879 transform_parallelly([pred](const auto & x) -> std::uint8_t {
11880 return pred(x) ? 1 : 0;
11881 }, xs));
11882 return elems_at_idxs(idxs, xs);
11883 }
11884
11885 // API search type: keep_if_parallelly_n_threads : (Int, (a -> Bool), [a]) -> [a]
11886 // fwd bind count: 2
11887 // Same as keep_if but using multiple threads.
11888 // Can be useful if calling the predicate takes some time.
11889 // keep_if_parallelly_n_threads(3, is_even, [1, 2, 3, 2, 4, 5]) == [2, 2, 4]
11890 template <typename Pred, typename Container>
keep_if_parallelly_n_threads(std::size_t n,Pred pred,const Container & xs)11891 Container keep_if_parallelly_n_threads(
11892 std::size_t n, Pred pred, const Container& xs)
11893 {
11894 // Avoid a temporary std::vector<bool>.
11895 const auto idxs = find_all_idxs_by(
11896 is_equal_to<std::uint8_t>(1),
11897 transform_parallelly_n_threads(n, [pred](const auto & x) -> std::uint8_t {
11898 return pred(x) ? 1 : 0;
11899 }, xs));
11900 return elems_at_idxs(idxs, xs);
11901 }
11902
11903 // API search type: transform_reduce : ((a -> b), ((b, b) -> b), b, [a]) -> b
11904 // fwd bind count: 3
11905 // transform_reduce(square, add, 0, [1,2,3]) == 0+1+4+9 = 14
11906 // The set of binary_f, init and unary_f::output should form a
11907 // commutative monoid.
11908 template <typename UnaryF, typename BinaryF, typename Container, typename Acc>
transform_reduce(UnaryF unary_f,BinaryF binary_f,const Acc & init,const Container & xs)11909 auto transform_reduce(UnaryF unary_f,
11910 BinaryF binary_f,
11911 const Acc& init,
11912 const Container& xs)
11913 {
11914 return reduce(binary_f, init, transform(unary_f, xs));
11915 }
11916
11917 // API search type: transform_reduce_1 : ((a -> b), ((b, b) -> b), [a]) -> b
11918 // fwd bind count: 2
11919 // transform_reduce_1(square, add, [1,2,3]) == 0+1+4+9 = 14
11920 // The set of binary_f, and unary_f::output should form
11921 // a commutative semigroup.
11922 template <typename UnaryF, typename BinaryF, typename Container>
transform_reduce_1(UnaryF unary_f,BinaryF binary_f,const Container & xs)11923 auto transform_reduce_1(UnaryF unary_f, BinaryF binary_f, const Container& xs)
11924 {
11925 return reduce_1(binary_f, transform(unary_f, xs));
11926 }
11927
11928 // API search type: transform_reduce_parallelly : ((a -> b), ((b, b) -> b), b, [a]) -> b
11929 // fwd bind count: 3
11930 // transform_reduce_parallelly(square, add, 0, [1,2,3]) == 0+1+4+9 = 14
11931 // Also known as map_reduce.
11932 // The set of binary_f, init and unary_f::output
11933 // should form a commutative monoid.
11934 // One thread per container element is spawned.
11935 // Check out transform_reduce_parallelly_n_threads to limit the number of threads.
11936 template <typename UnaryF, typename BinaryF, typename Container, typename Acc>
transform_reduce_parallelly(UnaryF unary_f,BinaryF binary_f,const Acc & init,const Container & xs)11937 auto transform_reduce_parallelly(UnaryF unary_f,
11938 BinaryF binary_f,
11939 const Acc& init,
11940 const Container& xs)
11941 {
11942 return reduce_parallelly(binary_f, init, transform_parallelly(unary_f, xs));
11943 }
11944
11945 // API search type: transform_reduce_parallelly_n_threads : (Int, (a -> b), ((b, b) -> b), b, [a]) -> b
11946 // fwd bind count: 4
11947 // transform_reduce_parallelly_n_threads(2, square, add, 0, [1,2,3]) == 0+1+4+9 = 14
11948 // Also known as map_reduce.
11949 // The set of binary_f, init and unary_f::output
11950 // should form a commutative monoid.
11951 template <typename UnaryF, typename BinaryF, typename Container, typename Acc>
transform_reduce_parallelly_n_threads(std::size_t n,UnaryF unary_f,BinaryF binary_f,const Acc & init,const Container & xs)11952 auto transform_reduce_parallelly_n_threads(std::size_t n,
11953 UnaryF unary_f,
11954 BinaryF binary_f,
11955 const Acc& init,
11956 const Container& xs)
11957 {
11958 return reduce_parallelly_n_threads(
11959 n, binary_f, init, transform_parallelly_n_threads(n, unary_f, xs));
11960 }
11961
11962 // API search type: transform_reduce_1_parallelly : ((a -> b), ((b, b) -> b), [a]) -> b
11963 // fwd bind count: 2
11964 // transform_reduce_1_parallelly(square, add, [1,2,3]) == 0+1+4+9 = 14
11965 // Also Known as map_reduce.
11966 // The set of binary_f, and unary_f::output
11967 // should form a commutative semigroup.
11968 // One thread per container element is spawned.
11969 // Check out transform_reduce_1_parallelly_n_threads to limit the number of threads.
11970 template <typename UnaryF, typename BinaryF, typename Container>
transform_reduce_1_parallelly(UnaryF unary_f,BinaryF binary_f,const Container & xs)11971 auto transform_reduce_1_parallelly(UnaryF unary_f,
11972 BinaryF binary_f,
11973 const Container& xs)
11974 {
11975 return reduce_1_parallelly(binary_f, transform_parallelly(unary_f, xs));
11976 }
11977
11978 // API search type: transform_reduce_1_parallelly_n_threads : (Int, (a -> b), ((b, b) -> b), [a]) -> b
11979 // fwd bind count: 3
11980 // transform_reduce_1_parallelly_n_threads(2, square, add, [1,2,3]) == 0+1+4+9 = 14
11981 // Also Known as map_reduce.
11982 // The set of binary_f, and unary_f::output
11983 // should form a commutative semigroup.
11984 template <typename UnaryF, typename BinaryF, typename Container>
transform_reduce_1_parallelly_n_threads(std::size_t n,UnaryF unary_f,BinaryF binary_f,const Container & xs)11985 auto transform_reduce_1_parallelly_n_threads(std::size_t n,
11986 UnaryF unary_f,
11987 BinaryF binary_f,
11988 const Container& xs)
11989 {
11990 return reduce_1_parallelly_n_threads(
11991 n, binary_f, transform_parallelly_n_threads(n, unary_f, xs));
11992 }
11993
11994 } // namespace fplus
11995 #include <array>
11996 #include <chrono>
11997 #include <functional>
11998
11999 namespace fplus
12000 {
12001
12002 // Optimizes the initial position to the nearest local minimum
12003 // in regards to the objective_function
12004 // using numerical gradient descent based on the epsilon neighborhood.
12005 // momentum_conservation should be in [0, 1). A low value means much decay.
12006 // If no fixed step size is provided, each step advances by the length
12007 // of the gradient.
12008 // In both cases the step is scaled with a step factor, starting at 1.0.
12009 // If one iteration results in no further improvement,
12010 // the step factor is reduced by a factor of 0.5.
12011 // The callback is executed with
12012 // iteration, step factor, momentum and current position
12013 // after every iteration.
12014 // A initial step factor other than 1.0 in all dimensions
12015 // can be emulated by scaling ones objective function accordingly.
12016 // Optimization stops if one of the provided criteria is met.
12017 // minimize_downhill<1>(\x -> square(x[0] + 2), 0.0001, 0.01, {123})[0] == -2;
12018 template <std::size_t N, typename F, typename pos_t = std::array<double, N>>
minimize_downhill(F objective_function,double epsilon,const pos_t & init_pos,maybe<double> fixed_step_size=nothing<double> (),double momentum_conservation=0.5,double sufficing_value=std::numeric_limits<double>::lowest (),double min_step_factor=std::numeric_limits<double>::min (),std::size_t max_iterations=std::numeric_limits<std::size_t>::max (),long int max_milliseconds=std::numeric_limits<long int>::max (),const std::function<void (std::size_t,double,const pos_t &,const pos_t &)> & callback=std::function<void (std::size_t,double,const pos_t &,const pos_t &)> ())12019 pos_t minimize_downhill(
12020 F objective_function,
12021 double epsilon,
12022 const pos_t& init_pos,
12023 maybe<double> fixed_step_size = nothing<double>(),
12024 double momentum_conservation = 0.5,
12025 double sufficing_value = std::numeric_limits<double>::lowest(),
12026 double min_step_factor = std::numeric_limits<double>::min(),
12027 std::size_t max_iterations = std::numeric_limits<std::size_t>::max(),
12028 long int max_milliseconds = std::numeric_limits<long int>::max(),
12029 const std::function<
12030 void (std::size_t, double, const pos_t&, const pos_t&)>&
12031 callback =
12032 std::function<
12033 void (std::size_t, double, const pos_t&, const pos_t&)>())
12034 {
12035 std::size_t iteration = 0;
12036 double step_factor = 1.0;
12037 pos_t position = init_pos;
12038 double value = internal::invoke(objective_function, position);
12039
12040 const auto start_time = std::chrono::steady_clock::now();
12041 const auto is_done = [&]() -> bool
12042 {
12043 if (max_milliseconds != std::numeric_limits<long int>::max())
12044 {
12045 const auto current_time = std::chrono::steady_clock::now();
12046 const auto elapsed = current_time - start_time;
12047 const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
12048 if (elapsed_ms >= max_milliseconds)
12049 {
12050 return true;
12051 }
12052 }
12053 return
12054 iteration >= max_iterations ||
12055 step_factor <= min_step_factor ||
12056 value <= sufficing_value;
12057 };
12058
12059 const auto calc_gradient =
12060 [&](const pos_t& pos) -> pos_t
12061 {
12062 pos_t result;
12063 for (std::size_t dim = 0; dim < N; ++dim)
12064 {
12065 auto test_pos_1 = pos;
12066 auto test_pos_2 = pos;
12067 test_pos_1[dim] -= epsilon / 2.0;
12068 test_pos_2[dim] += epsilon / 2.0;
12069 const auto val_1 = internal::invoke(objective_function, test_pos_1);
12070 const auto val_2 = internal::invoke(objective_function, test_pos_2);
12071 result[dim] = (val_2 - val_1) / epsilon;
12072 }
12073 return result;
12074 };
12075
12076 const auto add = [](const pos_t& p1, const pos_t& p2) -> pos_t
12077 {
12078 pos_t result;
12079 for (std::size_t dim = 0; dim < N; ++dim)
12080 {
12081 result[dim] = p1[dim] + p2[dim];
12082 }
12083 return result;
12084 };
12085
12086 const auto multiply = [](const pos_t& p, double f) -> pos_t
12087 {
12088 pos_t result;
12089 for (std::size_t dim = 0; dim < N; ++dim)
12090 {
12091 result[dim] = p[dim] * f;
12092 }
12093 return result;
12094 };
12095
12096 const auto dist_to_origin = [](const pos_t& p) -> double
12097 {
12098 double acc = 0;
12099 for (std::size_t dim = 0; dim < N; ++dim)
12100 {
12101 acc += square(p[dim]);
12102 }
12103 return sqrt(acc);
12104 };
12105
12106 const auto normalize = [&](const pos_t& p) -> pos_t
12107 {
12108 return multiply(p, 1.0 / dist_to_origin(p));
12109 };
12110
12111 const auto null_vector = []() -> pos_t
12112 {
12113 pos_t result;
12114 for (std::size_t dim = 0; dim < N; ++dim)
12115 {
12116 result[dim] = 0;
12117 }
12118 return result;
12119 };
12120
12121 pos_t momentum = null_vector();
12122 while (!is_done())
12123 {
12124 auto new_momentum = multiply(momentum, momentum_conservation);
12125 pos_t gradient = calc_gradient(add(position, new_momentum));
12126 const auto inverse_gradient = multiply(gradient, -1.0);
12127
12128 auto new_momentum_add =
12129 is_nothing(fixed_step_size) ?
12130 inverse_gradient :
12131 multiply(
12132 normalize(inverse_gradient),
12133 fixed_step_size.unsafe_get_just());
12134
12135 new_momentum =
12136 multiply(
12137 add(new_momentum, new_momentum_add),
12138 step_factor);
12139 if (dist_to_origin(momentum) <= std::numeric_limits<double>::min() &&
12140 dist_to_origin(new_momentum) <= std::numeric_limits<double>::min())
12141 {
12142 break;
12143 }
12144 const auto new_position = add(position, new_momentum);
12145 const auto new_value = internal::invoke(objective_function, new_position);
12146 if (new_value >= value)
12147 {
12148 step_factor /= 2.0;
12149 }
12150 else
12151 {
12152 value = new_value;
12153 position = new_position;
12154 momentum = new_momentum;
12155 }
12156 ++iteration;
12157 if (callback)
12158 {
12159 callback(iteration, step_factor, momentum, position);
12160 }
12161 }
12162 return position;
12163 }
12164
12165 } // namespace fplus
12166
12167 //
12168 // queue.hpp
12169 //
12170
12171 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12172 // https://github.com/Dobiasd/FunctionalPlus
12173 // Distributed under the Boost Software License, Version 1.0.
12174 // (See accompanying file LICENSE_1_0.txt or copy at
12175 // http://www.boost.org/LICENSE_1_0.txt)
12176
12177
12178
12179 #include <condition_variable>
12180 #include <cstdint>
12181 #include <deque>
12182 #include <mutex>
12183
12184 namespace fplus
12185 {
12186
12187 // A thread-safe queue.
12188 template <typename T>
12189 class queue
12190 {
12191 public:
queue()12192 queue() :
12193 queue_(),
12194 mutex_(),
12195 cond_()
12196 {}
pop()12197 fplus::maybe<T> pop()
12198 {
12199 std::unique_lock<std::mutex> lock(mutex_);
12200 if (queue_.empty())
12201 {
12202 return {};
12203 }
12204 auto item = queue_.front();
12205 queue_.pop_front();
12206 return item;
12207 }
12208
push(const T & item)12209 void push(const T& item)
12210 {
12211 {
12212 std::unique_lock<std::mutex> lock(mutex_);
12213 queue_.push_back(item);
12214 }
12215 cond_.notify_one();
12216 }
12217
pop_all()12218 std::vector<T> pop_all()
12219 {
12220 std::unique_lock<std::mutex> mlock(mutex_);
12221 const auto result = fplus::convert_container<std::vector<T>>(queue_);
12222 queue_.clear();
12223 return result;
12224 }
12225
wait_and_pop_all()12226 std::vector<T> wait_and_pop_all()
12227 {
12228 std::unique_lock<std::mutex> mlock(mutex_);
12229 cond_.wait(mlock, [&]() -> bool { return !queue_.empty(); });
12230 const auto result = fplus::convert_container<std::vector<T>>(queue_);
12231 queue_.clear();
12232 return result;
12233 }
12234
wait_for_and_pop_all(std::int64_t max_wait_time_us)12235 std::vector<T> wait_for_and_pop_all(std::int64_t max_wait_time_us)
12236 {
12237 std::unique_lock<std::mutex> mlock(mutex_);
12238 const auto t = std::chrono::microseconds{ max_wait_time_us };
12239 cond_.wait_for(mlock, t, [&]() -> bool { return !queue_.empty(); });
12240 const auto result = fplus::convert_container<std::vector<T>>(queue_);
12241 queue_.clear();
12242 return result;
12243 }
12244
12245 private:
12246 std::deque<T> queue_;
12247 std::mutex mutex_;
12248 std::condition_variable cond_;
12249 };
12250
12251 } // namespace fplus
12252
12253 //
12254 // raii.hpp
12255 //
12256
12257 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12258 // https://github.com/Dobiasd/FunctionalPlus
12259 // Distributed under the Boost Software License, Version 1.0.
12260 // (See accompanying file LICENSE_1_0.txt or copy at
12261 // http://www.boost.org/LICENSE_1_0.txt)
12262
12263
12264
12265 //
12266 // shared_ref.hpp
12267 //
12268
12269 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12270 // https://github.com/Dobiasd/FunctionalPlus
12271 // Distributed under the Boost Software License, Version 1.0.
12272 // (See accompanying file LICENSE_1_0.txt or copy at
12273 // http://www.boost.org/LICENSE_1_0.txt)
12274
12275
12276 #include <memory>
12277
12278 namespace fplus
12279 {
12280
12281 // A std::shared_ptr expresses
12282 // optionality of the contained value (can be nullptr)
12283 // and shared ownership that can be transferred.
12284 // A std::optional expresses optionality only.
12285 // The standard does not provide a class to
12286 // express only shared ownership without optionality.
12287 // shared_ref fills this gap.
12288 // It is recommended to use make_shared_ref for constructing an instance.
12289 template <typename T>
12290 class shared_ref
12291 {
12292 public:
12293 shared_ref(const shared_ref&) = default;
12294 shared_ref(shared_ref&&) = default;
12295 shared_ref& operator=(const shared_ref&) = default;
12296 shared_ref& operator=(shared_ref&&) = default;
12297 ~shared_ref() = default;
12298
operator ->()12299 T* operator->() { return m_ptr.get(); }
operator ->() const12300 const T* operator->() const { return m_ptr.get(); }
12301
operator *()12302 T& operator*() { return *m_ptr.get(); }
operator *() const12303 const T& operator*() const { return *m_ptr.get(); }
12304
12305 template <typename XT, typename...XTypes>
12306 friend shared_ref<XT> make_shared_ref(XTypes&&...args);
12307
12308 private:
12309 std::shared_ptr<T> m_ptr;
shared_ref(T * value)12310 shared_ref(T* value) :m_ptr(value) { assert(value != nullptr); }
12311 };
12312
12313 // http://stackoverflow.com/a/41976419/1866775
12314 template <typename T, typename...Types>
make_shared_ref(Types &&...args)12315 shared_ref<T> make_shared_ref(Types&&...args)
12316 {
12317 return shared_ref<T>(new T(std::forward<Types>(args)...));
12318 }
12319
12320 } // namespace fplus
12321
12322 namespace fplus
12323 {
12324
12325 // A generic RAII class.
12326 // It is recommended to use make_raii for constructing an instance.
12327 template <typename INIT, typename QUIT>
12328 class raii
12329 {
12330 public:
raii(INIT init,QUIT quit)12331 raii(INIT init, QUIT quit) :
12332 quit_(quit)
12333 {
12334 init();
12335 }
~raii()12336 ~raii()
12337 {
12338 quit_();
12339 }
12340 raii(const raii&) = delete;
12341 raii(raii&&) = default;
12342 raii& operator=(const raii&) = delete;
12343 raii& operator=(raii&&) = default;
12344 private:
12345 QUIT quit_;
12346 };
12347
12348 template <typename INIT, typename QUIT>
make_raii(INIT init,QUIT quit)12349 shared_ref<raii<INIT, QUIT>> make_raii(INIT init, QUIT quit)
12350 {
12351 return make_shared_ref<raii<INIT, QUIT>>(init, quit);
12352 }
12353
12354
12355 } // namespace fplus
12356
12357 //
12358 // read.hpp
12359 //
12360
12361 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12362 // https://github.com/Dobiasd/FunctionalPlus
12363 // Distributed under the Boost Software License, Version 1.0.
12364 // (See accompanying file LICENSE_1_0.txt or copy at
12365 // http://www.boost.org/LICENSE_1_0.txt)
12366
12367
12368
12369 #include <string>
12370 #include <type_traits>
12371
12372 namespace fplus
12373 {
12374
12375 namespace internal
12376 {
12377 template <typename T>
12378 struct helper_read_value_struct {};
12379
12380 template <>
12381 struct helper_read_value_struct <int>
12382 {
readfplus::internal::helper_read_value_struct12383 static void read(const std::string& str,
12384 int& result, std::size_t& num_chars_used)
12385 {
12386 result = std::stoi(str, &num_chars_used);
12387 }
12388 };
12389
12390 template <>
12391 struct helper_read_value_struct <long>
12392 {
readfplus::internal::helper_read_value_struct12393 static void read(const std::string& str,
12394 long& result, std::size_t& num_chars_used)
12395 {
12396 result = std::stol(str, &num_chars_used);
12397 }
12398 };
12399
12400 template <>
12401 struct helper_read_value_struct <long long>
12402 {
readfplus::internal::helper_read_value_struct12403 static void read(const std::string& str,
12404 long long& result, std::size_t& num_chars_used)
12405 {
12406 result = std::stoll(str, &num_chars_used);
12407 }
12408 };
12409
12410 template <>
12411 struct helper_read_value_struct <unsigned int>
12412 {
readfplus::internal::helper_read_value_struct12413 static void read(const std::string& str,
12414 unsigned int& result, std::size_t& num_chars_used)
12415 {
12416 unsigned long result_u_l = std::stoul(str, &num_chars_used);
12417 result = static_cast<unsigned int>(result_u_l);
12418 }
12419 };
12420
12421 template <>
12422 struct helper_read_value_struct <unsigned long>
12423 {
readfplus::internal::helper_read_value_struct12424 static void read(const std::string& str,
12425 unsigned long& result, std::size_t& num_chars_used)
12426 {
12427 result = std::stoul(str, &num_chars_used);
12428 }
12429 };
12430
12431 template <>
12432 struct helper_read_value_struct <unsigned long long>
12433 {
readfplus::internal::helper_read_value_struct12434 static void read(const std::string& str,
12435 unsigned long long& result, std::size_t& num_chars_used)
12436 {
12437 result = std::stoull(str, &num_chars_used);
12438 }
12439 };
12440
12441 template <>
12442 struct helper_read_value_struct <float>
12443 {
readfplus::internal::helper_read_value_struct12444 static void read(const std::string& str,
12445 float& result, std::size_t& num_chars_used)
12446 {
12447 result = std::stof(str, &num_chars_used);
12448 }
12449 };
12450
12451 template <>
12452 struct helper_read_value_struct <double>
12453 {
readfplus::internal::helper_read_value_struct12454 static void read(const std::string& str,
12455 double& result, std::size_t& num_chars_used)
12456 {
12457 result = std::stod(str, &num_chars_used);
12458 }
12459 };
12460
12461 template <>
12462 struct helper_read_value_struct <long double>
12463 {
readfplus::internal::helper_read_value_struct12464 static void read(const std::string& str,
12465 long double& result, std::size_t& num_chars_used)
12466 {
12467 result = std::stold(str, &num_chars_used);
12468 }
12469 };
12470
12471 template <>
12472 struct helper_read_value_struct <std::string>
12473 {
readfplus::internal::helper_read_value_struct12474 static void read(const std::string& str,
12475 std::string& result, std::size_t& num_chars_used)
12476 {
12477 num_chars_used = str.size();
12478 result = str;
12479 }
12480 };
12481 }
12482
12483 // API search type: read_value_result : String -> Result a
12484 // Try to deserialize a value.
12485 template <typename T>
read_value_result(const std::string & str)12486 result<T, std::string> read_value_result(const std::string& str)
12487 {
12488 try
12489 {
12490 T result;
12491 std::size_t num_chars_used = 0;
12492 internal::helper_read_value_struct<T>::read(str,
12493 result, num_chars_used);
12494 if (num_chars_used != str.size())
12495 {
12496 return error<T>(std::string("String not fully parsable."));
12497 }
12498 return ok<T, std::string>(result);
12499 } catch(const std::invalid_argument& e) {
12500 return error<T, std::string>(e.what());
12501 } catch(const std::out_of_range& e) {
12502 return error<T, std::string>(e.what());
12503 }
12504 }
12505
12506 // API search type: read_value : String -> Maybe a
12507 // Try to deserialize/parse a value, e.g.:
12508 // String to Int
12509 // String to Float
12510 // String to Double
12511 // read_value<unsigned int>("42") == 42
12512 // etc.
12513 template <typename T>
read_value(const std::string & str)12514 maybe<T> read_value(const std::string& str)
12515 {
12516 return to_maybe(read_value_result<T>(str));
12517 }
12518
12519 // API search type: read_value_with_default : (a, String) -> a
12520 // fwd bind count: 1
12521 // Try to deserialize a value, return given default on failure, e.g.:
12522 // String to Int
12523 // String to Float
12524 // String to Double
12525 // read_value_with_default<unsigned int>(3, "42") == 42
12526 // read_value_with_default<unsigned int>(3, "") == 3
12527 // read_value_with_default<unsigned int>(3, "foo") == 3
12528 // etc.
12529 template <typename T>
read_value_with_default(const T & def,const std::string & str)12530 T read_value_with_default(const T& def, const std::string& str)
12531 {
12532 return just_with_default(def, to_maybe(read_value_result<T>(str)));
12533 }
12534
12535 // API search type: read_value_unsafe : String -> a
12536 // Try to deserialize a value, crash on failure, e.g.:
12537 // String to Int
12538 // String to Float
12539 // String to Double
12540 // read_value_unsafe<unsigned int>("42") == 42
12541 // read_value_unsafe<unsigned int>("") == crash
12542 // read_value_unsafe<unsigned int>("foo") == crash
12543 // See read_value and read_value_with_default for safe versions.
12544 // etc.
12545 template <typename T>
read_value_unsafe(const std::string & str)12546 T read_value_unsafe(const std::string& str)
12547 {
12548 return unsafe_get_just(to_maybe(read_value_result<T>(str)));
12549 }
12550
12551 } // namespace fplus
12552
12553 //
12554 // replace.hpp
12555 //
12556
12557 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12558 // https://github.com/Dobiasd/FunctionalPlus
12559 // Distributed under the Boost Software License, Version 1.0.
12560 // (See accompanying file LICENSE_1_0.txt or copy at
12561 // http://www.boost.org/LICENSE_1_0.txt)
12562
12563
12564
12565 namespace fplus
12566 {
12567
12568 namespace internal
12569 {
12570
12571 template <typename UnaryPredicate, typename T, typename Container>
replace_if(internal::reuse_container_t,UnaryPredicate p,const T & dest,Container && xs)12572 Container replace_if(internal::reuse_container_t,
12573 UnaryPredicate p, const T& dest, Container&& xs)
12574 {
12575 std::replace_if(std::begin(xs), std::end(xs), p, dest);
12576 return std::forward<Container>(xs);
12577 }
12578
12579 template <typename UnaryPredicate, typename T, typename Container>
replace_if(internal::create_new_container_t,UnaryPredicate p,const T & dest,const Container & xs)12580 Container replace_if(internal::create_new_container_t,
12581 UnaryPredicate p, const T& dest, const Container& xs)
12582 {
12583 Container ys = xs;
12584 return replace_if(internal::reuse_container_t(),
12585 p, dest, std::move(ys));
12586 }
12587
12588 } // namespace internal
12589
12590 // API search type: replace_if : ((a -> Bool), a, [a]) -> [a]
12591 // fwd bind count: 2
12592 // Replace every element fulfilling a predicate with a specific value.
12593 // replace_if(is_even, 0, [1, 3, 4, 6, 7]) == [1, 3, 0, 0, 7]
12594 template <typename UnaryPredicate, typename Container,
12595 typename ContainerOut = internal::remove_const_and_ref_t<Container>>
replace_if(UnaryPredicate p,const typename ContainerOut::value_type & dest,Container && xs)12596 ContainerOut replace_if(UnaryPredicate p,
12597 const typename ContainerOut::value_type& dest, Container&& xs)
12598 {
12599 return internal::replace_if(internal::can_reuse_v<Container>{},
12600 p, dest, std::forward<Container>(xs));
12601 }
12602
12603 namespace internal
12604 {
12605
12606 template <typename Container,
12607 typename T = typename Container::value_type>
12608 Container replace_elem_at_idx(internal::reuse_container_t,
12609 std::size_t idx, const T& dest, Container&& xs)
12610 {
12611 assert(idx < xs.size());
12612 auto it = std::begin(xs);
12613 advance_iterator(it, idx);
12614 *it = dest;
12615 return std::forward<Container>(xs);
12616 }
12617
12618 template <typename Container,
12619 typename T = typename Container::value_type>
12620 Container replace_elem_at_idx(internal::create_new_container_t,
12621 std::size_t idx, const T& dest, const Container& xs)
12622 {
12623 Container ys = xs;
12624 return replace_elem_at_idx(internal::reuse_container_t(),
12625 idx, dest, std::move(ys));
12626 }
12627
12628 } // namespace internal
12629
12630 // API search type: replace_elem_at_idx : (Int, a, [a]) -> [a]
12631 // fwd bind count: 2
12632 // Replace the element at a specific index.
12633 // replace_elem_at_idx(2, 0, [1, 3, 4, 4, 7]) == [1, 3, 0, 4, 7]
12634 template <typename Container,
12635 typename ContainerOut = internal::remove_const_and_ref_t<Container>,
12636 typename T = typename ContainerOut::value_type>
12637 ContainerOut replace_elem_at_idx(std::size_t idx, const T& dest,
12638 Container&& xs)
12639 {
12640 return internal::replace_elem_at_idx(internal::can_reuse_v<Container>{},
12641 idx, dest, std::forward<Container>(xs));
12642 }
12643
12644 // API search type: replace_elems : (a, a, [a]) -> [a]
12645 // fwd bind count: 2
12646 // Replace all elements matching source with dest.
12647 // replace_elems(4, 0, [1, 3, 4, 4, 7]) == [1, 3, 0, 0, 7]
12648 template <typename Container,
12649 typename ContainerOut = internal::remove_const_and_ref_t<Container>,
12650 typename T = typename ContainerOut::value_type>
12651 ContainerOut replace_elems(const T& source, const T& dest, Container&& xs)
12652 {
12653 return replace_if(bind_1st_of_2(is_equal<T>, source), dest, xs);
12654 }
12655
12656 // API search type: replace_tokens : ([a], [a], [a]) -> [a]
12657 // fwd bind count: 2
12658 // Replace all segments matching source with dest.
12659 // replace_tokens("haha", "hihi", "oh, hahaha!") == "oh, hihiha!"
12660 // replace_tokens("haha", "o", "oh, hahaha!") == "oh, oha!"
12661 template <typename Container>
replace_tokens(const Container & source,const Container & dest,const Container & xs)12662 Container replace_tokens
12663 (const Container& source, const Container& dest, const Container& xs)
12664 {
12665 auto splitted = split_by_token(source, true, xs);
12666 return join(dest, splitted);
12667 }
12668
12669 } // namespace fplus
12670
12671 //
12672 // show.hpp
12673 //
12674
12675 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12676 // https://github.com/Dobiasd/FunctionalPlus
12677 // Distributed under the Boost Software License, Version 1.0.
12678 // (See accompanying file LICENSE_1_0.txt or copy at
12679 // http://www.boost.org/LICENSE_1_0.txt)
12680
12681
12682
12683 #include <iomanip>
12684 #include <ios>
12685 #include <sstream>
12686 #include <string>
12687
12688 namespace fplus
12689 {
12690
12691 // API search type: show : a -> String
12692 // fwd bind count: 0
12693 // 42 -> "42"
12694 // Useful to simply show values, e.g.:
12695 // Int to String
12696 // Float to String
12697 // Double to String
12698 // Pair to String
12699 // std::vector<std::list<T>> to String
12700 // std::vector<T> to String
12701 template <typename T>
show(const T & x)12702 std::string show(const T& x)
12703 {
12704 std::ostringstream ss;
12705 ss << x;
12706 return ss.str();
12707 }
12708
12709 // string identity
12710 // "foo" -> "foo"
12711 inline
show(const std::string & str)12712 std::string show(const std::string& str)
12713 {
12714 return str;
12715 }
12716
12717 template <typename T, typename A>
12718 std::string show(const std::vector<T, A>& xs);
12719
12720 template <typename T, typename A>
12721 std::string show(const std::list<T, A>& xs);
12722
12723 // {1, "one"} -> "(1, one)"
12724 template <typename X, typename Y>
show(const std::pair<X,Y> & p)12725 std::string show(const std::pair<X, Y>& p)
12726 {
12727 return std::string("(") + show(p.first) + ", " + show(p.second) + ")";
12728 }
12729
12730 template <typename Container> std::string show_cont(const Container& xs);
12731
12732 template <typename T, typename A>
show(const std::vector<T,A> & xs)12733 std::string show(const std::vector<T, A>& xs)
12734 {
12735 return show_cont(xs);
12736 }
12737
12738 template <typename T, typename A>
show(const std::list<T,A> & xs)12739 std::string show(const std::list<T, A>& xs)
12740 {
12741 return show_cont(xs);
12742 }
12743
12744 template <typename T, typename A>
show(const std::set<T,A> & xs)12745 std::string show(const std::set<T, A>& xs)
12746 {
12747 return show_cont(xs);
12748 }
12749
12750 template <typename T, typename A>
show(const std::deque<T,A> & xs)12751 std::string show(const std::deque<T, A>& xs)
12752 {
12753 return show_cont(xs);
12754 }
12755
12756 // API search type: show_cont_with_frame_and_newlines : (String, String, String, [a], Int) -> String
12757 // fwd bind count: 3
12758 // show_cont_with_frame_and_newlines (",", "(", ")", [1, 2, 3, 4, 5], 2)
12759 // == "(1,2)
12760 // 3,4)
12761 // 5)"
12762 template <typename Container>
show_cont_with_frame_and_newlines(const std::string & separator,const std::string & prefix,const std::string & suffix,const Container & xs,std::size_t new_line_every_nth_elem)12763 std::string show_cont_with_frame_and_newlines(
12764 const std::string& separator,
12765 const std::string& prefix, const std::string& suffix,
12766 const Container& xs,
12767 std::size_t new_line_every_nth_elem )
12768 {
12769 std::vector<std::string> elemStrs;
12770 elemStrs.reserve(xs.size());
12771 if (new_line_every_nth_elem == 0)
12772 {
12773 for (const auto& x : xs)
12774 {
12775 elemStrs.push_back(show(x));
12776 }
12777 }
12778 else
12779 {
12780 std::size_t i = 0;
12781 std::string newline =
12782 std::string("\n") + std::string(prefix.size(), ' ');
12783 for (const auto& x : xs)
12784 {
12785 if ( i && i % new_line_every_nth_elem == 0)
12786 elemStrs.push_back(newline + show(x));
12787 else
12788 elemStrs.push_back(show(x));
12789 ++i;
12790 }
12791 }
12792 return prefix + join(separator, elemStrs) + suffix;
12793 }
12794
12795 // API search type: show_cont_with_frame : (String, String, String, [a]) -> String
12796 // fwd bind count: 3
12797 // show_cont_with_frame (" => ", "{", "}", [1, 2, 3]) == "{1 => 2 => 3}"
12798 template <typename Container>
show_cont_with_frame(const std::string & separator,const std::string & prefix,const std::string & suffix,const Container & xs)12799 std::string show_cont_with_frame(
12800 const std::string& separator,
12801 const std::string& prefix, const std::string& suffix,
12802 const Container& xs)
12803 {
12804 return
12805 show_cont_with_frame_and_newlines( separator, prefix, suffix, xs, 0);
12806 }
12807
12808 // API search type: show_cont_with : (String, [a]) -> String
12809 // fwd bind count: 1
12810 // show_cont_with( " - ", [1, 2, 3]) == "[1 - 2 - 3]"
12811 template <typename Container>
show_cont_with(const std::string & separator,const Container & xs)12812 std::string show_cont_with(const std::string& separator, const Container& xs)
12813 {
12814 return show_cont_with_frame(separator, "[", "]", xs);
12815 }
12816
12817 // API search type: show_cont : [a] -> String
12818 // fwd bind count: 0
12819 // show_cont [1, 2, 3] -> "[1, 2, 3]"
12820 // Can i.a show std::vector and std::map.
12821 template <typename Container>
show_cont(const Container & xs)12822 std::string show_cont(const Container& xs)
12823 {
12824 return show_cont_with(", ", xs);
12825 }
12826
12827 // API search type: show_maybe : Maybe a -> String
12828 // fwd bind count: 0
12829 // show_maybe(Just 42) -> "Just 42"
12830 template <typename T>
show_maybe(const maybe<T> & maybe)12831 std::string show_maybe(const maybe<T>& maybe)
12832 {
12833 if (is_nothing(maybe))
12834 return "Nothing";
12835 else
12836 return std::string("Just " + show(unsafe_get_just(maybe)));
12837 }
12838
12839 // API search type: show_result : Result a b -> String
12840 // fwd bind count: 0
12841 // show_result(Ok 42) -> "Ok 42"
12842 // show_result(Error "fail") -> "Error fail"
12843 template <typename Ok, typename Error>
show_result(const result<Ok,Error> & result)12844 std::string show_result(const result<Ok, Error>& result)
12845 {
12846 if (is_error(result))
12847 return std::string("Error " + show(unsafe_get_error(result)));
12848 else
12849 return std::string("Ok " + show(unsafe_get_ok(result)));
12850 }
12851
12852 // API search type: show_float : (Int, Int, Float) -> String
12853 // fwd bind count: 2
12854 // Can be used to show floating point values in a specific format
12855 // (Float to String, Double to String etc.)
12856 // Examples:
12857 // const double pi = 3.14159
12858 // show_float<double>(0, 3, pi) == "3.142"
12859 // show_float<double>(1, 3, pi) == "3.142"
12860 // show_float<double>(2, 3, pi) == "03.142"
12861 // show_float<double>(3, 3, pi) == "003.142"
12862 // show_float<double>(1, 2, pi) == "3.14"
12863 // show_float<double>(1, 4, pi) == "3.1416"
12864 // show_float<double>(1, 7, pi) == "3.1415900"
12865 // show_float<double>(0, 3, -pi) == "-3.142"
12866 // show_float<double>(1, 3, -pi) == "-3.142"
12867 // show_float<double>(2, 3, -pi) == "-3.142"
12868 // show_float<double>(3, 3, -pi) == "-03.142"
12869 // show_float<double>(4, 3, -pi) == "-003.142"
12870 // show_float<double>(0, 3, 0.142) == "0.142";
12871 // show_float<double>(1, 3, 0.142) == "0.142";
12872 // show_float<double>(2, 3, 0.142) == "00.142";
12873 // fill_left(8, ' ', show_float<double>(0, 3, -pi)) == " -3.142"
12874 template <typename T>
show_float(std::size_t min_left_chars,std::size_t right_char_count,const T & x)12875 std::string show_float(
12876 std::size_t min_left_chars, std::size_t right_char_count, const T& x)
12877 {
12878 bool is_negative = x < 0;
12879 std::size_t min_left_chars_final =
12880 is_negative && min_left_chars > 0
12881 ? min_left_chars - 1
12882 : min_left_chars;
12883 std::stringstream stream;
12884 stream
12885 << std::fixed
12886 << std::setprecision(static_cast<int>(right_char_count))
12887 << std::abs(x);
12888 std::string s = stream.str();
12889 std::size_t min_dest_length = min_left_chars_final + 1 + right_char_count;
12890 std::string result = fill_left('0', min_dest_length, s);
12891 if (is_negative)
12892 {
12893 result = std::string("-") + result;
12894 }
12895 return result;
12896 }
12897
12898 // API search type: show_float_fill_left : (Char, Int, Int, Float) -> String
12899 // fwd bind count: 3
12900 // Can be used to show floating point values in a specific precision
12901 // left-padded with some character.
12902 // (Float to String, Double to String etc.)
12903 // Examples:
12904 // const double pi = 3.14159
12905 // show_float_fill_left<double>(' ', 8, 3, pi) == " 3.142"
12906 // show_float_fill_left<double>(' ', 8, 6, pi) == "3.141590"
12907 // show_float_fill_left<double>(' ', 8, 3, -pi) == " -3.142"
12908 // show_float_fill_left<double>(' ', 2, 3, -pi) == "-3.142"
12909 template <typename T>
show_float_fill_left(const std::string::value_type & filler,std::size_t min_size,std::size_t right_char_count,const T & x)12910 std::string show_float_fill_left(const std::string::value_type& filler,
12911 std::size_t min_size, std::size_t right_char_count, const T& x)
12912 {
12913 return fill_left(filler, min_size, show_float<T>(0, right_char_count, x));
12914 }
12915
12916 // API search type: show_fill_left : (Char, Int, a) -> String
12917 // fwd bind count: 2
12918 // Convert some value to a string with left-padded with some character.
12919 // (Int to String etc.)
12920 // Examples:
12921 // show_fill_left<int>(' ', 4, 3) == " 3"
12922 // show_fill_left<int>('0', 4, 3) == "0003"
12923 // show_fill_left<int>(' ', 4, 12345) == "12345"
12924 template <typename T>
show_fill_left(const std::string::value_type & filler,std::size_t min_size,const T & x)12925 std::string show_fill_left(
12926 const std::string::value_type& filler, std::size_t min_size, const T& x)
12927 {
12928 return fill_left(filler, min_size, show<T>(x));
12929 }
12930
12931 // API search type: show_fill_right : (Char, Int, a) -> String
12932 // fwd bind count: 2
12933 // Convert some value to a string with left-padded with some character.
12934 // (Int to String etc.)
12935 // Examples:
12936 // show_fill_right<int>(' ', 4, 3) == "3 "
12937 // show_fill_right<int>(' ', 4, 12345) == "12345"
12938 template <typename T>
show_fill_right(const std::string::value_type & filler,std::size_t min_size,const T & x)12939 std::string show_fill_right(const std::string::value_type& filler,
12940 std::size_t min_size, const T& x)
12941 {
12942 return fill_right(filler, min_size, show<T>(x));
12943 }
12944
12945 } // namespace fplus
12946
12947 //
12948 // string_tools.hpp
12949 //
12950
12951 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
12952 // https://github.com/Dobiasd/FunctionalPlus
12953 // Distributed under the Boost Software License, Version 1.0.
12954 // (See accompanying file LICENSE_1_0.txt or copy at
12955 // http://www.boost.org/LICENSE_1_0.txt)
12956
12957
12958
12959 #include <cctype>
12960 #include <string>
12961 #include <locale>
12962
12963 namespace fplus
12964 {
12965
12966 // API search type: is_letter_or_digit : Char -> Bool
12967 // fwd bind count: 0
12968 // Is character alphanumerical?
12969 template <typename String>
is_letter_or_digit(const typename String::value_type & c)12970 bool is_letter_or_digit(const typename String::value_type& c)
12971 {
12972 return
12973 std::isdigit(static_cast<unsigned char>(c)) ||
12974 std::isalpha(static_cast<unsigned char>(c));
12975 }
12976
12977 // API search type: is_whitespace : Char -> Bool
12978 // fwd bind count: 0
12979 // Is character a whitespace.
12980 template <typename String>
is_whitespace(const typename String::value_type & c)12981 bool is_whitespace(const typename String::value_type& c)
12982 {
12983 return (c == 32 || is_in_interval(9, 14, static_cast<int>(c)));
12984 }
12985
12986 // API search type: is_line_break : Char -> Bool
12987 // fwd bind count: 0
12988 // Newline character ('\n')?
12989 template <typename String>
is_line_break(const typename String::value_type & c)12990 bool is_line_break(const typename String::value_type& c)
12991 {
12992 return c == '\n';
12993 }
12994
12995 // API search type: clean_newlines : String -> String
12996 // fwd bind count: 0
12997 // Replaces windows and mac newlines with linux newlines.
12998 template <typename String>
clean_newlines(const String & str)12999 String clean_newlines(const String& str)
13000 {
13001 return replace_elems('\r', '\n',
13002 replace_tokens(String("\r\n"), String("\n"), str));
13003 }
13004
13005 // API search type: split_words : (Bool, String) -> [String]
13006 // fwd bind count: 1
13007 // Splits a string by non-letter and non-digit characters.
13008 // split_words(false, "How are you?") == ["How", "are", "you"]
13009 template <typename String, typename ContainerOut = std::vector<String>>
split_words(const bool allowEmpty,const String & str)13010 ContainerOut split_words(const bool allowEmpty, const String& str)
13011 {
13012 return split_by(logical_not(is_letter_or_digit<String>), allowEmpty, str);
13013 }
13014
13015 // API search type: split_lines : (Bool, String) -> [String]
13016 // fwd bind count: 1
13017 // Splits a string by the found newlines.
13018 // split_lines(false, "Hi,\nhow are you?") == ["Hi,", "How are you"]
13019 template <typename String, typename ContainerOut = std::vector<String>>
split_lines(bool allowEmpty,const String & str)13020 ContainerOut split_lines(bool allowEmpty, const String& str)
13021 {
13022 return split_by(is_line_break<String>, allowEmpty, clean_newlines(str));
13023 }
13024
13025 // API search type: trim_whitespace_left : String -> String
13026 // fwd bind count: 0
13027 // trim_whitespace_left(" text ") == "text "
13028 template <typename String>
trim_whitespace_left(const String & str)13029 String trim_whitespace_left(const String& str)
13030 {
13031 return drop_while(is_whitespace<String>, str);
13032 }
13033
13034 // API search type: trim_whitespace_right : String -> String
13035 // fwd bind count: 0
13036 // Remove whitespace characters from the end of a string.
13037 // trim_whitespace_right(" text ") == " text"
13038 template <typename String>
trim_whitespace_right(const String & str)13039 String trim_whitespace_right(const String& str)
13040 {
13041 return trim_right_by(is_whitespace<String>, str);
13042 }
13043
13044 // API search type: trim_whitespace : String -> String
13045 // fwd bind count: 0
13046 // Remove whitespace characters from the beginning and the end of a string.
13047 // trim_whitespace(" text ") == "text"
13048 template <typename String>
trim_whitespace(const String & str)13049 String trim_whitespace(const String& str)
13050 {
13051 return trim_by(is_whitespace<String>, str);
13052 }
13053
13054 // API search type: to_lower_case : String -> String
13055 // fwd bind count: 0
13056 // Convert a string to lowercase characters.
13057 // to_lower_case("ChaRacTer&WorDs23") == "character&words23"
13058 template <typename String>
to_lower_case(const String & str)13059 String to_lower_case(const String& str)
13060 {
13061 typedef typename String::value_type Char;
13062 return transform([](Char c) -> Char
13063 {
13064 return static_cast<Char>(
13065 std::tolower(static_cast<unsigned char>(c)));
13066 }, str);
13067 }
13068
13069 // API search type: to_lower_case_loc : (Locale, String) -> String
13070 // fwd bind count: 1
13071 // Convert a string to lowercase characters using specified locale.
13072 // to_upper_case_loc(locale("ru_RU.utf8"), "cYrIlLiC КиРиЛлИцА") == "cyrillic кириллица"
13073 template <typename String>
to_lower_case_loc(const std::locale & lcl,const String & str)13074 String to_lower_case_loc(const std::locale &lcl, const String &str)
13075 {
13076 typedef typename String::value_type Char;
13077 return transform([&lcl](Char c) -> Char
13078 {
13079 return static_cast<Char>(
13080 std::tolower(c, lcl));
13081 }, str);
13082 }
13083
13084 // API search type: to_upper_case : String -> String
13085 // fwd bind count: 0
13086 // Convert a string to uppercase characters.
13087 // to_upper_case("ChaRacTer&WorDs34") == "CHARACTER&WORDS34"
13088 template <typename String>
to_upper_case(const String & str)13089 String to_upper_case(const String& str)
13090 {
13091 typedef typename String::value_type Char;
13092 return transform([](Char c) -> Char
13093 {
13094 return static_cast<Char>(
13095 std::toupper(static_cast<unsigned char>(c)));
13096 }, str);
13097 }
13098
13099 // API search type: to_upper_case_loc : (Locale, String) -> String
13100 // fwd bind count: 1
13101 // Convert a string to uppercase characters using specified locale.
13102 // to_upper_case_loc(locale("ru_RU.utf8"), "cYrIlLiC КиРиЛлИцА") == "CYRILLIC КИРИЛЛИЦА"
13103 template <typename String>
to_upper_case_loc(const std::locale & lcl,const String & str)13104 String to_upper_case_loc(const std::locale &lcl, const String &str)
13105 {
13106 typedef typename String::value_type Char;
13107 return transform([&lcl](Char c) -> Char
13108 {
13109 return static_cast<Char>(
13110 std::toupper(c, lcl));
13111 }, str);
13112 }
13113
13114 // API search type: to_string_fill_left : (Char, Int, a) -> String
13115 // fwd bind count: 2
13116 // Convert a type right-aligned string using a fill character.
13117 // to_string_fill_left('0', 5, 42) == "00042"
13118 // to_string_fill_left(' ', 5, 42) == " 42"
13119 template <typename T>
to_string_fill_left(const std::string::value_type & filler,std::size_t min_size,const T & x)13120 std::string to_string_fill_left(const std::string::value_type& filler,
13121 std::size_t min_size, const T& x)
13122 {
13123 return fill_left(filler, min_size, std::to_string(x));
13124 }
13125
13126 // API search type: to_string_fill_right : (Char, Int, a) -> String
13127 // fwd bind count: 2
13128 // Convert a type left-aligned string using a fill character.
13129 // to_string_fill_right(' ', 5, 42) == "42 "
13130 template <typename T>
to_string_fill_right(const std::string::value_type & filler,std::size_t min_size,const T & x)13131 std::string to_string_fill_right(const std::string::value_type& filler,
13132 std::size_t min_size, const T& x)
13133 {
13134 return fill_right(filler, min_size, std::to_string(x));
13135 }
13136
13137 } // namespace fplus
13138
13139 //
13140 // tree.hpp
13141 //
13142
13143 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
13144 // https://github.com/Dobiasd/FunctionalPlus
13145 // Distributed under the Boost Software License, Version 1.0.
13146 // (See accompanying file LICENSE_1_0.txt or copy at
13147 // http://www.boost.org/LICENSE_1_0.txt)
13148
13149
13150
13151 #include <vector>
13152 #include <queue>
13153
13154 namespace fplus
13155 {
13156
13157 template <typename T>
13158 struct tree
13159 {
treefplus::tree13160 tree (const T& value, const std::vector<tree<T>>& children) :
13161 value_(value), children_(children) {}
13162 T value_;
13163 std::vector<tree<T>> children_;
13164 };
13165
13166 namespace internal
13167 {
13168 template <typename T>
make_singleton_tree(const T & x)13169 tree<T> make_singleton_tree(const T& x)
13170 {
13171 return {x, {}};
13172 }
13173 } // namespace internal
13174
13175 namespace internal
13176 {
13177
13178 template <typename BinaryPredicate, typename T>
presort_trees(BinaryPredicate tree_is_child_of,std::vector<tree<T>> xs_orig)13179 std::vector<tree<T>> presort_trees(BinaryPredicate tree_is_child_of,
13180 std::vector<tree<T>> xs_orig)
13181 {
13182 auto xs = fplus::convert_container<std::list<tree<T>>>(xs_orig);
13183 std::vector<tree<T>> result;
13184 while (!xs.empty())
13185 {
13186 for (auto it = std::begin(xs); it != std::end(xs);)
13187 {
13188 bool has_children = false;
13189 for (auto it_rest = std::begin(xs); it_rest != std::end(xs); ++it_rest)
13190 {
13191 if (it_rest != it && tree_is_child_of(*it_rest, *it))
13192 {
13193 has_children = true;
13194 }
13195 }
13196 if (!has_children)
13197 {
13198 result.push_back(*it);
13199 it = xs.erase(it);
13200 }
13201 else
13202 {
13203 ++it;
13204 }
13205 }
13206 }
13207 return result;
13208 }
13209
13210 template <typename BinaryPredicate, typename TreeCont> // todo: name?
trees_from_sequence_helper(BinaryPredicate tree_is_child_of,TreeCont xs_unsorted)13211 TreeCont trees_from_sequence_helper(
13212 BinaryPredicate tree_is_child_of, TreeCont xs_unsorted)
13213 {
13214 TreeCont result;
13215 auto xs = presort_trees(tree_is_child_of, xs_unsorted);
13216 for (auto it = std::begin(xs); it != std::end(xs); ++it)
13217 {
13218 const auto find_pred = bind_1st_of_2(tree_is_child_of, *it);
13219 auto it_find_begin = it;
13220 internal::advance_iterator(it_find_begin, 1);
13221 auto parent_it = std::find_if(it_find_begin, std::end(xs), find_pred);
13222 if (parent_it != std::end(xs))
13223 {
13224 parent_it->children_.push_back(*it);
13225 }
13226 else
13227 {
13228 result.push_back(*it);
13229 }
13230 }
13231 return result;
13232 }
13233
13234 } // namespace internal
13235
13236 // API search type: trees_from_sequence : (((a, a) -> Bool), [a]) -> [Tree a]
13237 // fwd bind count: 1
13238 // Converts the sequence into a tree considering the given binary predicate.
13239 template <typename BinaryPredicate, typename Container> // todo: name?
trees_from_sequence(BinaryPredicate is_child_of,const Container & xs)13240 std::vector<tree<typename Container::value_type>> trees_from_sequence(
13241 BinaryPredicate is_child_of, const Container& xs)
13242 {
13243 internal::check_binary_predicate_for_container<BinaryPredicate, Container>();
13244 typedef typename Container::value_type T;
13245 typedef tree<T> Tree;
13246 const auto singletons = transform_convert<std::vector<Tree>>(
13247 internal::make_singleton_tree<T>, xs);
13248 const auto tree_is_child_of =
13249 [is_child_of](const tree<T>& a, const tree<T>& b) -> bool
13250 {
13251 return is_child_of(a.value_, b.value_);
13252 };
13253 return internal::trees_from_sequence_helper(
13254 tree_is_child_of, std::move(singletons));
13255 }
13256
13257 namespace internal
13258 {
13259
13260 // -1 = a < b
13261 // 0 = a == b
13262 // 1 = b < a
13263 template <typename T>
tree_cmp(const tree<T> & a,const tree<T> & b)13264 int tree_cmp(const tree<T>& a, const tree<T>& b)
13265 {
13266 if(a.value_ < b.value_)
13267 {
13268 return -1;
13269 }
13270 else if(b.value_ < a.value_)
13271 {
13272 return 1;
13273 }
13274 else
13275 {
13276 const auto results = zip_with(tree_cmp<T>,
13277 sort_by(tree_cmp<T>, a.children_),
13278 sort_by(tree_cmp<T>, b.children_));
13279 return just_with_default(0, find_first_by(
13280 bind_1st_of_2(is_not_equal<int>, 0),
13281 results));
13282 }
13283 }
13284
13285 template <typename T>
tree_less(const tree<T> & a,const tree<T> & b)13286 bool tree_less(const tree<T>& a, const tree<T>& b)
13287 {
13288 return tree_cmp(a, b) < 0;
13289 }
13290
13291 } // namespace internal
13292
13293 namespace internal
13294 {
13295
13296 template <typename T>
are_normalized_trees_equal(const tree<T> & a,const tree<T> & b)13297 bool are_normalized_trees_equal(const tree<T>& a, const tree<T>& b)
13298 {
13299 if (a.value_ != b.value_ || a.children_.size() != b.children_.size())
13300 {
13301 return false;
13302 }
13303 else
13304 {
13305 return all(zip_with(are_normalized_trees_equal<T>,
13306 a.children_, b.children_));
13307 }
13308 }
13309
13310 template <typename T>
normalize_tree(tree<T> x)13311 tree<T> normalize_tree(tree<T> x)
13312 {
13313 x.children_ = sort_by(
13314 internal::tree_less<T>,
13315 transform(normalize_tree<T>, x.children_));
13316 return x;
13317 }
13318
13319 } // namespace internal
13320
13321 // API search type: are_trees_equal : (Tree a, Tree a) -> Bool
13322 // fwd bind count: 1
13323 template <typename T>
are_trees_equal(const tree<T> & a,const tree<T> & b)13324 bool are_trees_equal(const tree<T>& a, const tree<T>& b)
13325 {
13326 return internal::are_normalized_trees_equal(
13327 internal::normalize_tree(a), internal::normalize_tree(b));
13328 }
13329
13330 // API search type: tree_size : Tree a -> Int
13331 // fwd bind count: 0
13332 // A tree with only one element (root) has size 1.
13333 template <typename T>
tree_size(const tree<T> & x)13334 std::size_t tree_size(const tree<T>& x)
13335 {
13336 return 1 + sum(transform(tree_size<T>, x.children_));
13337 }
13338
13339 // API search type: tree_depth : Tree a -> Int
13340 // fwd bind count: 0
13341 // A tree with only one element (root) has depth 1.
13342 template <typename T>
tree_depth(const tree<T> & x)13343 std::size_t tree_depth(const tree<T>& x)
13344 {
13345 return 1 + just_with_default<std::size_t>(0,
13346 maximum_maybe(transform(tree_depth<T>, x.children_)));
13347 }
13348
13349 // API search type: flatten_tree_depth_first : Tree a -> [a]
13350 // fwd bind count: 0
13351 template <typename T>
flatten_tree_depth_first(const tree<T> & x)13352 std::vector<T> flatten_tree_depth_first(const tree<T>& x)
13353 {
13354 return prepend_elem(x.value_,
13355 transform_and_concat(flatten_tree_depth_first<T>, x.children_));
13356 }
13357
13358 // API search type: flatten_tree_breadth_first : Tree a -> [a]
13359 // fwd bind count: 0
13360 template <typename T>
flatten_tree_breadth_first(const tree<T> & x)13361 std::vector<T> flatten_tree_breadth_first(const tree<T>& x)
13362 {
13363 std::vector<T> result;
13364 result.reserve(tree_size(x));
13365 std::queue<const tree<T>*> q;
13366 q.push(&x);
13367 while (!q.empty())
13368 {
13369 const auto current = q.front();
13370 q.pop();
13371 result.push_back(current->value_);
13372 for (const auto& c : current->children_)
13373 {
13374 q.push(&c);
13375 }
13376 }
13377 return result;
13378 }
13379
13380 } // namespace fplus
13381
13382 //
13383 // side_effects.hpp
13384 //
13385
13386 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
13387 // https://github.com/Dobiasd/FunctionalPlus
13388 // Distributed under the Boost Software License, Version 1.0.
13389 // (See accompanying file LICENSE_1_0.txt or copy at
13390 // http://www.boost.org/LICENSE_1_0.txt)
13391
13392
13393
13394 #include <atomic>
13395 #include <chrono>
13396 #include <condition_variable>
13397 #include <cstdint>
13398 #include <fstream>
13399 #include <functional>
13400 #include <future>
13401 #include <iostream>
13402 #include <iterator>
13403 #include <streambuf>
13404 #include <string>
13405 #include <thread>
13406 #include <vector>
13407
13408 namespace fplus
13409 {
13410
13411 // Executes a function f in a fixed interval,
13412 // i.e. an average timespan between two consecutive calls of f,
13413 // given in microseconds.
13414 // f is a unary function, taking the time delta (in microseconds)
13415 // between the last and the current call as its argument.
13416 // In case of a delay outdated calls are be executed immediately.
13417 // So the average executation time of f should be way shorter
13418 // than the requested interval.
13419 // Call ticker::start() to run.
13420 // The ticker stops when ticker::stop() is called
13421 // or the instance runs out of scope.
13422 //
13423 // Example usage:
13424 //
13425 // void say_hi(std::int64_t)
13426 // {
13427 // std::cout << "hi " << std::endl;
13428 // }
13429 // int main()
13430 // {
13431 // ticker hi_ticker(say_hi, 2 * 1000 * 1000);
13432 // hi_ticker.start();
13433 // std::this_thread::sleep_for(std::chrono::milliseconds(4500));
13434 // }
13435 class ticker
13436 {
13437 public:
13438 typedef std::function<void(std::int64_t)> function;
ticker(const function & f,std::int64_t interval_us)13439 ticker(const function& f, std::int64_t interval_us) :
13440 f_(f),
13441 interval_us_(interval_us),
13442 control_mutex_(),
13443 is_running_(false),
13444 thread_(),
13445 stop_mutex_()
13446 {
13447 }
is_running()13448 bool is_running()
13449 {
13450 std::lock_guard<std::mutex> lock(control_mutex_);
13451 return is_running_;
13452 }
start()13453 bool start()
13454 {
13455 std::lock_guard<std::mutex> lock(control_mutex_);
13456 if (is_running_)
13457 return false;
13458 stop_mutex_.lock();
13459 thread_ = std::thread([this]() { thread_function(); });
13460 is_running_ = true;
13461 return true;
13462 }
stop()13463 bool stop()
13464 {
13465 std::lock_guard<std::mutex> lock(control_mutex_);
13466 if (!is_running_)
13467 return false;
13468 stop_mutex_.unlock();
13469 if (thread_.joinable())
13470 {
13471 thread_.join();
13472 thread_ = std::thread();
13473 }
13474 is_running_ = false;
13475 return true;
13476 }
~ticker()13477 ~ticker()
13478 {
13479 stop();
13480 }
13481 private:
thread_function()13482 void thread_function()
13483 {
13484 auto last_wake_up_time = std::chrono::steady_clock::now();
13485 auto last_time = last_wake_up_time;
13486 bool quit = false;
13487 while (!quit)
13488 {
13489 const auto wake_up_time =
13490 last_wake_up_time + std::chrono::microseconds{ interval_us_ };
13491 const auto sleep_time =
13492 wake_up_time - std::chrono::steady_clock::now();
13493 if (stop_mutex_.try_lock_for(sleep_time))
13494 {
13495 stop_mutex_.unlock();
13496 quit = true;
13497 }
13498 const auto current_time = std::chrono::steady_clock::now();
13499 const auto elapsed = current_time - last_time;
13500 last_wake_up_time = wake_up_time;
13501 last_time = current_time;
13502 const auto elapsed_us =
13503 std::chrono::duration_cast<std::chrono::microseconds>(
13504 elapsed).count();
13505 try
13506 {
13507 f_(elapsed_us);
13508 }
13509 catch (...)
13510 {
13511 }
13512 }
13513 }
13514 const function f_;
13515 const std::int64_t interval_us_;
13516 std::mutex control_mutex_;
13517 bool is_running_;
13518 std::thread thread_;
13519 std::timed_mutex stop_mutex_;
13520 };
13521
13522
13523 // API search type: sleep_for_n_seconds : Int -> Io ()
13524 // Returns a function that suspends
13525 // the calling thread for n seconds when executed.
13526 inline
sleep_for_n_seconds(std::size_t seconds)13527 std::function<void()> sleep_for_n_seconds(std::size_t seconds)
13528 {
13529 return [seconds]()
13530 {
13531 std::this_thread::sleep_for(std::chrono::seconds(seconds));
13532 };
13533 }
13534
13535 // API search type: sleep_for_n_milliseconds : Int -> Io ()
13536 // Returns a function that suspends
13537 // the calling thread for n milliseconds when executed.
13538 inline
sleep_for_n_milliseconds(std::size_t milliseconds)13539 std::function<void()> sleep_for_n_milliseconds(std::size_t milliseconds)
13540 {
13541 return [milliseconds]()
13542 {
13543 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
13544 };
13545 }
13546
13547 // API search type: sleep_for_n_microseconds : Int -> Io ()
13548 // Returns a function that suspends
13549 // the calling thread for n microseconds when executed.
13550 inline
sleep_for_n_microseconds(std::size_t microseconds)13551 std::function<void()> sleep_for_n_microseconds(std::size_t microseconds)
13552 {
13553 return [microseconds]()
13554 {
13555 std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
13556 };
13557 }
13558
13559 // API search type: execute_serially : [Io ()] -> Io ()
13560 // Returns a function that executes
13561 // the given side effects one after another when called.
13562 template <typename Container>
execute_serially(const Container & effs)13563 auto execute_serially(const Container& effs)
13564 {
13565 using Effect = typename Container::value_type;
13566 using Result = internal::invoke_result_t<Effect>;
13567
13568 return [effs]
13569 {
13570 std::vector<std::decay_t<Result>> results;
13571 for (const Effect& e : effs)
13572 {
13573 results.push_back(internal::invoke(e));
13574 }
13575 return results;
13576 };
13577 }
13578
13579 // API search type: execute_serially_until_success : [Io Bool] -> Io Bool
13580 // Returns a function that (when called) executes
13581 // the given side effects one after another until one of it returns true.
13582 template <typename Container>
execute_serially_until_success(const Container & effs)13583 auto execute_serially_until_success(const Container& effs)
13584 {
13585 using Effect = typename Container::value_type;
13586 using Result = internal::invoke_result_t<Effect>;
13587 static_assert(std::is_convertible<Result, bool>::value,
13588 "Effects must return a boolish type.");
13589 return [effs]() -> bool
13590 {
13591 for (const Effect& e : effs)
13592 {
13593 if (internal::invoke(e))
13594 {
13595 return true;
13596 }
13597 }
13598 return false;
13599 };
13600 }
13601
13602 // API search type: execute_and_return_fixed_value : (a, [Io b]) -> Io a
13603 // Returns a function that executes the given side effect
13604 // and returns a fixed value when called.
13605 template <typename Result, typename Effect>
execute_and_return_fixed_value(Result result,Effect eff)13606 std::function<Result()> execute_and_return_fixed_value(
13607 Result result,
13608 Effect eff)
13609 {
13610 return [eff, result]() -> Result
13611 {
13612 eff();
13613 return result;
13614 };
13615 }
13616
13617 // Converts an arbitrary callable effect to an std::function.
13618 template <typename Effect>
effect_to_std_function(Effect eff)13619 std::function<internal::invoke_result_t<Effect> ()> effect_to_std_function(Effect eff)
13620 {
13621 return [eff]
13622 {
13623 return internal::invoke(eff);
13624 };
13625 }
13626
13627 // API search type: execute_max_n_times_until_success : (Int, Io (), Int) -> Io Bool
13628 // Returns a function that (when called) executes a side effect
13629 // until it succeds once or the maximum number
13630 // of attempts with an optional pause in between.
13631 template <typename Effect>
execute_max_n_times_until_success(std::size_t n,const Effect & eff,std::size_t pause_in_milliseconds=0)13632 auto execute_max_n_times_until_success(std::size_t n,
13633 const Effect& eff,
13634 std::size_t pause_in_milliseconds = 0)
13635 {
13636 if (pause_in_milliseconds > 0)
13637 {
13638 auto sleep_and_return_false =
13639 execute_and_return_fixed_value(
13640 false,
13641 sleep_for_n_milliseconds(pause_in_milliseconds));
13642 return execute_serially_until_success(
13643 intersperse(
13644 sleep_and_return_false,
13645 replicate(n, effect_to_std_function(eff))));
13646 }
13647 return execute_serially_until_success(
13648 replicate(n, effect_to_std_function(eff)));
13649 }
13650
13651 // API search type: execute_n_times : (Int, Io a) -> Io ()
13652 // Returns a function that (when called) executes n times
13653 // the provided side effect function.
13654 // The return values (if present) are dropped.
13655 template<typename Effect>
execute_n_times(std::size_t n,const Effect & eff)13656 auto execute_n_times(std::size_t n, const Effect& eff)
13657 {
13658 for (auto _ : fplus::numbers(static_cast<size_t>(0), n))
13659 {
13660 (void) _; // suppress warning / unused variable
13661 eff();
13662 }
13663 }
13664
13665 // API search type: execute_serially_until_failure : [Io Bool] -> Io Bool
13666 // Returns a function that (when called) executes the given side effects
13667 // one after another until one of them returns false.
13668 template <typename Container>
execute_serially_until_failure(const Container & effs)13669 std::function<bool()> execute_serially_until_failure(const Container& effs)
13670 {
13671 using Effect = typename Container::value_type;
13672 using Result = internal::invoke_result_t<Effect>;
13673 static_assert(std::is_convertible<Result, bool>::value,
13674 "Effects must return a boolish type.");
13675 return [effs]() -> bool
13676 {
13677 for (const Effect& e : effs)
13678 {
13679 if (!internal::invoke(e))
13680 {
13681 return false;
13682 }
13683 }
13684 return true;
13685 };
13686 }
13687
13688 // API search type: execute_parallelly : [Io a] -> Io [a]
13689 // Returns a function that (when called) executes the given side effects
13690 // in parallel (one thread each) and returns the collected results.
13691 template <typename Container>
execute_parallelly(const Container & effs)13692 auto execute_parallelly(const Container& effs)
13693 {
13694 return [effs] {
13695 // Bluntly re-using the transform implementation to execute side effects.
13696 return transform_parallelly([](const auto& eff) {
13697 return internal::invoke(eff);
13698 }, effs);
13699 };
13700 }
13701
13702 // API search type: execute_parallelly_n_threads : (Int, [Io a]) -> Io [a]
13703 // Returns a function that (when called) executes the given side effects
13704 // in parallel (one thread each) and returns the collected results.
13705 template <typename Container>
execute_parallelly_n_threads(std::size_t n,const Container & effs)13706 auto execute_parallelly_n_threads(std::size_t n, const Container& effs)
13707 {
13708 return [n, effs] {
13709 // Bluntly re-using the transform implementation to execute side effects.
13710 return transform_parallelly_n_threads(n, [](const auto& eff) {
13711 return internal::invoke(eff);
13712 }, effs);
13713 };
13714 }
13715
13716 // API search type: execute_fire_and_forget : Io a -> Io a
13717 // Returns a function that (when called) executes the given side effect
13718 // in a new thread and returns immediately.
13719 template <typename Effect>
execute_fire_and_forget(Effect eff)13720 std::function<void()> execute_fire_and_forget(Effect eff)
13721 {
13722 return [eff]()
13723 {
13724 std::thread t(eff);
13725 t.detach();
13726 };
13727 }
13728
13729 // API search type: read_text_file_maybe : String -> Io (Maybe String)
13730 // Returns a function that reads the content of a text file when called.
13731 inline
read_text_file_maybe(const std::string & filename)13732 std::function<maybe<std::string>()> read_text_file_maybe(
13733 const std::string& filename)
13734 {
13735 return [filename]() -> maybe<std::string>
13736 {
13737 std::ifstream input(filename);
13738 if (!input.good())
13739 return {};
13740 return just(std::string(
13741 std::istreambuf_iterator<std::string::value_type>(input),
13742 std::istreambuf_iterator<std::string::value_type>()));
13743 };
13744 }
13745
13746 // API search type: read_text_file : String -> Io String
13747 // Returns a function that reads the content of a text file when called.
13748 // This function then returns an empty string if the file could not be read.
13749 inline
read_text_file(const std::string & filename)13750 std::function<std::string()> read_text_file(const std::string& filename)
13751 {
13752 return [filename]() -> std::string
13753 {
13754 return just_with_default(
13755 std::string(),
13756
13757 read_text_file_maybe(filename)());
13758 };
13759 }
13760
13761 // API search type: read_binary_file_maybe : String -> Io (Maybe [Int])
13762 // Returns a function that reads the content of a binary file when executed.
13763 inline
read_binary_file_maybe(const std::string & filename)13764 std::function<maybe<std::vector<std::uint8_t>>()> read_binary_file_maybe(
13765 const std::string& filename)
13766 {
13767 return [filename]() -> maybe<std::vector<std::uint8_t>>
13768 {
13769 std::ifstream file(filename, std::ios::binary);
13770 if (!file.good())
13771 return {};
13772 file.unsetf(std::ios::skipws);
13773 std::streampos fileSize;
13774 file.seekg(0, std::ios::end);
13775 fileSize = file.tellg();
13776 if (fileSize == static_cast<std::streamsize>(0))
13777 return {};
13778 file.seekg(0, std::ios::beg);
13779 std::vector<std::uint8_t> vec(static_cast<std::size_t>(fileSize), 0);
13780 file.read(reinterpret_cast<char*>(&vec[0]), fileSize);
13781 return vec;
13782 };
13783 }
13784
13785 // API search type: read_binary_file : String -> Io [Int]
13786 // Returns a function that reads the content of a binary file when executed.
13787 // This function then returns an empty vector if the file could not be read.
13788 inline
read_binary_file(const std::string & filename)13789 std::function<std::vector<std::uint8_t>()> read_binary_file(
13790 const std::string& filename)
13791 {
13792 return [filename]() -> std::vector<std::uint8_t>
13793 {
13794 return just_with_default(
13795 std::vector<std::uint8_t>(),
13796 read_binary_file_maybe(filename)());
13797 };
13798 }
13799
13800 // API search type: read_text_file_lines_maybe : (String, Bool) -> Io (Maybe [String])
13801 // Returns a function that (when called) reads the content of a text file
13802 // and returns it line by line.
13803 inline
read_text_file_lines_maybe(bool allow_empty,const std::string & filename)13804 std::function<maybe<std::vector<std::string>>()> read_text_file_lines_maybe(
13805 bool allow_empty, const std::string& filename)
13806 {
13807 return [filename, allow_empty]() -> maybe<std::vector<std::string>>
13808 {
13809 const auto maybe_content = read_text_file_maybe(filename)();
13810 if (maybe_content.is_nothing())
13811 return {};
13812 else
13813 return split_lines(allow_empty, maybe_content.unsafe_get_just());
13814 };
13815 }
13816
13817 // API search type: read_text_file_lines : (String, Bool) -> Io [String]
13818 // Returns a function that (when called) reads the content of a text file
13819 // and returns it line by line.
13820 // This function then returns an empty vector if the file could not be read.
13821 inline
read_text_file_lines(bool allow_empty,const std::string & filename)13822 std::function<std::vector<std::string>()> read_text_file_lines(
13823 bool allow_empty, const std::string& filename)
13824 {
13825 return [filename, allow_empty]() -> std::vector<std::string>
13826 {
13827 return just_with_default(
13828 std::vector<std::string>(),
13829 read_text_file_lines_maybe(allow_empty, filename)());
13830 };
13831 }
13832
13833 // API search type: write_text_file : (String, String) -> Io Bool
13834 // Returns a function that (when called) writes content into a text file,
13835 // replacing it if it already exists.
13836 inline
write_text_file(const std::string & filename,const std::string & content)13837 std::function<bool()> write_text_file(const std::string& filename,
13838 const std::string& content)
13839 {
13840 return [filename, content]() -> bool
13841 {
13842 std::ofstream output(filename);
13843 output << content;
13844 return output.good();
13845 };
13846 }
13847
13848 // API search type: write_binary_file : (String, [Int]) -> Io Bool
13849 // Returns a function that (when called) writes content into a binary file,
13850 // replacing it if it already exists.
13851 inline
write_binary_file(const std::string & filename,const std::vector<uint8_t> & content)13852 std::function<bool()> write_binary_file(const std::string& filename,
13853 const std::vector<uint8_t>& content)
13854 {
13855 return [filename, content]() -> bool
13856 {
13857 std::ofstream file(filename, std::ios::binary);
13858 file.write(reinterpret_cast<const char*>(&content[0]),
13859 static_cast<std::streamsize>(content.size()));
13860 return file.good();
13861 };
13862 }
13863
13864 // API search type: write_text_file_lines : (String, [String], Bool) -> Io Bool
13865 // Returns a function that (when called) writes lines into a text file,
13866 // replacing it if it already exists.
13867 inline
write_text_file_lines(bool trailing_newline,const std::string & filename,const std::vector<std::string> & lines)13868 std::function<bool()> write_text_file_lines(bool trailing_newline,
13869 const std::string& filename,
13870 const std::vector<std::string>& lines)
13871 {
13872 std::string content = join(std::string("\n"), lines);
13873 if (trailing_newline)
13874 {
13875 content += "\n";
13876 }
13877 return write_text_file(filename, content);
13878 }
13879
13880 // API search type: execute_effect : Io a -> a
13881 // Simply run a side effect (call a function without parameters)
13882 // and returns the result.
13883 // Can be useful for chaining.
13884 template <typename F>
execute_effect(const F f)13885 auto execute_effect(const F f)
13886 {
13887 return internal::invoke(f);
13888 }
13889
13890 // API search type: interact : (String -> String) -> Io ()
13891 // Takes a function F of type (String -> String)
13892 // and returns a function that
13893 // reads the entire input from standard input,
13894 // passes it through the given function,
13895 // and writes the result to standard output.
13896 template <typename F>
interact(F f)13897 std::function<void()> interact(F f)
13898 {
13899 return [f]() -> void
13900 {
13901 std::cout << f(std::string(
13902 std::istreambuf_iterator<char>(std::cin.rdbuf()),
13903 std::istreambuf_iterator<char>()));
13904 };
13905 }
13906
13907 // API search type: execute_with_maybe : ((a -> void), Maybe a) -> Io Bool
13908 // Returns a function that
13909 // akes a unary side-effect function with
13910 // a maybe holding a matching type
13911 // and runs the sideeffect if the Maybe holds a just.
13912 // The returned function returns false if the maybe was a nothing.
13913 template <typename Effect, typename X>
execute_with_maybe(Effect eff,const maybe<X> & m)13914 std::function<bool()> execute_with_maybe(Effect eff, const maybe<X>& m)
13915 {
13916 return [eff, m]() -> bool
13917 {
13918 if (m.is_nothing())
13919 {
13920 return false;
13921 }
13922 eff(m.unsafe_get_just());
13923 return true;
13924 };
13925 }
13926
13927 } // namespace fplus
13928
13929 //
13930 // stopwatch.hpp
13931 //
13932
13933 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
13934 // https://github.com/Dobiasd/FunctionalPlus
13935 // Distributed under the Boost Software License, Version 1.0.
13936 // (See accompanying file LICENSE_1_0.txt or copy at
13937 // http://www.boost.org/LICENSE_1_0.txt)
13938
13939
13940 #include <chrono>
13941
13942 namespace fplus
13943 {
13944
13945 class stopwatch
13946 {
13947 public:
stopwatch()13948 stopwatch() : beg_(clock::now()) {}
reset()13949 void reset() { beg_ = clock::now(); }
13950
13951 // time since creation or last reset in seconds
elapsed() const13952 double elapsed() const {
13953 return std::chrono::duration_cast<second>
13954 (clock::now() - beg_).count(); }
13955 private:
13956 typedef std::chrono::high_resolution_clock clock;
13957 typedef std::chrono::duration<double, std::ratio<1>> second;
13958 std::chrono::time_point<clock> beg_;
13959 };
13960
13961 } // namespace fplus
13962
13963 //
13964 // variant.hpp
13965 //
13966
13967 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
13968 // https://github.com/Dobiasd/FunctionalPlus
13969 // Distributed under the Boost Software License, Version 1.0.
13970 // (See accompanying file LICENSE_1_0.txt or copy at
13971 // http://www.boost.org/LICENSE_1_0.txt)
13972
13973
13974
13975 #include <iostream>
13976 #include <memory>
13977 #include <tuple>
13978
13979 namespace fplus
13980 {
13981
13982 namespace internal
13983 {
13984
13985 // http://stackoverflow.com/a/18987405/1866775
13986
13987 template <typename...>
13988 struct is_one_of;
13989
13990 template <typename F>
13991 struct is_one_of<F>
13992 {
13993 static constexpr bool value = false;
13994 };
13995
13996 template <typename F, typename S, typename... T>
13997 struct is_one_of<F, S, T...>
13998 {
13999 static constexpr bool value = std::is_same<F, S>::value
14000 || is_one_of<F, T...>::value;
14001 };
14002
14003 template <typename F, typename... T>
14004 struct is_one_of<F, std::tuple<T...>>
14005 {
14006 static constexpr bool value = is_one_of<F, T...>::value;
14007 };
14008
14009 template <typename...>
14010 struct is_unique;
14011
14012 template <>
14013 struct is_unique<> {
14014 static constexpr bool value = true;
14015 };
14016
14017 template<typename F, typename... T>
14018 struct is_unique<F, T...>
14019 {
14020 static constexpr bool value = is_unique<T...>::value
14021 && !is_one_of<F, T...>::value;
14022 };
14023
14024 template<typename... T>
14025 struct is_unique<std::tuple<T...>>
14026 {
14027 static constexpr bool value = is_unique<T...>::value;
14028 };
14029
14030 template <typename...>
14031 struct are_same;
14032
14033 template <>
14034 struct are_same<> {
14035 static constexpr bool value = true;
14036 };
14037
14038 template<typename F1, typename F2>
14039 struct are_same<F1, F2>
14040 {
14041 static constexpr bool value = std::is_same<F1, F2>::value;
14042 };
14043
14044 template<typename F1, typename F2, typename... T>
14045 struct are_same<F1, F2, T...>
14046 {
14047 static constexpr bool value = are_same<F2, T...>::value
14048 && std::is_same<F1, F2>::value;
14049 };
14050
14051 template<typename... T>
14052 struct are_same<std::tuple<T...>>
14053 {
14054 static constexpr bool value = are_same<T...>::value;
14055 };
14056
14057 // http://stackoverflow.com/a/3273571/1866775
14058 template<template<typename...> class List,
14059 template<typename> class Mod,
14060 typename ...Args>
14061 struct transform_parameter_pack {
14062 typedef List<typename Mod<Args>::type...> type;
14063 };
14064
14065 template<typename T>
14066 struct as_shared_pointer
14067 {
14068 typedef std::shared_ptr<T> type;
14069 };
14070
14071
14072
14073 // http://stackoverflow.com/a/27588263/1866775
14074
14075 template <typename T, typename... Ts> struct get_index;
14076
14077 template <typename T, typename... Ts>
14078 struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
14079
14080 template <typename T, typename Tail, typename... Ts>
14081 struct get_index<T, Tail, Ts...> :
14082 std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> {};
14083
14084 template <typename T>
14085 struct get_index<T>
14086 {
14087 // condition is always false, but should be dependant of T
14088 static_assert(sizeof(T) == 0, "element not found");
14089 };
14090
14091
14092 template <typename T, typename ... Ts>
14093 struct parameter_pack_head
14094 {
14095 typedef T type;
14096 };
14097
14098
14099 template <typename F>
14100 struct function_first_input_type
14101 {
14102 typedef typename std::remove_const<
14103 typename std::remove_reference<
14104 typename utils::function_traits<
14105 F>::template arg<0>::type>::type>::type
14106 type;
14107 };
14108
14109 template <typename F>
14110 struct unary_function_result_type
14111 {
14112 static_assert(utils::function_traits<F>::arity == 1,
14113 "Wrong arity.");
14114 typedef typename function_first_input_type<F>::type T;
14115 typedef std::decay_t<internal::invoke_result_t<F, T>> type;
14116 };
14117
14118
14119 // http://stackoverflow.com/a/42493805/1866775
14120
14121 template <typename T>
14122 struct tag { };
14123
14124 template <typename... Ts>
14125 struct type_set_eq_helper: tag<Ts>... { };
14126
14127 template <typename, typename, typename = void>
14128 struct type_set_eq: std::false_type { };
14129
14130 template <bool...>
14131 struct bool_pack { };
14132
14133 template <bool... Bs>
14134 using my_and = std::is_same<bool_pack<Bs..., true>, bool_pack<true, Bs...>>;
14135
14136 template <typename... Ts1, typename... Ts2>
14137 struct type_set_eq<std::tuple<Ts1...>, std::tuple<Ts2...>, typename std::enable_if< (sizeof...(Ts1) == sizeof...(Ts2)) && my_and< std::is_base_of<tag<Ts2>, type_set_eq_helper<Ts1...>>::value... >::value >::type >:
14138 std::true_type { };
14139
14140
14141 // http://stackoverflow.com/a/42581257/1866775
14142
14143 template <typename Lhs, typename Rhs>
14144 struct is_superset_of;
14145
14146 template <typename Tuple, typename T, typename... Ts>
14147 struct is_superset_of<Tuple, std::tuple<T, Ts...>>
14148 {
14149 static const bool value = is_one_of<T, Tuple>::value && is_superset_of<Tuple, std::tuple<Ts...>>::value;
14150 };
14151
14152 template <typename Tuple>
14153 struct is_superset_of<Tuple, std::tuple<>>
14154 {
14155 static const bool value = true;
14156 };
14157
14158
14159 // http://stackoverflow.com/a/36934374/1866775
14160 template<bool... bs>
14161 using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
14162
14163 } // namespace internal
14164
14165
14166 template<typename ... Types>
14167 struct variant
14168 {
14169 static_assert(internal::is_unique<Types...>::value, "Types must be unique.");
14170 static_assert(internal::all_true<(!std::is_reference<Types>::value)...>::value, "No reference types allowed.");
14171 static_assert(internal::all_true<(!std::is_const<Types>::value)...>::value, "No const types allowed.");
14172 static_assert(sizeof...(Types) >= 1, "Please provide at least one type.");
14173
14174 template <typename T>
variantfplus::variant14175 variant(const T& val) : shared_ptrs_({})
14176 {
14177 std::get<internal::get_index<T, Types...>::value>(shared_ptrs_) =
14178 std::make_shared<T>(val);
14179 }
14180
14181 template <typename T>
isfplus::variant14182 bool is() const
14183 {
14184 static_assert(
14185 internal::is_one_of<T, Types...>::value
14186 , "Type must match one possible variant type.");
14187
14188 const auto ptr =
14189 std::get<internal::get_index<T, Types...>::value>(shared_ptrs_);
14190
14191 return static_cast<bool>(ptr);
14192 }
14193
operator ==(const variant<Types...> & a,const variant<Types...> & b)14194 friend bool operator== (
14195 const variant<Types...>& a, const variant<Types...>& b)
14196 {
14197 return a.shared_ptrs_ == b.shared_ptrs_;
14198 }
14199
operator !=(const variant<Types...> & a,const variant<Types...> & b)14200 friend bool operator!= (
14201 const variant<Types...>& a, const variant<Types...>& b)
14202 {
14203 return a.shared_ptrs_ != b.shared_ptrs_;
14204 }
14205
14206 template <typename F>
visit_onefplus::variant14207 auto visit_one(F f) const
14208 {
14209 using T = typename internal::function_first_input_type<F>::type;
14210 using Ret = internal::invoke_result_t<F, T>;
14211 internal::trigger_static_asserts<internal::unary_function_tag, F, T>();
14212
14213 static_assert(
14214 internal::is_one_of<
14215 typename internal::function_first_input_type<F>::type,
14216 Types...>::value
14217 , "Function input must match one variant type.");
14218
14219 static_assert(!std::is_same<std::decay_t<Ret>, void>::value,
14220 "Function must return non-void type.");
14221
14222 const auto ptr =
14223 std::get<internal::get_index<T, Types...>::value>(shared_ptrs_);
14224
14225 if (ptr)
14226 {
14227 return just(internal::invoke(f, *ptr));
14228 }
14229
14230 return nothing<std::decay_t<Ret>>();
14231 }
14232
14233 template <typename ...Fs>
visitfplus::variant14234 auto visit(Fs ... fs) const ->
14235 typename internal::unary_function_result_type<
14236 typename internal::parameter_pack_head<Fs...>::type>::type
14237 {
14238 typedef typename internal::unary_function_result_type<
14239 typename internal::parameter_pack_head<Fs...>::type>::type
14240 Res;
14241
14242 static_assert(
14243 sizeof...(Fs) >= std::tuple_size<shared_ptr_pack>::value,
14244 "Too few functions provided.");
14245
14246 static_assert(
14247 sizeof...(Fs) <= std::tuple_size<shared_ptr_pack>::value,
14248 "Too many functions provided.");
14249
14250 typedef typename internal::transform_parameter_pack<
14251 std::tuple,
14252 internal::unary_function_result_type,
14253 Fs...
14254 >::type return_types_tuple;
14255
14256 typedef typename internal::transform_parameter_pack<
14257 std::tuple,
14258 internal::function_first_input_type,
14259 Fs...
14260 >::type function_first_input_types_tuple;
14261
14262 static_assert(
14263 internal::is_unique<function_first_input_types_tuple>::value,
14264 "Only one function per input type allowed.");
14265
14266 static_assert(
14267 internal::are_same<return_types_tuple>::value,
14268 "All Functions must return the same type.");
14269
14270 static_assert(
14271 internal::type_set_eq<function_first_input_types_tuple, std::tuple<Types...>>::value,
14272 "Functions do not cover all possible types.");
14273
14274 const auto results = justs(visit_helper<Res>(fs...));
14275 assert(size_of_cont(results) == 1);
14276 return head(results);
14277 }
14278
14279 template <typename ...Fs>
transformfplus::variant14280 variant<Types...> transform(Fs ... fs) const
14281 {
14282 static_assert(
14283 sizeof...(Fs) >= std::tuple_size<shared_ptr_pack>::value,
14284 "Too few functions provided.");
14285
14286 static_assert(
14287 sizeof...(Fs) <= std::tuple_size<shared_ptr_pack>::value,
14288 "Too many functions provided.");
14289
14290 typedef typename internal::transform_parameter_pack<
14291 std::tuple,
14292 internal::unary_function_result_type,
14293 Fs...
14294 >::type return_types_tuple;
14295
14296 typedef typename internal::transform_parameter_pack<
14297 std::tuple,
14298 internal::function_first_input_type,
14299 Fs...
14300 >::type function_first_input_types_tuple;
14301
14302 static_assert(
14303 internal::type_set_eq<function_first_input_types_tuple, std::tuple<Types...>>::value,
14304 "Functions do not cover all possible types.");
14305
14306 static_assert(
14307 internal::is_superset_of<std::tuple<Types...>, return_types_tuple>::value,
14308 "All Functions must return a possible variant type.");
14309
14310 return visit(fs...);
14311 }
14312
14313 private:
14314 template <typename Res, typename F>
visit_helperfplus::variant14315 std::vector<fplus::maybe<Res>> visit_helper(F f) const
14316 {
14317 return {visit_one(f)};
14318 }
14319
14320 template <typename Res, typename F, typename ...Fs>
visit_helperfplus::variant14321 std::vector<fplus::maybe<Res>> visit_helper(F f, Fs ... fs) const
14322 {
14323 return fplus::append(visit_helper<Res>(f), visit_helper<Res>(fs...));
14324 }
14325
14326 typedef typename internal::transform_parameter_pack<
14327 std::tuple,
14328 internal::as_shared_pointer,
14329 Types...
14330 >::type shared_ptr_pack;
14331 shared_ptr_pack shared_ptrs_;
14332 };
14333
14334 } // namespace fplus
14335
14336 //
14337 // timed.hpp
14338 //
14339
14340
14341 #include <chrono>
14342 #include <type_traits>
14343
14344 #include <cassert>
14345 #include <exception>
14346 #include <functional>
14347 #include <memory>
14348
14349 namespace fplus
14350 {
14351 using ExecutionTime = double; // in seconds
14352
14353 // Holds a value of type T plus an execution time
14354 template <typename T>
14355 class timed : public std::pair<T, ExecutionTime>
14356 {
14357 using base_pair = std::pair<T, ExecutionTime>;
14358 public:
timed()14359 timed() : base_pair() {}
timed(const T & val,ExecutionTime t=0.)14360 timed(const T& val, ExecutionTime t = 0.) : base_pair(val, t) {}
14361
14362 // Execution time in seconds (returns a double)
time_in_s() const14363 ExecutionTime time_in_s() const { return base_pair::second; }
14364
14365 // Execution time as a std::chrono::duration<double>
duration_in_s() const14366 std::chrono::duration<double, std::ratio<1>> duration_in_s() const
14367 {
14368 return std::chrono::duration<double, std::ratio<1>>(time_in_s());
14369 }
14370
14371 // Inner value
get() const14372 const T& get() const { return base_pair::first; }
get()14373 T& get() { return base_pair::first; }
14374 };
14375
14376 // API search type: show_timed : Timed a -> String
14377 // fwd bind count: 0
14378 // show_timed((42,1)) -> "42 (1000ms)"
14379 template <typename T>
show_timed(const fplus::timed<T> & v)14380 std::string show_timed(const fplus::timed<T>& v)
14381 {
14382 std::string result =
14383 fplus::show(v.get()) + " (" + fplus::show(v.time_in_s() * 1000.) + "ms)";
14384 return result;
14385 }
14386
14387 namespace internal
14388 {
14389 template<typename Fn>
14390 class timed_function_impl
14391 {
14392 public:
timed_function_impl(Fn fn)14393 explicit timed_function_impl(Fn fn) : _fn(fn) {};
operator ()(Args &&...args)14394 template<typename ...Args> auto operator()(Args&&... args)
14395 {
14396 return _timed_result(std::forward<Args>(args)...);
14397 }
14398
14399 private:
14400 template<typename ...Args>
_timed_result(Args &&...args)14401 auto _timed_result(Args&&... args)
14402 {
14403 fplus::stopwatch timer;
14404 auto r = _fn(std::forward<Args>(args)...);
14405 auto r_t = fplus::timed<decltype(r)>(r, timer.elapsed());
14406 return r_t;
14407 }
14408
14409 Fn _fn;
14410 };
14411 }
14412
14413 // API search type: make_timed_function : ((a -> b)) -> (a -> Timed b)
14414 // fwd bind count: 0
14415 // Transforms a function into a timed / benchmarked version of the same function.
14416 // -
14417 // Example:
14418 // -
14419 // using Ints = std::vector<int>;
14420 // Ints ascending_numbers = fplus::numbers(0, 1000);
14421 // Ints shuffled_numbers = fplus::shuffle(std::mt19937::default_seed, ascending_numbers);
14422 // auto sort_func = [](const Ints& values) { return fplus::sort(values); };
14423 // auto sort_bench = fplus::make_timed_function(sort_func);
14424 // auto sorted_numbers = sort_bench(shuffled_numbers);
14425 // assert(sorted_numbers.get() == ascending_numbers); // sorted_numbers.get() <=> actual output
14426 // assert(sorted_numbers.time_in_s() < 0.1); // // sorted_numbers.time_in_s() <=> execution time
14427 template<class Fn>
make_timed_function(Fn f)14428 auto make_timed_function(Fn f)
14429 {
14430 return internal::timed_function_impl<decltype(f)>(f);
14431 }
14432
14433 namespace internal
14434 {
14435 template<typename Fn>
14436 class timed_void_function_impl
14437 {
14438 public:
timed_void_function_impl(Fn fn)14439 explicit timed_void_function_impl(Fn fn) : _fn(fn) {};
operator ()(Args &&...args)14440 template<typename ...Args> auto operator()(Args&&... args)
14441 {
14442 return _timed_result(std::forward<Args>(args)...);
14443 }
14444
14445 private:
14446 template<typename ...Args>
_timed_result(Args &&...args)14447 auto _timed_result(Args&&... args)
14448 {
14449 fplus::stopwatch timer;
14450 _fn(std::forward<Args>(args)...);
14451 return timer.elapsed();
14452 }
14453
14454 Fn _fn;
14455 };
14456
14457 }
14458
14459 // API search type: make_timed_void_function : ((a -> Void)) -> (a -> Double)
14460 // fwd bind count: 0
14461 // Transforms a void function into a timed / benchmarked version of the same function.
14462 // -
14463 // Example:
14464 // -
14465 // void foo() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); }
14466 // ...
14467 // auto foo_bench = make_timed_void_function(foo);
14468 // auto r = foo_bench();
14469 // double run_time = foo_bench(); // in seconds
14470 template<class Fn>
make_timed_void_function(Fn f)14471 auto make_timed_void_function(Fn f)
14472 {
14473 return internal::timed_void_function_impl<decltype(f)>(f);
14474 }
14475
14476 }
14477
14478 //
14479 // benchmark_session.hpp
14480 //
14481
14482 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
14483 // https://github.com/Dobiasd/FunctionalPlus
14484 // Distributed under the Boost Software License, Version 1.0.
14485 // (See accompanying file LICENSE_1_0.txt or copy at
14486 // http://www.boost.org/LICENSE_1_0.txt)
14487
14488 #include <vector>
14489 #include <mutex>
14490
14491
14492 namespace fplus
14493 {
14494 using FunctionName = std::string;
14495 struct benchmark_function_report
14496 {
14497 std::size_t nb_calls;
14498 ExecutionTime total_time;
14499 ExecutionTime average_time;
14500 ExecutionTime deviation;
14501 };
14502
14503
14504 namespace internal
14505 {
14506 std::string show_benchmark_function_report(
14507 const std::map<FunctionName, benchmark_function_report> & reports);
14508 }
14509
14510
14511 // benchmark_session stores timings during a benchmark session
14512 // and is able to emit a report at the end
14513 class benchmark_session
14514 {
14515 public:
benchmark_session()14516 benchmark_session() : functions_times_mutex_(), functions_times_() {};
14517
14518 // report() shall return a string with a summary of the session
14519 // Example below:
14520 // Function |Nb calls|Total time|Av. time|Deviation|
14521 // ----------------------+--------+----------+--------+---------+
14522 // convert_charset_string| 4000| 4.942ms| 1.236us| 1.390us|
14523 // split_lines | 1000| 4.528ms| 4.528us| 1.896us|
report() const14524 inline std::string report() const
14525 {
14526 const auto reports = report_list();
14527 return fplus::internal::show_benchmark_function_report(reports);
14528 }
14529
report_list() const14530 std::map<FunctionName, benchmark_function_report> report_list() const
14531 {
14532 std::lock_guard<std::mutex> lock(functions_times_mutex_);
14533 std::map<FunctionName, benchmark_function_report> report;
14534 for (const auto & one_function_time : functions_times_)
14535 {
14536 report[one_function_time.first] = make_bench_report(one_function_time.second);
14537 }
14538 return report;
14539 }
14540
store_one_time(const FunctionName & function_name,ExecutionTime time)14541 inline void store_one_time(const FunctionName & function_name, ExecutionTime time)
14542 {
14543 std::lock_guard<std::mutex> lock(functions_times_mutex_);
14544 functions_times_[function_name].push_back(time);
14545 }
14546
14547 private:
make_bench_report(const std::vector<ExecutionTime> & times) const14548 benchmark_function_report make_bench_report(
14549 const std::vector<ExecutionTime> & times) const
14550 {
14551 benchmark_function_report result;
14552 result.nb_calls = times.size();
14553 auto mean_and_dev = fplus::mean_stddev<double>(times);
14554 result.average_time = mean_and_dev.first;
14555 result.deviation = mean_and_dev.second;
14556 result.total_time = fplus::sum(times);
14557 return result;
14558 }
14559
14560 mutable std::mutex functions_times_mutex_;
14561 std::map<FunctionName, std::vector<ExecutionTime>> functions_times_;
14562 };
14563
14564 namespace internal
14565 {
14566 template<typename Fn>
14567 class bench_function_impl
14568 {
14569 public:
bench_function_impl(benchmark_session & benchmark_sess,FunctionName function_name,Fn fn)14570 explicit bench_function_impl(
14571 benchmark_session & benchmark_sess,
14572 FunctionName function_name,
14573 Fn fn)
14574 : benchmark_session_(benchmark_sess)
14575 , function_name_(function_name)
14576 , fn_(fn)
14577 {};
14578
operator ()(Args &&...args)14579 template<typename ...Args> auto operator()(Args&&... args)
14580 {
14581 return _bench_result(std::forward<Args>(args)...);
14582 }
14583
14584 private:
14585 template<typename ...Args>
_bench_result(Args &&...args)14586 auto _bench_result(Args&&... args)
14587 {
14588 fplus::stopwatch timer;
14589 auto r = fn_(std::forward<Args>(args)...);
14590 benchmark_session_.store_one_time(function_name_, timer.elapsed());
14591 return r;
14592 }
14593
14594 benchmark_session & benchmark_session_;
14595 FunctionName function_name_;
14596 Fn fn_;
14597 };
14598
14599 template<typename Fn>
14600 class bench_void_function_impl
14601 {
14602 public:
bench_void_function_impl(benchmark_session & benchmark_sess,FunctionName function_name,Fn fn)14603 explicit bench_void_function_impl(
14604 benchmark_session & benchmark_sess,
14605 FunctionName function_name,
14606 Fn fn)
14607 : benchmark_session_(benchmark_sess)
14608 , function_name_(function_name)
14609 , fn_(fn)
14610 {};
14611
operator ()(Args &&...args)14612 template<typename ...Args> auto operator()(Args&&... args)
14613 {
14614 _bench_result(std::forward<Args>(args)...);
14615 }
14616
14617 private:
14618 template<typename ...Args>
_bench_result(Args &&...args)14619 auto _bench_result(Args&&... args)
14620 {
14621 fplus::stopwatch timer;
14622 fn_(std::forward<Args>(args)...);
14623 benchmark_session_.store_one_time(function_name_, timer.elapsed());
14624 }
14625
14626 benchmark_session & benchmark_session_;
14627 FunctionName function_name_;
14628 Fn fn_;
14629 };
14630
14631 } // namespace internal
14632
14633
14634 // API search type: make_benchmark_function : (benchmark_session, string, (a... -> b)) -> (a... -> b)
14635 // Transforms a function into a function with the *same* signature
14636 // and behavior, except that it also stores stats into the benchmark session (first parameter),
14637 // under the name given by the second parameter.
14638 // -
14639 // Notes:
14640 // Side effects: make_benchmark_function *will add side effects* to the function, since it stores data
14641 // into the benchmark session at each call.
14642 // If you intend to benchmark only one function, prefer to use the simpler "make_timed_function"
14643 // Use "make_benchmark_void_function" if your function returns void
14644 // -
14645 // Example of a minimal benchmark session (read benchmark_session_test.cpp for a full example)
14646 // fplus::benchmark_session benchmark_sess;
14647 // void foo() {
14648 // auto add_bench = fplus::make_benchmark_function(benchmark_sess, "add", add);
14649 // auto printf_bench = fplus::make_benchmark_void_function(benchmark_sess, "printf", printf);
14650 // int forty_five = add_bench(20, add_bench(19, 6));
14651 // int forty_two = benchmark_expression(benchmark_sess, "sub", forty_five - 3);
14652 // printf_bench("forty_two is %i\n", forty_two);
14653 // }
14654 // int main() {
14655 // foo();
14656 // std::cout << benchmark_sess.report();
14657 // }
14658 // This will output a report like this
14659 // Function|Nb calls|Total time|Av. time|Deviation|
14660 // --------+--------+----------+--------+---------+
14661 // printf | 1| 0.010ms| 9.952us| 0.000us|
14662 // add | 2| 0.000ms| 0.050us| 0.009us|
14663 // sub | 1| 0.000ms| 0.039us| 0.000us|
14664 // -
14665 // As an alternative to make_benchmark_function, you can also benchmark an expression.
14666 // For example, in order to benchmark the following line:
14667 // auto sorted = fplus::sort(my_vector);
14668 // Just copy/paste this expression into "bench_expression" like shown below: this expression
14669 // will then be benchmarked with the name "sort_my_vector"
14670 // auto sorted = benchmark_expression(
14671 // my_benchmark_session,
14672 // "sort_my_vector",
14673 // fplus::sort(my_vector);
14674 // );
14675 // Notes :
14676 // benchmark_expression is a preprocessor macro that uses an immediately invoked lambda (IIL).
14677 // The expression can be copy-pasted with no modification, and it is possible to not remove the ";"
14678 // (although it also works if it is not present)
14679 // You can also benchmark an expression that returns void using benchmark_void_expression
14680 template<class Fn>
make_benchmark_function(benchmark_session & session,const FunctionName & name,Fn f)14681 auto make_benchmark_function(benchmark_session & session, const FunctionName & name, Fn f)
14682 {
14683 // transforms f into a function with the same
14684 // signature, that will store timings into the benchmark session
14685 return internal::bench_function_impl<Fn>(session, name, f);
14686 }
14687
14688
14689 // API search type: make_benchmark_void_function : (benchmark_session, string, (a... -> Void)) -> (a... -> Void)
14690 // Transforms a function that returns a void into a function with the *same* signature
14691 // and behavior, except that it also stores stats into the benchmark session (first parameter),
14692 // under the name given by the second parameter
14693 // Note that make_benchmark_void_function *will add side effects* to the function
14694 // (since it stores data into the benchmark session at each call)
14695 // -
14696 // Example:
14697 // benchmark_session bench_session;
14698 // ...
14699 // void foo() {
14700 // std::this_thread::sleep_for(std::chrono::milliseconds(1000));
14701 // }
14702 // ...
14703 // auto foo_bench = make_benchmark_void_function(bench_session, "foo", foo);
14704 // foo_bench();
14705 // ...
14706 // std::cout << benchmark_session.report();
14707 template<class Fn>
make_benchmark_void_function(benchmark_session & session,const FunctionName & name,Fn f)14708 auto make_benchmark_void_function(benchmark_session & session, const FunctionName & name, Fn f)
14709 {
14710 // transforms a void returning function into a function with the same
14711 // signature, that will store timings into the benchmark session
14712 return internal::bench_void_function_impl<Fn>(session, name, f);
14713 }
14714
14715 #define benchmark_expression(bench_session, name, expression) \
14716 make_benchmark_function( \
14717 bench_session, \
14718 name, \
14719 [&]() { return expression; } \
14720 )();
14721
14722 #define benchmark_void_expression(bench_session, name, expression) \
14723 make_benchmark_void_function( \
14724 bench_session, \
14725 name, \
14726 [&]() { expression; } \
14727 )();
14728
14729
14730 namespace internal
14731 {
show_table(const std::vector<std::vector<std::string>> & rows)14732 inline std::string show_table(const std::vector<std::vector<std::string>>& rows)
14733 {
14734 if (rows.empty() || rows[0].empty())
14735 return "";
14736
14737 const std::vector<std::size_t> columns_width = [&]() {
14738 auto string_size = [](const std::string & s) -> std::size_t { return s.size(); };
14739 auto largest_string_size = [&](const std::vector<std::string> & strings) -> std::size_t {
14740 return string_size(fplus::maximum_on(string_size, strings));
14741 };
14742 return fplus::transform(largest_string_size, fplus::transpose(rows));
14743 }();
14744
14745 auto show_one_element = [](const std::pair<std::string, std::size_t> & elem_and_width) {
14746 const std::string & element = elem_and_width.first;
14747 const auto col_width = elem_and_width.second;
14748 bool is_number = element.size() > 0 && isdigit(element[0]);
14749 if (is_number)
14750 return fplus::show_fill_left(' ', col_width, element) + "|";
14751 else
14752 return fplus::show_fill_right(' ', col_width, element) + "|";
14753 };
14754
14755 auto show_one_separator = [](std::size_t col_width) {
14756 return fplus::show_fill_left('-', col_width, "") + "+";
14757 };
14758
14759 auto show_one_row = [&](const std::vector<std::string> & row) {
14760 return fplus::sum(fplus::transform(
14761 show_one_element,
14762 fplus::zip(row, columns_width)));
14763 };
14764
14765 auto firstrow_separator = fplus::sum(fplus::transform(show_one_separator, columns_width));
14766 auto rows_formatted = fplus::transform(show_one_row, rows);
14767 auto rows_separated = fplus::insert_at_idx(1, firstrow_separator, rows_formatted);
14768 return fplus::join( std::string("\n"), rows_separated) + "\n";
14769 }
14770
make_ordered_reports(const std::map<FunctionName,benchmark_function_report> & report_map)14771 inline std::vector< std::pair<FunctionName, benchmark_function_report> > make_ordered_reports(
14772 const std::map<FunctionName, benchmark_function_report> & report_map)
14773 {
14774 auto report_pairs = fplus::map_to_pairs(report_map);
14775 auto report_pairs_sorted = fplus::sort_by([](const auto &a, const auto &b) {
14776 return a.second.total_time > b.second.total_time;
14777 }, report_pairs);
14778 return report_pairs_sorted;
14779 }
14780
show_benchmark_function_report(const std::map<FunctionName,benchmark_function_report> & reports)14781 inline std::string show_benchmark_function_report(const std::map<FunctionName, benchmark_function_report> & reports)
14782 {
14783 auto ordered_reports = make_ordered_reports(reports);
14784 auto my_show_time_ms = [](double time) -> std::string {
14785 std::stringstream ss;
14786 ss << std::fixed << std::setprecision(3);
14787 ss << (time * 1000.);
14788 return ss.str() + "ms";
14789 };
14790 auto my_show_time_us = [](double time) -> std::string {
14791 std::stringstream ss;
14792 ss << std::fixed << std::setprecision(3);
14793 ss << (time * 1000000.);
14794 return ss.str() + "us";
14795 };
14796
14797 std::vector<std::string> header_row{ {
14798 "Function", "Nb calls", "Total time", "Av. time", "Deviation"
14799 } };
14800 auto value_rows = fplus::transform([&](const auto & kv) {
14801 const auto & report = kv.second;
14802 const auto & function_name = kv.first;
14803 std::vector<std::string> row;
14804 row.push_back(function_name);
14805 row.push_back(fplus::show(report.nb_calls));
14806 row.push_back(my_show_time_ms(report.total_time));
14807 row.push_back(my_show_time_us(report.average_time));
14808 row.push_back(my_show_time_us(report.deviation));
14809 return row;
14810 },
14811 ordered_reports);
14812
14813 return fplus::internal::show_table(fplus::insert_at_idx(0, header_row, value_rows));
14814 }
14815 } // namespace internal
14816
14817 }
14818
14819
14820 //
14821 // curry.hpp
14822 //
14823
14824 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
14825 // https://github.com/Dobiasd/FunctionalPlus
14826 // Distributed under the Boost Software License, Version 1.0.
14827 // (See accompanying file LICENSE_1_0.txt or copy at
14828 // http://www.boost.org/LICENSE_1_0.txt)
14829
14830
14831 namespace fplus
14832 {
14833 namespace curry
14834 {
14835
14836 // Currying.
14837 // Allow to generically bind parameters one by one.
14838
14839 #define fplus_curry_define_fn_0(fplus_curry_define_fn_0_name) \
14840 inline auto fplus_curry_define_fn_0_name() \
14841 { \
14842 return [](auto&& fplus_curry_p1) \
14843 { \
14844 return fplus::fplus_curry_define_fn_0_name(std::forward<decltype(fplus_curry_p1)>(fplus_curry_p1)); \
14845 }; \
14846 }
14847
14848 #define fplus_curry_define_fn_1(fplus_curry_define_fn_1_name) \
14849 template <typename P1> \
14850 auto fplus_curry_define_fn_1_name(P1 p1) \
14851 { \
14852 return [p1](auto&& fplus_curry_p2) \
14853 { \
14854 return fplus::fplus_curry_define_fn_1_name(p1, std::forward<decltype(fplus_curry_p2)>(fplus_curry_p2)); \
14855 }; \
14856 }
14857
14858 #define fplus_curry_define_fn_2(fplus_curry_define_fn_2_name) \
14859 template <typename P1> \
14860 auto fplus_curry_define_fn_2_name(P1 p1) \
14861 { \
14862 return [p1](const auto& fplus_curry_p2) \
14863 { \
14864 return [p1, fplus_curry_p2](auto&& fplus_curry_p3) \
14865 { \
14866 return fplus::fplus_curry_define_fn_2_name(p1, fplus_curry_p2, std::forward<decltype(fplus_curry_p3)>(fplus_curry_p3)); \
14867 }; \
14868 }; \
14869 }
14870
14871 #define fplus_curry_define_fn_3(fplus_curry_define_fn_3_name) \
14872 template <typename P1> \
14873 auto fplus_curry_define_fn_3_name(P1 p1) \
14874 { \
14875 return [p1](const auto& fplus_curry_p2) \
14876 { \
14877 return [p1, fplus_curry_p2](const auto& fplus_curry_p3) \
14878 { \
14879 return [p1, fplus_curry_p2, fplus_curry_p3](auto&& fplus_curry_p4) \
14880 { \
14881 return fplus::fplus_curry_define_fn_3_name(p1, fplus_curry_p2, fplus_curry_p3, std::forward<decltype(fplus_curry_p4)>(fplus_curry_p4)); \
14882 }; \
14883 }; \
14884 }; \
14885 }
14886
14887 #define fplus_curry_define_fn_4(fplus_curry_define_fn_4_name) \
14888 template <typename P1> \
14889 auto fplus_curry_define_fn_4_name(P1 p1) \
14890 { \
14891 return [p1](const auto& fplus_curry_p2) \
14892 { \
14893 return [p1, fplus_curry_p2](const auto& fplus_curry_p3) \
14894 { \
14895 return [p1, fplus_curry_p2, fplus_curry_p3](const auto& fplus_curry_p4) \
14896 { \
14897 return [p1, fplus_curry_p2, fplus_curry_p3, fplus_curry_p4](auto&& fplus_curry_p5) \
14898 { \
14899 return fplus::fplus_curry_define_fn_4_name(p1, fplus_curry_p2, fplus_curry_p3, fplus_curry_p4, std::forward<decltype(fplus_curry_p5)>(fplus_curry_p5)); \
14900 }; \
14901 }; \
14902 }; \
14903 }; \
14904 }
14905
14906
14907
14908 //
14909 // curry_instances.autogenerated_defines
14910 //
14911
14912 // THIS FILE WAS GENERATED AUTOMATICALLY. DO NOT EDIT.
14913 fplus_curry_define_fn_0(identity)
14914 fplus_curry_define_fn_1(is_equal)
14915 fplus_curry_define_fn_1(is_not_equal)
14916 fplus_curry_define_fn_1(is_less)
14917 fplus_curry_define_fn_1(is_less_or_equal)
14918 fplus_curry_define_fn_1(is_greater)
14919 fplus_curry_define_fn_1(is_greater_or_equal)
14920 fplus_curry_define_fn_1(xor_bools)
14921 fplus_curry_define_fn_0(is_just)
14922 fplus_curry_define_fn_0(is_nothing)
14923 fplus_curry_define_fn_0(unsafe_get_just)
14924 fplus_curry_define_fn_0(just_with_default)
14925 fplus_curry_define_fn_1(throw_on_nothing)
14926 fplus_curry_define_fn_0(just)
14927 fplus_curry_define_fn_1(as_just_if)
14928 fplus_curry_define_fn_0(maybe_to_seq)
14929 fplus_curry_define_fn_0(singleton_seq_as_maybe)
14930 fplus_curry_define_fn_1(lift_maybe)
14931 fplus_curry_define_fn_2(lift_maybe_def)
14932 fplus_curry_define_fn_2(lift_maybe_2)
14933 fplus_curry_define_fn_3(lift_maybe_2_def)
14934 fplus_curry_define_fn_1(and_then_maybe)
14935 fplus_curry_define_fn_0(flatten_maybe)
14936 fplus_curry_define_fn_0(is_even)
14937 fplus_curry_define_fn_0(is_odd)
14938 fplus_curry_define_fn_0(is_empty)
14939 fplus_curry_define_fn_0(is_not_empty)
14940 fplus_curry_define_fn_0(size_of_cont)
14941 fplus_curry_define_fn_0(convert)
14942 fplus_curry_define_fn_0(convert_elems)
14943 fplus_curry_define_fn_0(convert_container)
14944 fplus_curry_define_fn_0(convert_container_and_elems)
14945 fplus_curry_define_fn_2(get_segment)
14946 fplus_curry_define_fn_2(set_segment)
14947 fplus_curry_define_fn_2(remove_segment)
14948 fplus_curry_define_fn_2(insert_at)
14949 fplus_curry_define_fn_1(elem_at_idx)
14950 fplus_curry_define_fn_1(elem_at_idx_maybe)
14951 fplus_curry_define_fn_1(elems_at_idxs)
14952 fplus_curry_define_fn_1(transform)
14953 fplus_curry_define_fn_1(transform_convert)
14954 fplus_curry_define_fn_1(transform_inner)
14955 fplus_curry_define_fn_0(reverse)
14956 fplus_curry_define_fn_1(take)
14957 fplus_curry_define_fn_1(take_exact)
14958 fplus_curry_define_fn_1(take_cyclic)
14959 fplus_curry_define_fn_1(drop)
14960 fplus_curry_define_fn_1(take_last)
14961 fplus_curry_define_fn_1(drop_last)
14962 fplus_curry_define_fn_1(drop_exact)
14963 fplus_curry_define_fn_1(take_while)
14964 fplus_curry_define_fn_1(take_last_while)
14965 fplus_curry_define_fn_1(drop_while)
14966 fplus_curry_define_fn_1(drop_last_while)
14967 fplus_curry_define_fn_2(fold_left)
14968 fplus_curry_define_fn_2(reduce)
14969 fplus_curry_define_fn_1(fold_left_1)
14970 fplus_curry_define_fn_1(reduce_1)
14971 fplus_curry_define_fn_2(fold_right)
14972 fplus_curry_define_fn_1(fold_right_1)
14973 fplus_curry_define_fn_2(scan_left)
14974 fplus_curry_define_fn_1(scan_left_1)
14975 fplus_curry_define_fn_2(scan_right)
14976 fplus_curry_define_fn_1(scan_right_1)
14977 fplus_curry_define_fn_0(sum)
14978 fplus_curry_define_fn_0(product)
14979 fplus_curry_define_fn_1(append_elem)
14980 fplus_curry_define_fn_1(prepend_elem)
14981 fplus_curry_define_fn_1(append)
14982 fplus_curry_define_fn_1(append_convert)
14983 fplus_curry_define_fn_0(concat)
14984 fplus_curry_define_fn_1(interweave)
14985 fplus_curry_define_fn_0(unweave)
14986 fplus_curry_define_fn_1(sort_by)
14987 fplus_curry_define_fn_1(sort_on)
14988 fplus_curry_define_fn_0(sort)
14989 fplus_curry_define_fn_1(stable_sort_by)
14990 fplus_curry_define_fn_1(stable_sort_on)
14991 fplus_curry_define_fn_0(stable_sort)
14992 fplus_curry_define_fn_2(partial_sort_by)
14993 fplus_curry_define_fn_2(partial_sort_on)
14994 fplus_curry_define_fn_1(partial_sort)
14995 fplus_curry_define_fn_2(nth_element_by)
14996 fplus_curry_define_fn_2(nth_element_on)
14997 fplus_curry_define_fn_1(nth_element)
14998 fplus_curry_define_fn_1(unique_by)
14999 fplus_curry_define_fn_1(unique_on)
15000 fplus_curry_define_fn_0(unique)
15001 fplus_curry_define_fn_1(intersperse)
15002 fplus_curry_define_fn_1(join)
15003 fplus_curry_define_fn_1(join_elem)
15004 fplus_curry_define_fn_1(is_elem_of_by)
15005 fplus_curry_define_fn_1(is_elem_of)
15006 fplus_curry_define_fn_1(nub_by)
15007 fplus_curry_define_fn_1(nub_on)
15008 fplus_curry_define_fn_0(nub)
15009 fplus_curry_define_fn_1(all_unique_by_eq)
15010 fplus_curry_define_fn_1(all_unique_on)
15011 fplus_curry_define_fn_0(all_unique)
15012 fplus_curry_define_fn_1(is_strictly_sorted_by)
15013 fplus_curry_define_fn_1(is_strictly_sorted_on)
15014 fplus_curry_define_fn_0(is_strictly_sorted)
15015 fplus_curry_define_fn_1(is_sorted_by)
15016 fplus_curry_define_fn_1(is_sorted_on)
15017 fplus_curry_define_fn_0(is_sorted)
15018 fplus_curry_define_fn_1(is_prefix_of)
15019 fplus_curry_define_fn_1(is_suffix_of)
15020 fplus_curry_define_fn_1(all_by)
15021 fplus_curry_define_fn_0(all)
15022 fplus_curry_define_fn_1(all_the_same_by)
15023 fplus_curry_define_fn_1(all_the_same_on)
15024 fplus_curry_define_fn_0(all_the_same)
15025 fplus_curry_define_fn_2(numbers_step)
15026 fplus_curry_define_fn_1(numbers)
15027 fplus_curry_define_fn_0(singleton_seq)
15028 fplus_curry_define_fn_0(all_idxs)
15029 fplus_curry_define_fn_0(init)
15030 fplus_curry_define_fn_0(tail)
15031 fplus_curry_define_fn_0(head)
15032 fplus_curry_define_fn_0(last)
15033 fplus_curry_define_fn_0(mean_stddev)
15034 fplus_curry_define_fn_1(count_occurrences_by)
15035 fplus_curry_define_fn_0(count_occurrences)
15036 fplus_curry_define_fn_2(lexicographical_less_by)
15037 fplus_curry_define_fn_1(lexicographical_less)
15038 fplus_curry_define_fn_0(lexicographical_sort)
15039 fplus_curry_define_fn_1(replicate)
15040 fplus_curry_define_fn_2(instead_of_if)
15041 fplus_curry_define_fn_2(instead_of_if_empty)
15042 fplus_curry_define_fn_0(is_ok)
15043 fplus_curry_define_fn_0(is_error)
15044 fplus_curry_define_fn_0(unsafe_get_ok)
15045 fplus_curry_define_fn_0(unsafe_get_error)
15046 fplus_curry_define_fn_1(ok_with_default)
15047 fplus_curry_define_fn_0(ok)
15048 fplus_curry_define_fn_0(error)
15049 fplus_curry_define_fn_0(to_maybe)
15050 fplus_curry_define_fn_1(from_maybe)
15051 fplus_curry_define_fn_1(throw_on_error)
15052 fplus_curry_define_fn_1(lift_result)
15053 fplus_curry_define_fn_2(lift_result_both)
15054 fplus_curry_define_fn_2(unify_result)
15055 fplus_curry_define_fn_1(and_then_result)
15056 fplus_curry_define_fn_1(keep_if)
15057 fplus_curry_define_fn_1(drop_if)
15058 fplus_curry_define_fn_1(without)
15059 fplus_curry_define_fn_1(without_any)
15060 fplus_curry_define_fn_1(keep_if_with_idx)
15061 fplus_curry_define_fn_1(drop_if_with_idx)
15062 fplus_curry_define_fn_1(keep_by_idx)
15063 fplus_curry_define_fn_1(drop_by_idx)
15064 fplus_curry_define_fn_1(keep_idxs)
15065 fplus_curry_define_fn_1(drop_idxs)
15066 fplus_curry_define_fn_1(drop_idx)
15067 fplus_curry_define_fn_0(justs)
15068 fplus_curry_define_fn_0(oks)
15069 fplus_curry_define_fn_0(errors)
15070 fplus_curry_define_fn_1(trim_left)
15071 fplus_curry_define_fn_1(trim_token_left)
15072 fplus_curry_define_fn_1(trim_right_by)
15073 fplus_curry_define_fn_1(trim_right)
15074 fplus_curry_define_fn_1(trim_token_right)
15075 fplus_curry_define_fn_1(trim_by)
15076 fplus_curry_define_fn_1(trim)
15077 fplus_curry_define_fn_1(trim_token)
15078 fplus_curry_define_fn_1(adjacent_keep_snd_if)
15079 fplus_curry_define_fn_1(adjacent_drop_fst_if)
15080 fplus_curry_define_fn_1(adjacent_drop_snd_if)
15081 fplus_curry_define_fn_1(adjacent_keep_fst_if)
15082 fplus_curry_define_fn_1(generate_by_idx)
15083 fplus_curry_define_fn_1(repeat)
15084 fplus_curry_define_fn_1(infixes)
15085 fplus_curry_define_fn_3(carthesian_product_with_where)
15086 fplus_curry_define_fn_2(carthesian_product_with)
15087 fplus_curry_define_fn_2(carthesian_product_where)
15088 fplus_curry_define_fn_1(carthesian_product)
15089 fplus_curry_define_fn_1(carthesian_product_n)
15090 fplus_curry_define_fn_1(permutations)
15091 fplus_curry_define_fn_1(combinations)
15092 fplus_curry_define_fn_1(combinations_with_replacement)
15093 fplus_curry_define_fn_0(power_set)
15094 fplus_curry_define_fn_2(iterate)
15095 fplus_curry_define_fn_1(iterate_maybe)
15096 fplus_curry_define_fn_1(adjacent_difference_by)
15097 fplus_curry_define_fn_0(adjacent_difference)
15098 fplus_curry_define_fn_0(rotate_left)
15099 fplus_curry_define_fn_0(rotate_right)
15100 fplus_curry_define_fn_0(rotations_left)
15101 fplus_curry_define_fn_0(rotations_right)
15102 fplus_curry_define_fn_2(fill_left)
15103 fplus_curry_define_fn_2(fill_right)
15104 fplus_curry_define_fn_0(inits)
15105 fplus_curry_define_fn_0(tails)
15106 fplus_curry_define_fn_1(apply_to_pair)
15107 fplus_curry_define_fn_2(zip_with)
15108 fplus_curry_define_fn_3(zip_with_3)
15109 fplus_curry_define_fn_4(zip_with_defaults)
15110 fplus_curry_define_fn_1(zip)
15111 fplus_curry_define_fn_1(zip_repeat)
15112 fplus_curry_define_fn_0(unzip)
15113 fplus_curry_define_fn_0(fst)
15114 fplus_curry_define_fn_0(snd)
15115 fplus_curry_define_fn_1(transform_fst)
15116 fplus_curry_define_fn_1(transform_snd)
15117 fplus_curry_define_fn_2(transform_pair)
15118 fplus_curry_define_fn_0(swap_pair_elems)
15119 fplus_curry_define_fn_0(swap_pairs_elems)
15120 fplus_curry_define_fn_0(adjacent_pairs)
15121 fplus_curry_define_fn_0(overlapping_pairs)
15122 fplus_curry_define_fn_0(overlapping_pairs_cyclic)
15123 fplus_curry_define_fn_0(enumerate)
15124 fplus_curry_define_fn_4(inner_product_with)
15125 fplus_curry_define_fn_2(inner_product)
15126 fplus_curry_define_fn_2(first_mismatch_idx_by)
15127 fplus_curry_define_fn_2(first_mismatch_by)
15128 fplus_curry_define_fn_2(first_mismatch_idx_on)
15129 fplus_curry_define_fn_2(first_mismatch_on)
15130 fplus_curry_define_fn_2(first_mismatch_idx)
15131 fplus_curry_define_fn_2(first_mismatch)
15132 fplus_curry_define_fn_2(first_match_idx_by)
15133 fplus_curry_define_fn_2(first_match_by)
15134 fplus_curry_define_fn_2(first_match_idx_on)
15135 fplus_curry_define_fn_2(first_match_on)
15136 fplus_curry_define_fn_2(first_match_idx)
15137 fplus_curry_define_fn_2(first_match)
15138 fplus_curry_define_fn_2(is_in_interval)
15139 fplus_curry_define_fn_2(is_in_interval_around)
15140 fplus_curry_define_fn_2(is_in_open_interval)
15141 fplus_curry_define_fn_2(is_in_open_interval_around)
15142 fplus_curry_define_fn_2(is_in_closed_interval)
15143 fplus_curry_define_fn_4(reference_interval)
15144 fplus_curry_define_fn_2(clamp)
15145 fplus_curry_define_fn_0(is_negative)
15146 fplus_curry_define_fn_0(is_positive)
15147 fplus_curry_define_fn_0(abs)
15148 fplus_curry_define_fn_1(abs_diff)
15149 fplus_curry_define_fn_0(square)
15150 fplus_curry_define_fn_0(cube)
15151 fplus_curry_define_fn_0(sign)
15152 fplus_curry_define_fn_0(sign_with_zero)
15153 fplus_curry_define_fn_0(integral_cast_throw)
15154 fplus_curry_define_fn_0(integral_cast_clamp)
15155 fplus_curry_define_fn_0(round)
15156 fplus_curry_define_fn_0(floor)
15157 fplus_curry_define_fn_1(floor_to_int_mult)
15158 fplus_curry_define_fn_1(ceil_to_int_mult)
15159 fplus_curry_define_fn_0(ceil)
15160 fplus_curry_define_fn_1(int_power)
15161 fplus_curry_define_fn_2(min_2_on)
15162 fplus_curry_define_fn_2(max_2_on)
15163 fplus_curry_define_fn_1(min_2)
15164 fplus_curry_define_fn_1(max_2)
15165 fplus_curry_define_fn_0(deg_to_rad)
15166 fplus_curry_define_fn_0(rad_to_deg)
15167 fplus_curry_define_fn_2(normalize_min_max)
15168 fplus_curry_define_fn_2(normalize_mean_stddev)
15169 fplus_curry_define_fn_0(standardize)
15170 fplus_curry_define_fn_1(histogram_using_intervals)
15171 fplus_curry_define_fn_2(generate_consecutive_intervals)
15172 fplus_curry_define_fn_3(histogram)
15173 fplus_curry_define_fn_1(modulo_chain)
15174 fplus_curry_define_fn_2(line_equation)
15175 fplus_curry_define_fn_1(find_first_by)
15176 fplus_curry_define_fn_1(find_last_by)
15177 fplus_curry_define_fn_1(find_first_idx_by)
15178 fplus_curry_define_fn_1(find_last_idx_by)
15179 fplus_curry_define_fn_1(find_first_idx)
15180 fplus_curry_define_fn_1(find_last_idx)
15181 fplus_curry_define_fn_1(find_all_idxs_by)
15182 fplus_curry_define_fn_1(find_all_idxs_of)
15183 fplus_curry_define_fn_1(find_all_instances_of_token)
15184 fplus_curry_define_fn_1(find_all_instances_of_token_non_overlapping)
15185 fplus_curry_define_fn_1(find_first_instance_of_token)
15186 fplus_curry_define_fn_1(set_includes)
15187 fplus_curry_define_fn_1(unordered_set_includes)
15188 fplus_curry_define_fn_1(set_merge)
15189 fplus_curry_define_fn_1(unordered_set_merge)
15190 fplus_curry_define_fn_1(set_intersection)
15191 fplus_curry_define_fn_1(unordered_set_intersection)
15192 fplus_curry_define_fn_1(set_is_disjoint)
15193 fplus_curry_define_fn_1(unordered_set_is_disjoint)
15194 fplus_curry_define_fn_1(set_difference)
15195 fplus_curry_define_fn_1(unordered_set_difference)
15196 fplus_curry_define_fn_1(set_symmetric_difference)
15197 fplus_curry_define_fn_1(unordered_set_symmetric_difference)
15198 fplus_curry_define_fn_0(sets_intersection)
15199 fplus_curry_define_fn_0(unordered_sets_intersection)
15200 fplus_curry_define_fn_1(any_by)
15201 fplus_curry_define_fn_0(any)
15202 fplus_curry_define_fn_1(none_by)
15203 fplus_curry_define_fn_0(none)
15204 fplus_curry_define_fn_1(minimum_idx_by)
15205 fplus_curry_define_fn_1(minimum_idx_by_maybe)
15206 fplus_curry_define_fn_1(maximum_idx_by)
15207 fplus_curry_define_fn_1(maximum_idx_by_maybe)
15208 fplus_curry_define_fn_0(minimum_idx)
15209 fplus_curry_define_fn_0(minimum_idx_maybe)
15210 fplus_curry_define_fn_0(maximum_idx)
15211 fplus_curry_define_fn_0(maximum_idx_maybe)
15212 fplus_curry_define_fn_1(minimum_idx_on)
15213 fplus_curry_define_fn_1(minimum_idx_on_maybe)
15214 fplus_curry_define_fn_1(maximum_idx_on)
15215 fplus_curry_define_fn_1(maximum_idx_on_maybe)
15216 fplus_curry_define_fn_1(minimum_by)
15217 fplus_curry_define_fn_1(minimum_by_maybe)
15218 fplus_curry_define_fn_1(maximum_by)
15219 fplus_curry_define_fn_1(maximum_by_maybe)
15220 fplus_curry_define_fn_0(minimum)
15221 fplus_curry_define_fn_0(minimum_maybe)
15222 fplus_curry_define_fn_0(maximum)
15223 fplus_curry_define_fn_0(maximum_maybe)
15224 fplus_curry_define_fn_1(minimum_on)
15225 fplus_curry_define_fn_1(minimum_on_maybe)
15226 fplus_curry_define_fn_1(maximum_on)
15227 fplus_curry_define_fn_1(maximum_on_maybe)
15228 fplus_curry_define_fn_0(mean)
15229 fplus_curry_define_fn_0(mean_obj_div_size_t)
15230 fplus_curry_define_fn_0(mean_obj_div_double)
15231 fplus_curry_define_fn_0(mean_using_doubles)
15232 fplus_curry_define_fn_0(median)
15233 fplus_curry_define_fn_1(all_unique_by_less)
15234 fplus_curry_define_fn_0(all_unique_less)
15235 fplus_curry_define_fn_1(is_infix_of)
15236 fplus_curry_define_fn_1(is_subsequence_of)
15237 fplus_curry_define_fn_1(count_if)
15238 fplus_curry_define_fn_1(count)
15239 fplus_curry_define_fn_1(is_unique_in_by)
15240 fplus_curry_define_fn_1(is_unique_in)
15241 fplus_curry_define_fn_1(is_permutation_of)
15242 fplus_curry_define_fn_1(fill_pigeonholes_to)
15243 fplus_curry_define_fn_0(fill_pigeonholes)
15244 fplus_curry_define_fn_1(fill_pigeonholes_bool_to)
15245 fplus_curry_define_fn_0(fill_pigeonholes_bool)
15246 fplus_curry_define_fn_0(present_in_all)
15247 fplus_curry_define_fn_1(elem_at_idx_or_nothing)
15248 fplus_curry_define_fn_2(elem_at_idx_or_constant)
15249 fplus_curry_define_fn_1(elem_at_idx_or_replicate)
15250 fplus_curry_define_fn_1(elem_at_idx_or_wrap)
15251 fplus_curry_define_fn_2(extrapolate_replicate)
15252 fplus_curry_define_fn_2(extrapolate_wrap)
15253 fplus_curry_define_fn_1(elem_at_float_idx)
15254 fplus_curry_define_fn_0(pairs_to_map)
15255 fplus_curry_define_fn_0(pairs_to_map_grouped)
15256 fplus_curry_define_fn_0(pairs_to_unordered_map_grouped)
15257 fplus_curry_define_fn_0(map_to_pairs)
15258 fplus_curry_define_fn_1(transform_map_values)
15259 fplus_curry_define_fn_2(map_union_with)
15260 fplus_curry_define_fn_1(map_union)
15261 fplus_curry_define_fn_0(map_grouped_to_pairs)
15262 fplus_curry_define_fn_0(get_map_keys)
15263 fplus_curry_define_fn_0(get_map_values)
15264 fplus_curry_define_fn_0(swap_keys_and_values)
15265 fplus_curry_define_fn_1(create_map)
15266 fplus_curry_define_fn_1(create_map_with)
15267 fplus_curry_define_fn_1(create_map_grouped)
15268 fplus_curry_define_fn_1(create_unordered_map)
15269 fplus_curry_define_fn_1(create_unordered_map_with)
15270 fplus_curry_define_fn_1(create_unordered_map_grouped)
15271 fplus_curry_define_fn_1(get_from_map)
15272 fplus_curry_define_fn_1(get_from_map_unsafe)
15273 fplus_curry_define_fn_2(get_from_map_with_def)
15274 fplus_curry_define_fn_1(get_first_from_map)
15275 fplus_curry_define_fn_1(get_first_from_map_unsafe)
15276 fplus_curry_define_fn_2(get_first_from_map_with_def)
15277 fplus_curry_define_fn_1(map_contains)
15278 fplus_curry_define_fn_1(map_keep_if)
15279 fplus_curry_define_fn_1(map_drop_if)
15280 fplus_curry_define_fn_1(map_keep)
15281 fplus_curry_define_fn_1(map_drop)
15282 fplus_curry_define_fn_1(map_keep_if_value)
15283 fplus_curry_define_fn_1(map_drop_if_value)
15284 fplus_curry_define_fn_1(map_keep_values)
15285 fplus_curry_define_fn_1(map_drop_values)
15286 fplus_curry_define_fn_1(map_pluck)
15287 fplus_curry_define_fn_1(choose)
15288 fplus_curry_define_fn_2(choose_by)
15289 fplus_curry_define_fn_1(choose_lazy)
15290 fplus_curry_define_fn_2(choose_by_lazy)
15291 fplus_curry_define_fn_1(choose_def)
15292 fplus_curry_define_fn_2(choose_by_def)
15293 fplus_curry_define_fn_1(choose_def_lazy)
15294 fplus_curry_define_fn_2(choose_by_def_lazy)
15295 fplus_curry_define_fn_1(group_by)
15296 fplus_curry_define_fn_1(group_on)
15297 fplus_curry_define_fn_1(group_on_labeled)
15298 fplus_curry_define_fn_0(group)
15299 fplus_curry_define_fn_1(group_globally_by)
15300 fplus_curry_define_fn_1(group_globally_on)
15301 fplus_curry_define_fn_1(group_globally_on_labeled)
15302 fplus_curry_define_fn_0(group_globally)
15303 fplus_curry_define_fn_1(cluster_by)
15304 fplus_curry_define_fn_2(split_by)
15305 fplus_curry_define_fn_1(split_by_keep_separators)
15306 fplus_curry_define_fn_2(split)
15307 fplus_curry_define_fn_2(split_one_of)
15308 fplus_curry_define_fn_1(split_keep_separators)
15309 fplus_curry_define_fn_1(split_at_idx)
15310 fplus_curry_define_fn_2(insert_at_idx)
15311 fplus_curry_define_fn_1(partition)
15312 fplus_curry_define_fn_1(split_at_idxs)
15313 fplus_curry_define_fn_1(split_every)
15314 fplus_curry_define_fn_2(split_by_token)
15315 fplus_curry_define_fn_1(run_length_encode_by)
15316 fplus_curry_define_fn_0(run_length_encode)
15317 fplus_curry_define_fn_0(run_length_decode)
15318 fplus_curry_define_fn_1(span)
15319 fplus_curry_define_fn_2(divvy)
15320 fplus_curry_define_fn_1(aperture)
15321 fplus_curry_define_fn_1(stride)
15322 fplus_curry_define_fn_1(winsorize)
15323 fplus_curry_define_fn_1(separate_on)
15324 fplus_curry_define_fn_0(separate)
15325 fplus_curry_define_fn_1(transform_with_idx)
15326 fplus_curry_define_fn_1(transform_and_keep_justs)
15327 fplus_curry_define_fn_1(transform_and_keep_oks)
15328 fplus_curry_define_fn_1(transform_and_concat)
15329 fplus_curry_define_fn_1(replicate_elems)
15330 fplus_curry_define_fn_0(interleave)
15331 fplus_curry_define_fn_0(transpose)
15332 fplus_curry_define_fn_1(shuffle)
15333 fplus_curry_define_fn_2(sample)
15334 fplus_curry_define_fn_1(random_element)
15335 fplus_curry_define_fn_2(random_elements)
15336 fplus_curry_define_fn_1(apply_functions)
15337 fplus_curry_define_fn_2(apply_function_n_times)
15338 fplus_curry_define_fn_1(transform_parallelly)
15339 fplus_curry_define_fn_2(transform_parallelly_n_threads)
15340 fplus_curry_define_fn_2(reduce_parallelly)
15341 fplus_curry_define_fn_3(reduce_parallelly_n_threads)
15342 fplus_curry_define_fn_1(reduce_1_parallelly)
15343 fplus_curry_define_fn_2(reduce_1_parallelly_n_threads)
15344 fplus_curry_define_fn_1(keep_if_parallelly)
15345 fplus_curry_define_fn_2(keep_if_parallelly_n_threads)
15346 fplus_curry_define_fn_3(transform_reduce)
15347 fplus_curry_define_fn_2(transform_reduce_1)
15348 fplus_curry_define_fn_3(transform_reduce_parallelly)
15349 fplus_curry_define_fn_4(transform_reduce_parallelly_n_threads)
15350 fplus_curry_define_fn_2(transform_reduce_1_parallelly)
15351 fplus_curry_define_fn_3(transform_reduce_1_parallelly_n_threads)
15352 fplus_curry_define_fn_1(read_value_with_default)
15353 fplus_curry_define_fn_2(replace_if)
15354 fplus_curry_define_fn_2(replace_elem_at_idx)
15355 fplus_curry_define_fn_2(replace_elems)
15356 fplus_curry_define_fn_2(replace_tokens)
15357 fplus_curry_define_fn_0(show)
15358 fplus_curry_define_fn_3(show_cont_with_frame_and_newlines)
15359 fplus_curry_define_fn_3(show_cont_with_frame)
15360 fplus_curry_define_fn_1(show_cont_with)
15361 fplus_curry_define_fn_0(show_cont)
15362 fplus_curry_define_fn_0(show_maybe)
15363 fplus_curry_define_fn_0(show_result)
15364 fplus_curry_define_fn_2(show_float)
15365 fplus_curry_define_fn_3(show_float_fill_left)
15366 fplus_curry_define_fn_2(show_fill_left)
15367 fplus_curry_define_fn_2(show_fill_right)
15368 fplus_curry_define_fn_0(is_letter_or_digit)
15369 fplus_curry_define_fn_0(is_whitespace)
15370 fplus_curry_define_fn_0(is_line_break)
15371 fplus_curry_define_fn_0(clean_newlines)
15372 fplus_curry_define_fn_1(split_words)
15373 fplus_curry_define_fn_1(split_lines)
15374 fplus_curry_define_fn_0(trim_whitespace_left)
15375 fplus_curry_define_fn_0(trim_whitespace_right)
15376 fplus_curry_define_fn_0(trim_whitespace)
15377 fplus_curry_define_fn_0(to_lower_case)
15378 fplus_curry_define_fn_1(to_lower_case_loc)
15379 fplus_curry_define_fn_0(to_upper_case)
15380 fplus_curry_define_fn_1(to_upper_case_loc)
15381 fplus_curry_define_fn_2(to_string_fill_left)
15382 fplus_curry_define_fn_2(to_string_fill_right)
15383 fplus_curry_define_fn_1(trees_from_sequence)
15384 fplus_curry_define_fn_1(are_trees_equal)
15385 fplus_curry_define_fn_0(tree_size)
15386 fplus_curry_define_fn_0(tree_depth)
15387 fplus_curry_define_fn_0(flatten_tree_depth_first)
15388 fplus_curry_define_fn_0(flatten_tree_breadth_first)
15389 fplus_curry_define_fn_0(show_timed)
15390 fplus_curry_define_fn_0(make_timed_function)
15391 fplus_curry_define_fn_0(make_timed_void_function)
15392
15393 } // namespace curry
15394 } // namespace fplus
15395
15396 //
15397 // fwd.hpp
15398 //
15399
15400 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
15401 // https://github.com/Dobiasd/FunctionalPlus
15402 // Distributed under the Boost Software License, Version 1.0.
15403 // (See accompanying file LICENSE_1_0.txt or copy at
15404 // http://www.boost.org/LICENSE_1_0.txt)
15405
15406
15407 namespace fplus
15408 {
15409 namespace fwd
15410 {
15411
15412 // Partial currying.
15413 // Allow to generically bind all but parameters except the last one.
15414 // The lambda paramter ist named fplus_fwd_x instead of x
15415 // because gcc can produce unjustified shadow warnings. see:
15416 // http://stackoverflow.com/questions/41208811/parameter-of-returned-generic-lambda-allegedly-shadows-parameter-of-free-functio
15417 #define fplus_fwd_define_fn_0(fplus_fwd_define_fn_0_name) \
15418 inline auto fplus_fwd_define_fn_0_name() \
15419 { \
15420 return [](auto&& fplus_fwd_x) \
15421 { \
15422 return fplus::fplus_fwd_define_fn_0_name(std::forward<decltype(fplus_fwd_x)>(fplus_fwd_x)); \
15423 }; \
15424 }
15425
15426 #define fplus_fwd_define_fn_1(fplus_fwd_define_fn_1_name) \
15427 template <typename P1> \
15428 auto fplus_fwd_define_fn_1_name(P1 p1) \
15429 { \
15430 return [p1](auto&& fplus_fwd_x) \
15431 { \
15432 return fplus::fplus_fwd_define_fn_1_name(p1, std::forward<decltype(fplus_fwd_x)>(fplus_fwd_x)); \
15433 }; \
15434 }
15435
15436 #define fplus_fwd_define_fn_2(fplus_fwd_define_fn_2_name) \
15437 template <typename P1, typename P2> \
15438 auto fplus_fwd_define_fn_2_name(P1 p1, P2 p2) \
15439 { \
15440 return [p1, p2](auto&& fplus_fwd_x) \
15441 { \
15442 return fplus::fplus_fwd_define_fn_2_name(p1, p2, std::forward<decltype(fplus_fwd_x)>(fplus_fwd_x)); \
15443 }; \
15444 }
15445
15446 #define fplus_fwd_define_fn_3(fplus_fwd_define_fn_3_name) \
15447 template <typename P1, typename P2, typename P3> \
15448 auto fplus_fwd_define_fn_3_name(P1 p1, P2 p2, P3 p3) \
15449 { \
15450 return [p1, p2, p3](auto&& fplus_fwd_x) \
15451 { \
15452 return fplus::fplus_fwd_define_fn_3_name(p1, p2, p3, std::forward<decltype(fplus_fwd_x)>(fplus_fwd_x)); \
15453 }; \
15454 }
15455
15456 #define fplus_fwd_define_fn_4(fplus_fwd_define_fn_4_name) \
15457 template <typename P1, typename P2, typename P3, typename P4> \
15458 auto fplus_fwd_define_fn_4_name(P1 p1, P2 p2, P3 p3, P4 p4) \
15459 { \
15460 return [p1, p2, p3, p4](auto&& fplus_fwd_x) \
15461 { \
15462 return fplus::fplus_fwd_define_fn_4_name(p1, p2, p3, p4, std::forward<decltype(fplus_fwd_x)>(fplus_fwd_x)); \
15463 }; \
15464 }
15465
15466
15467 #define fplus_fwd_flip_define_fn_1(fplus_fwd_flip_define_fn_1_name) \
15468 namespace flip \
15469 { \
15470 template <typename P2> \
15471 auto fplus_fwd_flip_define_fn_1_name(P2 p2) \
15472 { \
15473 return [p2](auto&& fplus_fwd_flip_x) \
15474 { \
15475 return fplus::fplus_fwd_flip_define_fn_1_name(std::forward<decltype(fplus_fwd_flip_x)>(fplus_fwd_flip_x), p2); \
15476 }; \
15477 } \
15478 } // namespace flip
15479
15480
15481 namespace internal
15482 {
15483 template<typename F, typename G>
15484 struct compose_helper{
compose_helperfplus::fwd::internal::compose_helper15485 compose_helper(F f, G g) : f_(f), g_(g) {}
15486 template<typename X>
operator ()fplus::fwd::internal::compose_helper15487 decltype(auto) operator()(X&& x) const
15488 {
15489 return g_(f_(std::forward<X>(x)));
15490 }
15491 private:
15492 F f_;
15493 G g_;
15494 };
15495 } // namespace internal
15496 template<typename F, typename G>
compose(F f,G g)15497 auto compose(F f, G g) {
15498 return internal::compose_helper<F, G> {f, g};
15499 }
15500 template<typename F1, typename... Fs>
compose(F1 f,Fs...args)15501 auto compose(F1 f, Fs ... args)
15502 {
15503 return compose(f, compose(args...));
15504 }
15505
15506 template<typename X, typename... Fs>
apply(X && x,Fs...args)15507 auto apply(X&& x, Fs ... args)
15508 {
15509 return compose(args...)(std::forward<X>(x));
15510 }
15511 template<typename X, typename F>
apply(X && x,F f)15512 auto apply(X&& x, F f)
15513 {
15514 return f(std::forward<X>(x));
15515 }
15516
15517
15518 //
15519 // fwd_instances.autogenerated_defines
15520 //
15521
15522 // THIS FILE WAS GENERATED AUTOMATICALLY. DO NOT EDIT.
15523 fplus_fwd_define_fn_0(identity)
15524 fplus_fwd_define_fn_1(is_equal)
15525 fplus_fwd_define_fn_1(is_not_equal)
15526 fplus_fwd_define_fn_1(is_less)
15527 fplus_fwd_define_fn_1(is_less_or_equal)
15528 fplus_fwd_define_fn_1(is_greater)
15529 fplus_fwd_define_fn_1(is_greater_or_equal)
15530 fplus_fwd_define_fn_1(xor_bools)
15531 fplus_fwd_define_fn_0(is_just)
15532 fplus_fwd_define_fn_0(is_nothing)
15533 fplus_fwd_define_fn_0(unsafe_get_just)
15534 fplus_fwd_define_fn_0(just_with_default)
15535 fplus_fwd_define_fn_1(throw_on_nothing)
15536 fplus_fwd_define_fn_0(just)
15537 fplus_fwd_define_fn_1(as_just_if)
15538 fplus_fwd_define_fn_0(maybe_to_seq)
15539 fplus_fwd_define_fn_0(singleton_seq_as_maybe)
15540 fplus_fwd_define_fn_1(lift_maybe)
15541 fplus_fwd_define_fn_2(lift_maybe_def)
15542 fplus_fwd_define_fn_2(lift_maybe_2)
15543 fplus_fwd_define_fn_3(lift_maybe_2_def)
15544 fplus_fwd_define_fn_1(and_then_maybe)
15545 fplus_fwd_define_fn_0(flatten_maybe)
15546 fplus_fwd_define_fn_0(is_even)
15547 fplus_fwd_define_fn_0(is_odd)
15548 fplus_fwd_define_fn_0(is_empty)
15549 fplus_fwd_define_fn_0(is_not_empty)
15550 fplus_fwd_define_fn_0(size_of_cont)
15551 fplus_fwd_define_fn_0(convert)
15552 fplus_fwd_define_fn_0(convert_elems)
15553 fplus_fwd_define_fn_0(convert_container)
15554 fplus_fwd_define_fn_0(convert_container_and_elems)
15555 fplus_fwd_define_fn_2(get_segment)
15556 fplus_fwd_define_fn_2(set_segment)
15557 fplus_fwd_define_fn_2(remove_segment)
15558 fplus_fwd_define_fn_2(insert_at)
15559 fplus_fwd_define_fn_1(elem_at_idx)
15560 fplus_fwd_define_fn_1(elem_at_idx_maybe)
15561 fplus_fwd_define_fn_1(elems_at_idxs)
15562 fplus_fwd_define_fn_1(transform)
15563 fplus_fwd_define_fn_1(transform_convert)
15564 fplus_fwd_define_fn_1(transform_inner)
15565 fplus_fwd_define_fn_0(reverse)
15566 fplus_fwd_define_fn_1(take)
15567 fplus_fwd_define_fn_1(take_exact)
15568 fplus_fwd_define_fn_1(take_cyclic)
15569 fplus_fwd_define_fn_1(drop)
15570 fplus_fwd_define_fn_1(take_last)
15571 fplus_fwd_define_fn_1(drop_last)
15572 fplus_fwd_define_fn_1(drop_exact)
15573 fplus_fwd_define_fn_1(take_while)
15574 fplus_fwd_define_fn_1(take_last_while)
15575 fplus_fwd_define_fn_1(drop_while)
15576 fplus_fwd_define_fn_1(drop_last_while)
15577 fplus_fwd_define_fn_2(fold_left)
15578 fplus_fwd_define_fn_2(reduce)
15579 fplus_fwd_define_fn_1(fold_left_1)
15580 fplus_fwd_define_fn_1(reduce_1)
15581 fplus_fwd_define_fn_2(fold_right)
15582 fplus_fwd_define_fn_1(fold_right_1)
15583 fplus_fwd_define_fn_2(scan_left)
15584 fplus_fwd_define_fn_1(scan_left_1)
15585 fplus_fwd_define_fn_2(scan_right)
15586 fplus_fwd_define_fn_1(scan_right_1)
15587 fplus_fwd_define_fn_0(sum)
15588 fplus_fwd_define_fn_0(product)
15589 fplus_fwd_define_fn_1(append_elem)
15590 fplus_fwd_define_fn_1(prepend_elem)
15591 fplus_fwd_define_fn_1(append)
15592 fplus_fwd_define_fn_1(append_convert)
15593 fplus_fwd_define_fn_0(concat)
15594 fplus_fwd_define_fn_1(interweave)
15595 fplus_fwd_define_fn_0(unweave)
15596 fplus_fwd_define_fn_1(sort_by)
15597 fplus_fwd_define_fn_1(sort_on)
15598 fplus_fwd_define_fn_0(sort)
15599 fplus_fwd_define_fn_1(stable_sort_by)
15600 fplus_fwd_define_fn_1(stable_sort_on)
15601 fplus_fwd_define_fn_0(stable_sort)
15602 fplus_fwd_define_fn_2(partial_sort_by)
15603 fplus_fwd_define_fn_2(partial_sort_on)
15604 fplus_fwd_define_fn_1(partial_sort)
15605 fplus_fwd_define_fn_2(nth_element_by)
15606 fplus_fwd_define_fn_2(nth_element_on)
15607 fplus_fwd_define_fn_1(nth_element)
15608 fplus_fwd_define_fn_1(unique_by)
15609 fplus_fwd_define_fn_1(unique_on)
15610 fplus_fwd_define_fn_0(unique)
15611 fplus_fwd_define_fn_1(intersperse)
15612 fplus_fwd_define_fn_1(join)
15613 fplus_fwd_define_fn_1(join_elem)
15614 fplus_fwd_define_fn_1(is_elem_of_by)
15615 fplus_fwd_define_fn_1(is_elem_of)
15616 fplus_fwd_define_fn_1(nub_by)
15617 fplus_fwd_define_fn_1(nub_on)
15618 fplus_fwd_define_fn_0(nub)
15619 fplus_fwd_define_fn_1(all_unique_by_eq)
15620 fplus_fwd_define_fn_1(all_unique_on)
15621 fplus_fwd_define_fn_0(all_unique)
15622 fplus_fwd_define_fn_1(is_strictly_sorted_by)
15623 fplus_fwd_define_fn_1(is_strictly_sorted_on)
15624 fplus_fwd_define_fn_0(is_strictly_sorted)
15625 fplus_fwd_define_fn_1(is_sorted_by)
15626 fplus_fwd_define_fn_1(is_sorted_on)
15627 fplus_fwd_define_fn_0(is_sorted)
15628 fplus_fwd_define_fn_1(is_prefix_of)
15629 fplus_fwd_define_fn_1(is_suffix_of)
15630 fplus_fwd_define_fn_1(all_by)
15631 fplus_fwd_define_fn_0(all)
15632 fplus_fwd_define_fn_1(all_the_same_by)
15633 fplus_fwd_define_fn_1(all_the_same_on)
15634 fplus_fwd_define_fn_0(all_the_same)
15635 fplus_fwd_define_fn_2(numbers_step)
15636 fplus_fwd_define_fn_1(numbers)
15637 fplus_fwd_define_fn_0(singleton_seq)
15638 fplus_fwd_define_fn_0(all_idxs)
15639 fplus_fwd_define_fn_0(init)
15640 fplus_fwd_define_fn_0(tail)
15641 fplus_fwd_define_fn_0(head)
15642 fplus_fwd_define_fn_0(last)
15643 fplus_fwd_define_fn_0(mean_stddev)
15644 fplus_fwd_define_fn_1(count_occurrences_by)
15645 fplus_fwd_define_fn_0(count_occurrences)
15646 fplus_fwd_define_fn_2(lexicographical_less_by)
15647 fplus_fwd_define_fn_1(lexicographical_less)
15648 fplus_fwd_define_fn_0(lexicographical_sort)
15649 fplus_fwd_define_fn_1(replicate)
15650 fplus_fwd_define_fn_2(instead_of_if)
15651 fplus_fwd_define_fn_2(instead_of_if_empty)
15652 fplus_fwd_define_fn_0(is_ok)
15653 fplus_fwd_define_fn_0(is_error)
15654 fplus_fwd_define_fn_0(unsafe_get_ok)
15655 fplus_fwd_define_fn_0(unsafe_get_error)
15656 fplus_fwd_define_fn_1(ok_with_default)
15657 fplus_fwd_define_fn_0(ok)
15658 fplus_fwd_define_fn_0(error)
15659 fplus_fwd_define_fn_0(to_maybe)
15660 fplus_fwd_define_fn_1(from_maybe)
15661 fplus_fwd_define_fn_1(throw_on_error)
15662 fplus_fwd_define_fn_1(lift_result)
15663 fplus_fwd_define_fn_2(lift_result_both)
15664 fplus_fwd_define_fn_2(unify_result)
15665 fplus_fwd_define_fn_1(and_then_result)
15666 fplus_fwd_define_fn_1(keep_if)
15667 fplus_fwd_define_fn_1(drop_if)
15668 fplus_fwd_define_fn_1(without)
15669 fplus_fwd_define_fn_1(without_any)
15670 fplus_fwd_define_fn_1(keep_if_with_idx)
15671 fplus_fwd_define_fn_1(drop_if_with_idx)
15672 fplus_fwd_define_fn_1(keep_by_idx)
15673 fplus_fwd_define_fn_1(drop_by_idx)
15674 fplus_fwd_define_fn_1(keep_idxs)
15675 fplus_fwd_define_fn_1(drop_idxs)
15676 fplus_fwd_define_fn_1(drop_idx)
15677 fplus_fwd_define_fn_0(justs)
15678 fplus_fwd_define_fn_0(oks)
15679 fplus_fwd_define_fn_0(errors)
15680 fplus_fwd_define_fn_1(trim_left)
15681 fplus_fwd_define_fn_1(trim_token_left)
15682 fplus_fwd_define_fn_1(trim_right_by)
15683 fplus_fwd_define_fn_1(trim_right)
15684 fplus_fwd_define_fn_1(trim_token_right)
15685 fplus_fwd_define_fn_1(trim_by)
15686 fplus_fwd_define_fn_1(trim)
15687 fplus_fwd_define_fn_1(trim_token)
15688 fplus_fwd_define_fn_1(adjacent_keep_snd_if)
15689 fplus_fwd_define_fn_1(adjacent_drop_fst_if)
15690 fplus_fwd_define_fn_1(adjacent_drop_snd_if)
15691 fplus_fwd_define_fn_1(adjacent_keep_fst_if)
15692 fplus_fwd_define_fn_1(generate_by_idx)
15693 fplus_fwd_define_fn_1(repeat)
15694 fplus_fwd_define_fn_1(infixes)
15695 fplus_fwd_define_fn_3(carthesian_product_with_where)
15696 fplus_fwd_define_fn_2(carthesian_product_with)
15697 fplus_fwd_define_fn_2(carthesian_product_where)
15698 fplus_fwd_define_fn_1(carthesian_product)
15699 fplus_fwd_define_fn_1(carthesian_product_n)
15700 fplus_fwd_define_fn_1(permutations)
15701 fplus_fwd_define_fn_1(combinations)
15702 fplus_fwd_define_fn_1(combinations_with_replacement)
15703 fplus_fwd_define_fn_0(power_set)
15704 fplus_fwd_define_fn_2(iterate)
15705 fplus_fwd_define_fn_1(iterate_maybe)
15706 fplus_fwd_define_fn_1(adjacent_difference_by)
15707 fplus_fwd_define_fn_0(adjacent_difference)
15708 fplus_fwd_define_fn_0(rotate_left)
15709 fplus_fwd_define_fn_0(rotate_right)
15710 fplus_fwd_define_fn_0(rotations_left)
15711 fplus_fwd_define_fn_0(rotations_right)
15712 fplus_fwd_define_fn_2(fill_left)
15713 fplus_fwd_define_fn_2(fill_right)
15714 fplus_fwd_define_fn_0(inits)
15715 fplus_fwd_define_fn_0(tails)
15716 fplus_fwd_define_fn_1(apply_to_pair)
15717 fplus_fwd_define_fn_2(zip_with)
15718 fplus_fwd_define_fn_3(zip_with_3)
15719 fplus_fwd_define_fn_4(zip_with_defaults)
15720 fplus_fwd_define_fn_1(zip)
15721 fplus_fwd_define_fn_1(zip_repeat)
15722 fplus_fwd_define_fn_0(unzip)
15723 fplus_fwd_define_fn_0(fst)
15724 fplus_fwd_define_fn_0(snd)
15725 fplus_fwd_define_fn_1(transform_fst)
15726 fplus_fwd_define_fn_1(transform_snd)
15727 fplus_fwd_define_fn_2(transform_pair)
15728 fplus_fwd_define_fn_0(swap_pair_elems)
15729 fplus_fwd_define_fn_0(swap_pairs_elems)
15730 fplus_fwd_define_fn_0(adjacent_pairs)
15731 fplus_fwd_define_fn_0(overlapping_pairs)
15732 fplus_fwd_define_fn_0(overlapping_pairs_cyclic)
15733 fplus_fwd_define_fn_0(enumerate)
15734 fplus_fwd_define_fn_4(inner_product_with)
15735 fplus_fwd_define_fn_2(inner_product)
15736 fplus_fwd_define_fn_2(first_mismatch_idx_by)
15737 fplus_fwd_define_fn_2(first_mismatch_by)
15738 fplus_fwd_define_fn_2(first_mismatch_idx_on)
15739 fplus_fwd_define_fn_2(first_mismatch_on)
15740 fplus_fwd_define_fn_2(first_mismatch_idx)
15741 fplus_fwd_define_fn_2(first_mismatch)
15742 fplus_fwd_define_fn_2(first_match_idx_by)
15743 fplus_fwd_define_fn_2(first_match_by)
15744 fplus_fwd_define_fn_2(first_match_idx_on)
15745 fplus_fwd_define_fn_2(first_match_on)
15746 fplus_fwd_define_fn_2(first_match_idx)
15747 fplus_fwd_define_fn_2(first_match)
15748 fplus_fwd_define_fn_2(is_in_interval)
15749 fplus_fwd_define_fn_2(is_in_interval_around)
15750 fplus_fwd_define_fn_2(is_in_open_interval)
15751 fplus_fwd_define_fn_2(is_in_open_interval_around)
15752 fplus_fwd_define_fn_2(is_in_closed_interval)
15753 fplus_fwd_define_fn_4(reference_interval)
15754 fplus_fwd_define_fn_2(clamp)
15755 fplus_fwd_define_fn_0(is_negative)
15756 fplus_fwd_define_fn_0(is_positive)
15757 fplus_fwd_define_fn_0(abs)
15758 fplus_fwd_define_fn_1(abs_diff)
15759 fplus_fwd_define_fn_0(square)
15760 fplus_fwd_define_fn_0(cube)
15761 fplus_fwd_define_fn_0(sign)
15762 fplus_fwd_define_fn_0(sign_with_zero)
15763 fplus_fwd_define_fn_0(integral_cast_throw)
15764 fplus_fwd_define_fn_0(integral_cast_clamp)
15765 fplus_fwd_define_fn_0(round)
15766 fplus_fwd_define_fn_0(floor)
15767 fplus_fwd_define_fn_1(floor_to_int_mult)
15768 fplus_fwd_define_fn_1(ceil_to_int_mult)
15769 fplus_fwd_define_fn_0(ceil)
15770 fplus_fwd_define_fn_1(int_power)
15771 fplus_fwd_define_fn_2(min_2_on)
15772 fplus_fwd_define_fn_2(max_2_on)
15773 fplus_fwd_define_fn_1(min_2)
15774 fplus_fwd_define_fn_1(max_2)
15775 fplus_fwd_define_fn_0(deg_to_rad)
15776 fplus_fwd_define_fn_0(rad_to_deg)
15777 fplus_fwd_define_fn_2(normalize_min_max)
15778 fplus_fwd_define_fn_2(normalize_mean_stddev)
15779 fplus_fwd_define_fn_0(standardize)
15780 fplus_fwd_define_fn_1(histogram_using_intervals)
15781 fplus_fwd_define_fn_2(generate_consecutive_intervals)
15782 fplus_fwd_define_fn_3(histogram)
15783 fplus_fwd_define_fn_1(modulo_chain)
15784 fplus_fwd_define_fn_2(line_equation)
15785 fplus_fwd_define_fn_1(find_first_by)
15786 fplus_fwd_define_fn_1(find_last_by)
15787 fplus_fwd_define_fn_1(find_first_idx_by)
15788 fplus_fwd_define_fn_1(find_last_idx_by)
15789 fplus_fwd_define_fn_1(find_first_idx)
15790 fplus_fwd_define_fn_1(find_last_idx)
15791 fplus_fwd_define_fn_1(find_all_idxs_by)
15792 fplus_fwd_define_fn_1(find_all_idxs_of)
15793 fplus_fwd_define_fn_1(find_all_instances_of_token)
15794 fplus_fwd_define_fn_1(find_all_instances_of_token_non_overlapping)
15795 fplus_fwd_define_fn_1(find_first_instance_of_token)
15796 fplus_fwd_define_fn_1(set_includes)
15797 fplus_fwd_define_fn_1(unordered_set_includes)
15798 fplus_fwd_define_fn_1(set_merge)
15799 fplus_fwd_define_fn_1(unordered_set_merge)
15800 fplus_fwd_define_fn_1(set_intersection)
15801 fplus_fwd_define_fn_1(unordered_set_intersection)
15802 fplus_fwd_define_fn_1(set_is_disjoint)
15803 fplus_fwd_define_fn_1(unordered_set_is_disjoint)
15804 fplus_fwd_define_fn_1(set_difference)
15805 fplus_fwd_define_fn_1(unordered_set_difference)
15806 fplus_fwd_define_fn_1(set_symmetric_difference)
15807 fplus_fwd_define_fn_1(unordered_set_symmetric_difference)
15808 fplus_fwd_define_fn_0(sets_intersection)
15809 fplus_fwd_define_fn_0(unordered_sets_intersection)
15810 fplus_fwd_define_fn_1(any_by)
15811 fplus_fwd_define_fn_0(any)
15812 fplus_fwd_define_fn_1(none_by)
15813 fplus_fwd_define_fn_0(none)
15814 fplus_fwd_define_fn_1(minimum_idx_by)
15815 fplus_fwd_define_fn_1(minimum_idx_by_maybe)
15816 fplus_fwd_define_fn_1(maximum_idx_by)
15817 fplus_fwd_define_fn_1(maximum_idx_by_maybe)
15818 fplus_fwd_define_fn_0(minimum_idx)
15819 fplus_fwd_define_fn_0(minimum_idx_maybe)
15820 fplus_fwd_define_fn_0(maximum_idx)
15821 fplus_fwd_define_fn_0(maximum_idx_maybe)
15822 fplus_fwd_define_fn_1(minimum_idx_on)
15823 fplus_fwd_define_fn_1(minimum_idx_on_maybe)
15824 fplus_fwd_define_fn_1(maximum_idx_on)
15825 fplus_fwd_define_fn_1(maximum_idx_on_maybe)
15826 fplus_fwd_define_fn_1(minimum_by)
15827 fplus_fwd_define_fn_1(minimum_by_maybe)
15828 fplus_fwd_define_fn_1(maximum_by)
15829 fplus_fwd_define_fn_1(maximum_by_maybe)
15830 fplus_fwd_define_fn_0(minimum)
15831 fplus_fwd_define_fn_0(minimum_maybe)
15832 fplus_fwd_define_fn_0(maximum)
15833 fplus_fwd_define_fn_0(maximum_maybe)
15834 fplus_fwd_define_fn_1(minimum_on)
15835 fplus_fwd_define_fn_1(minimum_on_maybe)
15836 fplus_fwd_define_fn_1(maximum_on)
15837 fplus_fwd_define_fn_1(maximum_on_maybe)
15838 fplus_fwd_define_fn_0(mean)
15839 fplus_fwd_define_fn_0(mean_obj_div_size_t)
15840 fplus_fwd_define_fn_0(mean_obj_div_double)
15841 fplus_fwd_define_fn_0(mean_using_doubles)
15842 fplus_fwd_define_fn_0(median)
15843 fplus_fwd_define_fn_1(all_unique_by_less)
15844 fplus_fwd_define_fn_0(all_unique_less)
15845 fplus_fwd_define_fn_1(is_infix_of)
15846 fplus_fwd_define_fn_1(is_subsequence_of)
15847 fplus_fwd_define_fn_1(count_if)
15848 fplus_fwd_define_fn_1(count)
15849 fplus_fwd_define_fn_1(is_unique_in_by)
15850 fplus_fwd_define_fn_1(is_unique_in)
15851 fplus_fwd_define_fn_1(is_permutation_of)
15852 fplus_fwd_define_fn_1(fill_pigeonholes_to)
15853 fplus_fwd_define_fn_0(fill_pigeonholes)
15854 fplus_fwd_define_fn_1(fill_pigeonholes_bool_to)
15855 fplus_fwd_define_fn_0(fill_pigeonholes_bool)
15856 fplus_fwd_define_fn_0(present_in_all)
15857 fplus_fwd_define_fn_1(elem_at_idx_or_nothing)
15858 fplus_fwd_define_fn_2(elem_at_idx_or_constant)
15859 fplus_fwd_define_fn_1(elem_at_idx_or_replicate)
15860 fplus_fwd_define_fn_1(elem_at_idx_or_wrap)
15861 fplus_fwd_define_fn_2(extrapolate_replicate)
15862 fplus_fwd_define_fn_2(extrapolate_wrap)
15863 fplus_fwd_define_fn_1(elem_at_float_idx)
15864 fplus_fwd_define_fn_0(pairs_to_map)
15865 fplus_fwd_define_fn_0(pairs_to_map_grouped)
15866 fplus_fwd_define_fn_0(pairs_to_unordered_map_grouped)
15867 fplus_fwd_define_fn_0(map_to_pairs)
15868 fplus_fwd_define_fn_1(transform_map_values)
15869 fplus_fwd_define_fn_2(map_union_with)
15870 fplus_fwd_define_fn_1(map_union)
15871 fplus_fwd_define_fn_0(map_grouped_to_pairs)
15872 fplus_fwd_define_fn_0(get_map_keys)
15873 fplus_fwd_define_fn_0(get_map_values)
15874 fplus_fwd_define_fn_0(swap_keys_and_values)
15875 fplus_fwd_define_fn_1(create_map)
15876 fplus_fwd_define_fn_1(create_map_with)
15877 fplus_fwd_define_fn_1(create_map_grouped)
15878 fplus_fwd_define_fn_1(create_unordered_map)
15879 fplus_fwd_define_fn_1(create_unordered_map_with)
15880 fplus_fwd_define_fn_1(create_unordered_map_grouped)
15881 fplus_fwd_define_fn_1(get_from_map)
15882 fplus_fwd_define_fn_1(get_from_map_unsafe)
15883 fplus_fwd_define_fn_2(get_from_map_with_def)
15884 fplus_fwd_define_fn_1(get_first_from_map)
15885 fplus_fwd_define_fn_1(get_first_from_map_unsafe)
15886 fplus_fwd_define_fn_2(get_first_from_map_with_def)
15887 fplus_fwd_define_fn_1(map_contains)
15888 fplus_fwd_define_fn_1(map_keep_if)
15889 fplus_fwd_define_fn_1(map_drop_if)
15890 fplus_fwd_define_fn_1(map_keep)
15891 fplus_fwd_define_fn_1(map_drop)
15892 fplus_fwd_define_fn_1(map_keep_if_value)
15893 fplus_fwd_define_fn_1(map_drop_if_value)
15894 fplus_fwd_define_fn_1(map_keep_values)
15895 fplus_fwd_define_fn_1(map_drop_values)
15896 fplus_fwd_define_fn_1(map_pluck)
15897 fplus_fwd_define_fn_1(choose)
15898 fplus_fwd_define_fn_2(choose_by)
15899 fplus_fwd_define_fn_1(choose_lazy)
15900 fplus_fwd_define_fn_2(choose_by_lazy)
15901 fplus_fwd_define_fn_1(choose_def)
15902 fplus_fwd_define_fn_2(choose_by_def)
15903 fplus_fwd_define_fn_1(choose_def_lazy)
15904 fplus_fwd_define_fn_2(choose_by_def_lazy)
15905 fplus_fwd_define_fn_1(group_by)
15906 fplus_fwd_define_fn_1(group_on)
15907 fplus_fwd_define_fn_1(group_on_labeled)
15908 fplus_fwd_define_fn_0(group)
15909 fplus_fwd_define_fn_1(group_globally_by)
15910 fplus_fwd_define_fn_1(group_globally_on)
15911 fplus_fwd_define_fn_1(group_globally_on_labeled)
15912 fplus_fwd_define_fn_0(group_globally)
15913 fplus_fwd_define_fn_1(cluster_by)
15914 fplus_fwd_define_fn_2(split_by)
15915 fplus_fwd_define_fn_1(split_by_keep_separators)
15916 fplus_fwd_define_fn_2(split)
15917 fplus_fwd_define_fn_2(split_one_of)
15918 fplus_fwd_define_fn_1(split_keep_separators)
15919 fplus_fwd_define_fn_1(split_at_idx)
15920 fplus_fwd_define_fn_2(insert_at_idx)
15921 fplus_fwd_define_fn_1(partition)
15922 fplus_fwd_define_fn_1(split_at_idxs)
15923 fplus_fwd_define_fn_1(split_every)
15924 fplus_fwd_define_fn_2(split_by_token)
15925 fplus_fwd_define_fn_1(run_length_encode_by)
15926 fplus_fwd_define_fn_0(run_length_encode)
15927 fplus_fwd_define_fn_0(run_length_decode)
15928 fplus_fwd_define_fn_1(span)
15929 fplus_fwd_define_fn_2(divvy)
15930 fplus_fwd_define_fn_1(aperture)
15931 fplus_fwd_define_fn_1(stride)
15932 fplus_fwd_define_fn_1(winsorize)
15933 fplus_fwd_define_fn_1(separate_on)
15934 fplus_fwd_define_fn_0(separate)
15935 fplus_fwd_define_fn_1(transform_with_idx)
15936 fplus_fwd_define_fn_1(transform_and_keep_justs)
15937 fplus_fwd_define_fn_1(transform_and_keep_oks)
15938 fplus_fwd_define_fn_1(transform_and_concat)
15939 fplus_fwd_define_fn_1(replicate_elems)
15940 fplus_fwd_define_fn_0(interleave)
15941 fplus_fwd_define_fn_0(transpose)
15942 fplus_fwd_define_fn_1(shuffle)
15943 fplus_fwd_define_fn_2(sample)
15944 fplus_fwd_define_fn_1(random_element)
15945 fplus_fwd_define_fn_2(random_elements)
15946 fplus_fwd_define_fn_1(apply_functions)
15947 fplus_fwd_define_fn_2(apply_function_n_times)
15948 fplus_fwd_define_fn_1(transform_parallelly)
15949 fplus_fwd_define_fn_2(transform_parallelly_n_threads)
15950 fplus_fwd_define_fn_2(reduce_parallelly)
15951 fplus_fwd_define_fn_3(reduce_parallelly_n_threads)
15952 fplus_fwd_define_fn_1(reduce_1_parallelly)
15953 fplus_fwd_define_fn_2(reduce_1_parallelly_n_threads)
15954 fplus_fwd_define_fn_1(keep_if_parallelly)
15955 fplus_fwd_define_fn_2(keep_if_parallelly_n_threads)
15956 fplus_fwd_define_fn_3(transform_reduce)
15957 fplus_fwd_define_fn_2(transform_reduce_1)
15958 fplus_fwd_define_fn_3(transform_reduce_parallelly)
15959 fplus_fwd_define_fn_4(transform_reduce_parallelly_n_threads)
15960 fplus_fwd_define_fn_2(transform_reduce_1_parallelly)
15961 fplus_fwd_define_fn_3(transform_reduce_1_parallelly_n_threads)
15962 fplus_fwd_define_fn_1(read_value_with_default)
15963 fplus_fwd_define_fn_2(replace_if)
15964 fplus_fwd_define_fn_2(replace_elem_at_idx)
15965 fplus_fwd_define_fn_2(replace_elems)
15966 fplus_fwd_define_fn_2(replace_tokens)
15967 fplus_fwd_define_fn_0(show)
15968 fplus_fwd_define_fn_3(show_cont_with_frame_and_newlines)
15969 fplus_fwd_define_fn_3(show_cont_with_frame)
15970 fplus_fwd_define_fn_1(show_cont_with)
15971 fplus_fwd_define_fn_0(show_cont)
15972 fplus_fwd_define_fn_0(show_maybe)
15973 fplus_fwd_define_fn_0(show_result)
15974 fplus_fwd_define_fn_2(show_float)
15975 fplus_fwd_define_fn_3(show_float_fill_left)
15976 fplus_fwd_define_fn_2(show_fill_left)
15977 fplus_fwd_define_fn_2(show_fill_right)
15978 fplus_fwd_define_fn_0(is_letter_or_digit)
15979 fplus_fwd_define_fn_0(is_whitespace)
15980 fplus_fwd_define_fn_0(is_line_break)
15981 fplus_fwd_define_fn_0(clean_newlines)
15982 fplus_fwd_define_fn_1(split_words)
15983 fplus_fwd_define_fn_1(split_lines)
15984 fplus_fwd_define_fn_0(trim_whitespace_left)
15985 fplus_fwd_define_fn_0(trim_whitespace_right)
15986 fplus_fwd_define_fn_0(trim_whitespace)
15987 fplus_fwd_define_fn_0(to_lower_case)
15988 fplus_fwd_define_fn_1(to_lower_case_loc)
15989 fplus_fwd_define_fn_0(to_upper_case)
15990 fplus_fwd_define_fn_1(to_upper_case_loc)
15991 fplus_fwd_define_fn_2(to_string_fill_left)
15992 fplus_fwd_define_fn_2(to_string_fill_right)
15993 fplus_fwd_define_fn_1(trees_from_sequence)
15994 fplus_fwd_define_fn_1(are_trees_equal)
15995 fplus_fwd_define_fn_0(tree_size)
15996 fplus_fwd_define_fn_0(tree_depth)
15997 fplus_fwd_define_fn_0(flatten_tree_depth_first)
15998 fplus_fwd_define_fn_0(flatten_tree_breadth_first)
15999 fplus_fwd_define_fn_0(show_timed)
16000 fplus_fwd_define_fn_0(make_timed_function)
16001 fplus_fwd_define_fn_0(make_timed_void_function)
16002 fplus_fwd_flip_define_fn_1(is_equal)
16003 fplus_fwd_flip_define_fn_1(is_not_equal)
16004 fplus_fwd_flip_define_fn_1(is_less)
16005 fplus_fwd_flip_define_fn_1(is_less_or_equal)
16006 fplus_fwd_flip_define_fn_1(is_greater)
16007 fplus_fwd_flip_define_fn_1(is_greater_or_equal)
16008 fplus_fwd_flip_define_fn_1(xor_bools)
16009 fplus_fwd_flip_define_fn_1(throw_on_nothing)
16010 fplus_fwd_flip_define_fn_1(as_just_if)
16011 fplus_fwd_flip_define_fn_1(lift_maybe)
16012 fplus_fwd_flip_define_fn_1(and_then_maybe)
16013 fplus_fwd_flip_define_fn_1(elem_at_idx)
16014 fplus_fwd_flip_define_fn_1(elem_at_idx_maybe)
16015 fplus_fwd_flip_define_fn_1(elems_at_idxs)
16016 fplus_fwd_flip_define_fn_1(transform)
16017 fplus_fwd_flip_define_fn_1(transform_convert)
16018 fplus_fwd_flip_define_fn_1(transform_inner)
16019 fplus_fwd_flip_define_fn_1(take)
16020 fplus_fwd_flip_define_fn_1(take_exact)
16021 fplus_fwd_flip_define_fn_1(take_cyclic)
16022 fplus_fwd_flip_define_fn_1(drop)
16023 fplus_fwd_flip_define_fn_1(take_last)
16024 fplus_fwd_flip_define_fn_1(drop_last)
16025 fplus_fwd_flip_define_fn_1(drop_exact)
16026 fplus_fwd_flip_define_fn_1(take_while)
16027 fplus_fwd_flip_define_fn_1(take_last_while)
16028 fplus_fwd_flip_define_fn_1(drop_while)
16029 fplus_fwd_flip_define_fn_1(drop_last_while)
16030 fplus_fwd_flip_define_fn_1(fold_left_1)
16031 fplus_fwd_flip_define_fn_1(reduce_1)
16032 fplus_fwd_flip_define_fn_1(fold_right_1)
16033 fplus_fwd_flip_define_fn_1(scan_left_1)
16034 fplus_fwd_flip_define_fn_1(scan_right_1)
16035 fplus_fwd_flip_define_fn_1(append_elem)
16036 fplus_fwd_flip_define_fn_1(prepend_elem)
16037 fplus_fwd_flip_define_fn_1(append)
16038 fplus_fwd_flip_define_fn_1(append_convert)
16039 fplus_fwd_flip_define_fn_1(interweave)
16040 fplus_fwd_flip_define_fn_1(sort_by)
16041 fplus_fwd_flip_define_fn_1(sort_on)
16042 fplus_fwd_flip_define_fn_1(stable_sort_by)
16043 fplus_fwd_flip_define_fn_1(stable_sort_on)
16044 fplus_fwd_flip_define_fn_1(partial_sort)
16045 fplus_fwd_flip_define_fn_1(nth_element)
16046 fplus_fwd_flip_define_fn_1(unique_by)
16047 fplus_fwd_flip_define_fn_1(unique_on)
16048 fplus_fwd_flip_define_fn_1(intersperse)
16049 fplus_fwd_flip_define_fn_1(join)
16050 fplus_fwd_flip_define_fn_1(join_elem)
16051 fplus_fwd_flip_define_fn_1(is_elem_of_by)
16052 fplus_fwd_flip_define_fn_1(is_elem_of)
16053 fplus_fwd_flip_define_fn_1(nub_by)
16054 fplus_fwd_flip_define_fn_1(nub_on)
16055 fplus_fwd_flip_define_fn_1(all_unique_by_eq)
16056 fplus_fwd_flip_define_fn_1(all_unique_on)
16057 fplus_fwd_flip_define_fn_1(is_strictly_sorted_by)
16058 fplus_fwd_flip_define_fn_1(is_strictly_sorted_on)
16059 fplus_fwd_flip_define_fn_1(is_sorted_by)
16060 fplus_fwd_flip_define_fn_1(is_sorted_on)
16061 fplus_fwd_flip_define_fn_1(is_prefix_of)
16062 fplus_fwd_flip_define_fn_1(is_suffix_of)
16063 fplus_fwd_flip_define_fn_1(all_by)
16064 fplus_fwd_flip_define_fn_1(all_the_same_by)
16065 fplus_fwd_flip_define_fn_1(all_the_same_on)
16066 fplus_fwd_flip_define_fn_1(numbers)
16067 fplus_fwd_flip_define_fn_1(count_occurrences_by)
16068 fplus_fwd_flip_define_fn_1(lexicographical_less)
16069 fplus_fwd_flip_define_fn_1(replicate)
16070 fplus_fwd_flip_define_fn_1(ok_with_default)
16071 fplus_fwd_flip_define_fn_1(from_maybe)
16072 fplus_fwd_flip_define_fn_1(throw_on_error)
16073 fplus_fwd_flip_define_fn_1(lift_result)
16074 fplus_fwd_flip_define_fn_1(and_then_result)
16075 fplus_fwd_flip_define_fn_1(keep_if)
16076 fplus_fwd_flip_define_fn_1(drop_if)
16077 fplus_fwd_flip_define_fn_1(without)
16078 fplus_fwd_flip_define_fn_1(without_any)
16079 fplus_fwd_flip_define_fn_1(keep_if_with_idx)
16080 fplus_fwd_flip_define_fn_1(drop_if_with_idx)
16081 fplus_fwd_flip_define_fn_1(keep_by_idx)
16082 fplus_fwd_flip_define_fn_1(drop_by_idx)
16083 fplus_fwd_flip_define_fn_1(keep_idxs)
16084 fplus_fwd_flip_define_fn_1(drop_idxs)
16085 fplus_fwd_flip_define_fn_1(drop_idx)
16086 fplus_fwd_flip_define_fn_1(trim_left)
16087 fplus_fwd_flip_define_fn_1(trim_token_left)
16088 fplus_fwd_flip_define_fn_1(trim_right_by)
16089 fplus_fwd_flip_define_fn_1(trim_right)
16090 fplus_fwd_flip_define_fn_1(trim_token_right)
16091 fplus_fwd_flip_define_fn_1(trim_by)
16092 fplus_fwd_flip_define_fn_1(trim)
16093 fplus_fwd_flip_define_fn_1(trim_token)
16094 fplus_fwd_flip_define_fn_1(adjacent_keep_snd_if)
16095 fplus_fwd_flip_define_fn_1(adjacent_drop_fst_if)
16096 fplus_fwd_flip_define_fn_1(adjacent_drop_snd_if)
16097 fplus_fwd_flip_define_fn_1(adjacent_keep_fst_if)
16098 fplus_fwd_flip_define_fn_1(generate_by_idx)
16099 fplus_fwd_flip_define_fn_1(repeat)
16100 fplus_fwd_flip_define_fn_1(infixes)
16101 fplus_fwd_flip_define_fn_1(carthesian_product)
16102 fplus_fwd_flip_define_fn_1(carthesian_product_n)
16103 fplus_fwd_flip_define_fn_1(permutations)
16104 fplus_fwd_flip_define_fn_1(combinations)
16105 fplus_fwd_flip_define_fn_1(combinations_with_replacement)
16106 fplus_fwd_flip_define_fn_1(iterate_maybe)
16107 fplus_fwd_flip_define_fn_1(adjacent_difference_by)
16108 fplus_fwd_flip_define_fn_1(apply_to_pair)
16109 fplus_fwd_flip_define_fn_1(zip)
16110 fplus_fwd_flip_define_fn_1(zip_repeat)
16111 fplus_fwd_flip_define_fn_1(transform_fst)
16112 fplus_fwd_flip_define_fn_1(transform_snd)
16113 fplus_fwd_flip_define_fn_1(abs_diff)
16114 fplus_fwd_flip_define_fn_1(floor_to_int_mult)
16115 fplus_fwd_flip_define_fn_1(ceil_to_int_mult)
16116 fplus_fwd_flip_define_fn_1(int_power)
16117 fplus_fwd_flip_define_fn_1(min_2)
16118 fplus_fwd_flip_define_fn_1(max_2)
16119 fplus_fwd_flip_define_fn_1(histogram_using_intervals)
16120 fplus_fwd_flip_define_fn_1(modulo_chain)
16121 fplus_fwd_flip_define_fn_1(find_first_by)
16122 fplus_fwd_flip_define_fn_1(find_last_by)
16123 fplus_fwd_flip_define_fn_1(find_first_idx_by)
16124 fplus_fwd_flip_define_fn_1(find_last_idx_by)
16125 fplus_fwd_flip_define_fn_1(find_first_idx)
16126 fplus_fwd_flip_define_fn_1(find_last_idx)
16127 fplus_fwd_flip_define_fn_1(find_all_idxs_by)
16128 fplus_fwd_flip_define_fn_1(find_all_idxs_of)
16129 fplus_fwd_flip_define_fn_1(find_all_instances_of_token)
16130 fplus_fwd_flip_define_fn_1(find_all_instances_of_token_non_overlapping)
16131 fplus_fwd_flip_define_fn_1(find_first_instance_of_token)
16132 fplus_fwd_flip_define_fn_1(set_includes)
16133 fplus_fwd_flip_define_fn_1(unordered_set_includes)
16134 fplus_fwd_flip_define_fn_1(set_merge)
16135 fplus_fwd_flip_define_fn_1(unordered_set_merge)
16136 fplus_fwd_flip_define_fn_1(set_intersection)
16137 fplus_fwd_flip_define_fn_1(unordered_set_intersection)
16138 fplus_fwd_flip_define_fn_1(set_is_disjoint)
16139 fplus_fwd_flip_define_fn_1(unordered_set_is_disjoint)
16140 fplus_fwd_flip_define_fn_1(set_difference)
16141 fplus_fwd_flip_define_fn_1(unordered_set_difference)
16142 fplus_fwd_flip_define_fn_1(set_symmetric_difference)
16143 fplus_fwd_flip_define_fn_1(unordered_set_symmetric_difference)
16144 fplus_fwd_flip_define_fn_1(any_by)
16145 fplus_fwd_flip_define_fn_1(none_by)
16146 fplus_fwd_flip_define_fn_1(minimum_idx_by)
16147 fplus_fwd_flip_define_fn_1(minimum_idx_by_maybe)
16148 fplus_fwd_flip_define_fn_1(maximum_idx_by)
16149 fplus_fwd_flip_define_fn_1(maximum_idx_by_maybe)
16150 fplus_fwd_flip_define_fn_1(minimum_idx_on)
16151 fplus_fwd_flip_define_fn_1(minimum_idx_on_maybe)
16152 fplus_fwd_flip_define_fn_1(maximum_idx_on)
16153 fplus_fwd_flip_define_fn_1(maximum_idx_on_maybe)
16154 fplus_fwd_flip_define_fn_1(minimum_by)
16155 fplus_fwd_flip_define_fn_1(minimum_by_maybe)
16156 fplus_fwd_flip_define_fn_1(maximum_by)
16157 fplus_fwd_flip_define_fn_1(maximum_by_maybe)
16158 fplus_fwd_flip_define_fn_1(minimum_on)
16159 fplus_fwd_flip_define_fn_1(minimum_on_maybe)
16160 fplus_fwd_flip_define_fn_1(maximum_on)
16161 fplus_fwd_flip_define_fn_1(maximum_on_maybe)
16162 fplus_fwd_flip_define_fn_1(all_unique_by_less)
16163 fplus_fwd_flip_define_fn_1(is_infix_of)
16164 fplus_fwd_flip_define_fn_1(is_subsequence_of)
16165 fplus_fwd_flip_define_fn_1(count_if)
16166 fplus_fwd_flip_define_fn_1(count)
16167 fplus_fwd_flip_define_fn_1(is_unique_in_by)
16168 fplus_fwd_flip_define_fn_1(is_unique_in)
16169 fplus_fwd_flip_define_fn_1(is_permutation_of)
16170 fplus_fwd_flip_define_fn_1(fill_pigeonholes_to)
16171 fplus_fwd_flip_define_fn_1(fill_pigeonholes_bool_to)
16172 fplus_fwd_flip_define_fn_1(elem_at_idx_or_nothing)
16173 fplus_fwd_flip_define_fn_1(elem_at_idx_or_replicate)
16174 fplus_fwd_flip_define_fn_1(elem_at_idx_or_wrap)
16175 fplus_fwd_flip_define_fn_1(elem_at_float_idx)
16176 fplus_fwd_flip_define_fn_1(transform_map_values)
16177 fplus_fwd_flip_define_fn_1(map_union)
16178 fplus_fwd_flip_define_fn_1(create_map)
16179 fplus_fwd_flip_define_fn_1(create_map_with)
16180 fplus_fwd_flip_define_fn_1(create_map_grouped)
16181 fplus_fwd_flip_define_fn_1(create_unordered_map)
16182 fplus_fwd_flip_define_fn_1(create_unordered_map_with)
16183 fplus_fwd_flip_define_fn_1(create_unordered_map_grouped)
16184 fplus_fwd_flip_define_fn_1(get_from_map)
16185 fplus_fwd_flip_define_fn_1(get_from_map_unsafe)
16186 fplus_fwd_flip_define_fn_1(get_first_from_map)
16187 fplus_fwd_flip_define_fn_1(get_first_from_map_unsafe)
16188 fplus_fwd_flip_define_fn_1(map_contains)
16189 fplus_fwd_flip_define_fn_1(map_keep_if)
16190 fplus_fwd_flip_define_fn_1(map_drop_if)
16191 fplus_fwd_flip_define_fn_1(map_keep)
16192 fplus_fwd_flip_define_fn_1(map_drop)
16193 fplus_fwd_flip_define_fn_1(map_keep_if_value)
16194 fplus_fwd_flip_define_fn_1(map_drop_if_value)
16195 fplus_fwd_flip_define_fn_1(map_keep_values)
16196 fplus_fwd_flip_define_fn_1(map_drop_values)
16197 fplus_fwd_flip_define_fn_1(map_pluck)
16198 fplus_fwd_flip_define_fn_1(choose)
16199 fplus_fwd_flip_define_fn_1(choose_lazy)
16200 fplus_fwd_flip_define_fn_1(choose_def)
16201 fplus_fwd_flip_define_fn_1(choose_def_lazy)
16202 fplus_fwd_flip_define_fn_1(group_by)
16203 fplus_fwd_flip_define_fn_1(group_on)
16204 fplus_fwd_flip_define_fn_1(group_on_labeled)
16205 fplus_fwd_flip_define_fn_1(group_globally_by)
16206 fplus_fwd_flip_define_fn_1(group_globally_on)
16207 fplus_fwd_flip_define_fn_1(group_globally_on_labeled)
16208 fplus_fwd_flip_define_fn_1(cluster_by)
16209 fplus_fwd_flip_define_fn_1(split_by_keep_separators)
16210 fplus_fwd_flip_define_fn_1(split_keep_separators)
16211 fplus_fwd_flip_define_fn_1(split_at_idx)
16212 fplus_fwd_flip_define_fn_1(partition)
16213 fplus_fwd_flip_define_fn_1(split_at_idxs)
16214 fplus_fwd_flip_define_fn_1(split_every)
16215 fplus_fwd_flip_define_fn_1(run_length_encode_by)
16216 fplus_fwd_flip_define_fn_1(span)
16217 fplus_fwd_flip_define_fn_1(aperture)
16218 fplus_fwd_flip_define_fn_1(stride)
16219 fplus_fwd_flip_define_fn_1(winsorize)
16220 fplus_fwd_flip_define_fn_1(separate_on)
16221 fplus_fwd_flip_define_fn_1(transform_with_idx)
16222 fplus_fwd_flip_define_fn_1(transform_and_keep_justs)
16223 fplus_fwd_flip_define_fn_1(transform_and_keep_oks)
16224 fplus_fwd_flip_define_fn_1(transform_and_concat)
16225 fplus_fwd_flip_define_fn_1(replicate_elems)
16226 fplus_fwd_flip_define_fn_1(shuffle)
16227 fplus_fwd_flip_define_fn_1(random_element)
16228 fplus_fwd_flip_define_fn_1(apply_functions)
16229 fplus_fwd_flip_define_fn_1(transform_parallelly)
16230 fplus_fwd_flip_define_fn_1(reduce_1_parallelly)
16231 fplus_fwd_flip_define_fn_1(keep_if_parallelly)
16232 fplus_fwd_flip_define_fn_1(read_value_with_default)
16233 fplus_fwd_flip_define_fn_1(show_cont_with)
16234 fplus_fwd_flip_define_fn_1(split_words)
16235 fplus_fwd_flip_define_fn_1(split_lines)
16236 fplus_fwd_flip_define_fn_1(to_lower_case_loc)
16237 fplus_fwd_flip_define_fn_1(to_upper_case_loc)
16238 fplus_fwd_flip_define_fn_1(trees_from_sequence)
16239 fplus_fwd_flip_define_fn_1(are_trees_equal)
16240
16241 } // namespace fwd
16242 } // namespace fplus
16243