|
| 1 | +#ifndef METAL_LIST_MIN_ELEMENT_HPP |
| 2 | +#define METAL_LIST_MIN_ELEMENT_HPP |
| 3 | + |
| 4 | +#include "../config.hpp" |
| 5 | +#include "../lambda/apply.hpp" |
| 6 | +#include "../lambda/lambda.hpp" |
| 7 | +#include "../number/if.hpp" |
| 8 | +#include "../number/less.hpp" |
| 9 | + |
| 10 | +namespace metal { |
| 11 | + /// \cond |
| 12 | + namespace detail { |
| 13 | + template<class lbd = metal::lambda<metal::less>> |
| 14 | + struct _min_folder; |
| 15 | + } |
| 16 | + /// \endcond |
| 17 | + |
| 18 | + /// \ingroup list |
| 19 | + /// |
| 20 | + /// ### Description |
| 21 | + /// TODO |
| 22 | + /// |
| 23 | + /// \note{The first such element is returned if the ordering relation is [strict].} |
| 24 | + /// [strict]: |
| 25 | + /// https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings |
| 26 | + /// |
| 27 | + /// ### Usage |
| 28 | + /// For any \list `l` and \lambda `lbd` |
| 29 | + /// \code |
| 30 | + /// using result = metal::min_element<l, lbd>; |
| 31 | + /// \endcode |
| 32 | + /// |
| 33 | + /// \pre: For any two \values `val_i` and `val_j` contained in `l` |
| 34 | + /// `metal::invoke<lbd, val_i, val_j>` returns a \number |
| 35 | + /// \returns: \value |
| 36 | + /// \semantics: |
| 37 | + /// TODO |
| 38 | + /// |
| 39 | + /// \tip{`lbd` may be omitted, in which case it defaults to `metal::lambda<metal::less>`.} |
| 40 | + /// |
| 41 | + /// ### Example |
| 42 | + /// \snippet list.cpp min_element |
| 43 | + /// |
| 44 | + /// ### See Also |
| 45 | + /// \see sort |
| 46 | +#if !defined(METAL_WORKAROUND) |
| 47 | + template<class seq, class lbd = metal::lambda<metal::less>> |
| 48 | + using min_element = apply< |
| 49 | + lambda<detail::_min_folder<if_<is_lambda<lbd>, lbd>>::template type>, |
| 50 | + seq>; |
| 51 | +#else |
| 52 | + // MSVC 14 has shabby SFINAE support in case of default alias template args |
| 53 | + template<class seq, class... lbd> |
| 54 | + using min_element = apply< |
| 55 | + lambda<detail::_min_folder<if_<is_lambda<lbd>, lbd>...>::template type>, |
| 56 | + seq>; |
| 57 | +#endif |
| 58 | +} |
| 59 | + |
| 60 | +#include "../lambda/invoke.hpp" |
| 61 | +#include "../value/fold_left.hpp" |
| 62 | + |
| 63 | +namespace metal { |
| 64 | + /// \cond |
| 65 | + namespace detail { |
| 66 | + template<class lbd> |
| 67 | + struct _min_folder { |
| 68 | + template<class x, class y> |
| 69 | + using custom_min = if_<invoke<lbd, y, x>, y, x>; |
| 70 | + // Must use `invoke` in order to support SFINAE. It is tempting to |
| 71 | + // pattern-match the `expr` from `lbd` and use `expr<y, x>`, but |
| 72 | + // the latter approach spoils SFINAE guarantees. |
| 73 | + |
| 74 | + template<class... vals> |
| 75 | + using type = fold_left<lambda<custom_min>, vals...>; |
| 76 | + }; |
| 77 | + } |
| 78 | + /// \endcond |
| 79 | +} |
| 80 | + |
| 81 | +#endif |
0 commit comments