summaryrefslogtreecommitdiff
path: root/boost/beast/core/detail/integer_sequence.hpp
blob: 71664229afc426b31354164128ef0fe27f4845f2 (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
135
136
137
138
139
140
141
142
143
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//

#ifndef BOOST_BEAST_DETAIL_INTEGER_SEQUENCE_HPP
#define BOOST_BEAST_DETAIL_INTEGER_SEQUENCE_HPP

#include <boost/config.hpp>
#include <cstddef>
#include <type_traits>
#include <utility>

namespace boost {
namespace beast {
namespace detail {

template<class T, T... Ints>
struct integer_sequence
{
    using value_type = T;
    BOOST_STATIC_ASSERT(std::is_integral<T>::value);

    static std::size_t constexpr static_size = sizeof...(Ints);

    static std::size_t constexpr size()
    {
        return sizeof...(Ints);
    }
};

template<std::size_t... Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;

// This workaround is needed for broken sizeof...
template<class... Args>
struct sizeof_workaround
{
    static std::size_t constexpr size = sizeof... (Args);
};

#ifdef BOOST_MSVC

// This implementation compiles on real MSVC and clang but not gcc

template<class T, unsigned long long N, class Seq>
struct make_integer_sequence_unchecked;

template<class T, unsigned long long N, unsigned long long ...Indices>
struct make_integer_sequence_unchecked<
    T, N, integer_sequence<T, Indices...>>
{
    using type = typename make_integer_sequence_unchecked<
        T, N-1, integer_sequence<T, N-1, Indices...>>::type;
};

template<class T, unsigned long long ...Indices>
struct make_integer_sequence_unchecked<
    T, 0, integer_sequence<T, Indices...>>
{
    using type = integer_sequence<T, Indices...>;
};

template<class T, T N>
struct make_integer_sequence_checked
{
    BOOST_STATIC_ASSERT(std::is_integral<T>::value);
    BOOST_STATIC_ASSERT(N >= 0);

    using type = typename make_integer_sequence_unchecked<
        T, N, integer_sequence<T>>::type;
};

template<class T, T N>
using make_integer_sequence =
    typename make_integer_sequence_checked<T, N>::type;

template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;

template<class... Args>
using index_sequence_for =
    make_index_sequence<sizeof_workaround<Args...>::size>;

#else

// This implementation compiles on gcc but not MSVC

template<std::size_t... Ints>
struct index_tuple
{
    using next = index_tuple<Ints..., sizeof... (Ints)>;

};

template<std::size_t N>
struct build_index_tuple
{
    using type = typename build_index_tuple<N-1>::type::next;
};

template<>
struct build_index_tuple<0>
{
    using type = index_tuple<>;
};

template<class T, T N,
    class Seq = typename build_index_tuple<N>::type
>
struct integer_sequence_helper;

template<class T, T N, std::size_t... Ints>
struct integer_sequence_helper<T, N, index_tuple<Ints...>>
{
    BOOST_STATIC_ASSERT(std::is_integral<T>::value);
    BOOST_STATIC_ASSERT(N >= 0);

    using type = integer_sequence<T, static_cast<T> (Ints)...>;
};

template<class T, T N>
using make_integer_sequence =
    typename integer_sequence_helper<T, N>::type;

template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;

template<class... Args>
using index_sequence_for =
    make_index_sequence<sizeof_workaround<Args...>::size>;

#endif

} // detail
} // beast
} // boost

#endif