aboutsummaryrefslogtreecommitdiff
path: root/src/common/Utilities/advstd.h
blob: 86edcd4445df0d72bf45a3ef456f06976f60ba17 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TRINITY_ADVSTD_H
#define TRINITY_ADVSTD_H

#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>

// this namespace holds implementations of upcoming stdlib features that our c++ version doesn't have yet
namespace advstd
{
    // C++17 std::apply (constrained to only function pointers, not all callable)
    template <typename... Ts>
    using apply_tuple_type = std::tuple<std::remove_cv_t<std::remove_reference_t<Ts>>...>;
    template <typename R, typename... Ts, std::size_t... I>
    R apply_impl(R(*func)(Ts...), apply_tuple_type<Ts...>&& args, std::index_sequence<I...>)
    {
        return func(std::get<I>(std::forward<apply_tuple_type<Ts...>>(args))...);
    }
    template <typename R, typename... Ts>
    R apply(R(*func)(Ts...), apply_tuple_type<Ts...>&& args)
    {
        return apply_impl(func, std::forward<apply_tuple_type<Ts...>>(args), std::index_sequence_for<Ts...>{});
    }

#define forward_1v(stdname, type) template <typename T> constexpr type stdname ## _v = std::stdname<T>::value
#define forward_2v(stdname, type) template <typename U, typename V> constexpr type stdname ## _v = std::stdname<U,V>::value

    // C++17 std::is_same_v
    forward_2v(is_same, bool);

    // C++17 std::is_integral_v
    forward_1v(is_integral, bool);

    // C++17 std::is_assignable_v
    forward_2v(is_assignable, bool);

    // C++17 std::is_signed_v
    forward_1v(is_signed, bool);

    // C++17 std::is_unsigned_v
    forward_1v(is_unsigned, bool);

    // C++17 std::is_base_of_v
    forward_2v(is_base_of, bool);

    // C++17 std::is_floating_point_v
    forward_1v(is_floating_point, bool);

    // C++17 std::is_pointer_v
    forward_1v(is_pointer, bool);

    // C++17 std::is_reference_v
    forward_1v(is_reference, bool);

    // C++17 std::tuple_size_v
    forward_1v(tuple_size, size_t);

    // C++17 std::is_enum_v
    forward_1v(is_enum, bool);

    // C++17 std::is_arithmetic_v
    forward_1v(is_arithmetic, bool);

    // C++17 std::is_move_assignable_v
    forward_1v(is_move_assignable, bool);

#undef forward_1v
#undef forward_2v

    // C++17 std::size
    template <typename C>
    constexpr auto size(const C& c) { return c.size(); }

    template <typename T, std::size_t N>
    constexpr std::size_t size(const T(&)[N]) noexcept { return N; }

    // C++17 std::data
    template <typename C>
    constexpr auto data(C& c) { return c.data(); }

    template <typename C>
    constexpr auto data(C const& c) { return c.data(); }

    template <typename T, std::size_t N>
    constexpr T* data(T(&a)[N]) noexcept { return a; }

    template <typename T, std::size_t N>
    constexpr T const* data(const T(&a)[N]) noexcept { return a; }

    template <typename T>
    constexpr T const* data(std::initializer_list<T> l) noexcept { return l.begin(); }

    // C++17 std::gcd
    template <typename T1, typename T2>
    constexpr std::enable_if_t<advstd::is_unsigned_v<T1> && advstd::is_unsigned_v<T2>, std::common_type_t<T1, T2>> gcd(T1 m, T2 n)
    {
        if (m < n)
            return gcd(n, m);
        if (!n)
            return m;
        return gcd(n, m%n);
    }

    // C++17 std::lcm
    template <typename T1, typename T2>
    constexpr std::enable_if_t<advstd::is_unsigned_v<T1> && advstd::is_unsigned_v<T2>, std::common_type_t<T1, T2>> lcm(T1 m, T2 n)
    {
        return (m/gcd(m, n))*n;
    }

    // C++20 std::remove_cvref_t
    template <class T>
    using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
}

#endif