Skip to content

Commit 5d2f4e6

Browse files
author
ecrypa
committed
implement min_element
1 parent 1cd7d07 commit 5d2f4e6

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

example/src/list.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -681,5 +681,29 @@ IS_SAME(
681681
>
682682
);
683683
/// [accumulate]
684+
685+
HIDE(
686+
/// [min_element]
687+
using nums = metal::numbers<4, 42, 17, -7, 0>;
688+
689+
IS_SAME(metal::min_element<nums>, metal::number<-7>);
690+
691+
using comp_lt = metal::lambda<metal::less>;
692+
IS_SAME(metal::min_element<nums, comp_lt>, metal::number<-7>);
693+
694+
using comp_gt = metal::lambda<metal::greater>;
695+
IS_SAME(metal::min_element<nums, comp_gt>, metal::number<42>);
696+
697+
using vals = metal::list<const char[3], char[1], char[1], char[3], const char[1]>;
698+
699+
template<typename x, typename y>
700+
using smaller = metal::number<(sizeof(x) < sizeof(y))>;
701+
IS_SAME(metal::min_element<vals, metal::lambda<smaller>>, char[1]);
702+
703+
template<typename x, typename y>
704+
using larger = metal::number<(sizeof(x) > sizeof(y))>;
705+
IS_SAME(metal::min_element<vals, metal::lambda<larger>>, const char[3]);
706+
/// [min_element]
707+
)
684708
)
685709
#endif

include/metal/list.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "list/iota.hpp"
2929
#include "list/join.hpp"
3030
#include "list/list.hpp"
31+
#include "list/min_element.hpp"
3132
#include "list/none_of.hpp"
3233
#include "list/partition.hpp"
3334
#include "list/powerset.hpp"

include/metal/list/min_element.hpp

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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

Comments
 (0)