summaryrefslogtreecommitdiffhomepage
path: root/compat/functional.hpp
blob: 893fe1a0158673509e3470cf5c92172f35f78692 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#pragma once

#include <algorithm>
#include <iterator>
#include <type_traits>

template<typename t>
using remove_qualifiers = std::remove_reference_t<std::remove_cv_t<t>>;

namespace functools
{

template<typename seq_, typename = void>
struct reserver_
{
    static inline void maybe_reserve_space(seq_&, unsigned)
    {
        //qDebug() << "nada";
    }
};

template<typename seq_>
struct reserver_<seq_, decltype(std::declval<seq_>().reserve(0u), (void)0)>
{
    static inline void maybe_reserve_space(seq_& seq, unsigned sz)
    {
        seq.reserve(sz);
    }
};

template<typename seq_>
inline void maybe_reserve_space(seq_& seq, unsigned sz)
{
    reserver_<seq_, void>::maybe_reserve_space(seq, sz);
}

} // ns

template<typename t, t value_>
struct constant final
{
    using type = t;
    constexpr type operator()() const noexcept
    {
        return value_;
    }
    static constexpr type value = value_;

    constant() = delete;
};

template<typename seq_, typename F>
auto map(F&& fun, const seq_& seq)
{
    using seq_type = remove_qualifiers<seq_>;

    seq_type ret;
    std::back_insert_iterator<seq_type> it = std::back_inserter(ret);

    for (const auto& elt : seq)
        it = fun(elt);

    return ret;
}

template<typename seq_, typename F>
auto remove_if_not(F&& fun, const seq_& seq)
{
    using namespace functools;

    using seq_type = remove_qualifiers<seq_>;
    using value_type = typename std::iterator_traits<decltype(std::begin(std::declval<seq_>()))>::value_type;
    using fun_ret_type = decltype(fun(std::declval<const value_type&>()));
    static_assert(std::is_convertible<fun_ret_type, bool>::value, "must return bool");

    seq_type ret;
    maybe_reserve_space(ret, seq.size());

    std::back_insert_iterator<seq_type> it = std::back_inserter(ret);

    for (const value_type& elt : seq)
        if (fun(elt))
            it = elt;

    return ret;
}