summaryrefslogtreecommitdiffstats
path: root/third_party/xsimd/include/xsimd/types/xsimd_batch_constant.hpp
blob: 0de9c8ad42c1a3d4903a67016ce489599b80cdfe (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/***************************************************************************
 * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
 * Martin Renou                                                             *
 * Copyright (c) QuantStack                                                 *
 * Copyright (c) Serge Guelton                                              *
 *                                                                          *
 * Distributed under the terms of the BSD 3-Clause License.                 *
 *                                                                          *
 * The full license is in the file LICENSE, distributed with this software. *
 ****************************************************************************/

#ifndef XSIMD_BATCH_CONSTANT_HPP
#define XSIMD_BATCH_CONSTANT_HPP

#include "./xsimd_batch.hpp"
#include "./xsimd_utils.hpp"

namespace xsimd
{
    /**
     * @brief batch of boolean constant
     *
     * Abstract representation of a batch of boolean constants.
     *
     * @tparam batch_type the type of the associated batch values.
     * @tparam Values boolean constant represented by this batch
     **/
    template <class batch_type, bool... Values>
    struct batch_bool_constant
    {

    public:
        static constexpr std::size_t size = sizeof...(Values);
        using arch_type = typename batch_type::arch_type;
        using value_type = bool;
        static_assert(sizeof...(Values) == batch_type::size, "consistent batch size");

        constexpr operator batch_bool<typename batch_type::value_type, arch_type>() const noexcept { return { Values... }; }

        constexpr bool get(size_t i) const noexcept
        {
            return std::array<value_type, size> { { Values... } }[i];
        }

        static constexpr int mask() noexcept
        {
            return mask_helper(0, static_cast<int>(Values)...);
        }

    private:
        static constexpr int mask_helper(int acc) noexcept { return acc; }

        template <class... Tys>
        static constexpr int mask_helper(int acc, int mask, Tys... masks) noexcept
        {
            return mask_helper(acc | mask, (masks << 1)...);
        }

        struct logical_or
        {
            constexpr bool operator()(bool x, bool y) const { return x || y; }
        };
        struct logical_and
        {
            constexpr bool operator()(bool x, bool y) const { return x && y; }
        };
        struct logical_xor
        {
            constexpr bool operator()(bool x, bool y) const { return x ^ y; }
        };

        template <class F, class SelfPack, class OtherPack, size_t... Indices>
        static constexpr batch_bool_constant<batch_type, F()(std::tuple_element<Indices, SelfPack>::type::value, std::tuple_element<Indices, OtherPack>::type::value)...>
        apply(detail::index_sequence<Indices...>)
        {
            return {};
        }

        template <class F, bool... OtherValues>
        static constexpr auto apply(batch_bool_constant<batch_type, Values...>, batch_bool_constant<batch_type, OtherValues...>)
            -> decltype(apply<F, std::tuple<std::integral_constant<bool, Values>...>, std::tuple<std::integral_constant<bool, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>()))
        {
            static_assert(sizeof...(Values) == sizeof...(OtherValues), "compatible constant batches");
            return apply<F, std::tuple<std::integral_constant<bool, Values>...>, std::tuple<std::integral_constant<bool, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>());
        }

    public:
#define MAKE_BINARY_OP(OP, NAME)                                                            \
    template <bool... OtherValues>                                                          \
    constexpr auto operator OP(batch_bool_constant<batch_type, OtherValues...> other) const \
        -> decltype(apply<NAME>(*this, other))                                              \
    {                                                                                       \
        return apply<NAME>(*this, other);                                                   \
    }

        MAKE_BINARY_OP(|, logical_or)
        MAKE_BINARY_OP(||, logical_or)
        MAKE_BINARY_OP(&, logical_and)
        MAKE_BINARY_OP(&&, logical_and)
        MAKE_BINARY_OP(^, logical_xor)

#undef MAKE_BINARY_OP

        constexpr batch_bool_constant<batch_type, !Values...> operator!() const
        {
            return {};
        }

        constexpr batch_bool_constant<batch_type, !Values...> operator~() const
        {
            return {};
        }
    };

    /**
     * @brief batch of integral constants
     *
     * Abstract representation of a batch of integral constants.
     *
     * @tparam batch_type the type of the associated batch values.
     * @tparam Values constants represented by this batch
     **/
    template <class batch_type, typename batch_type::value_type... Values>
    struct batch_constant
    {
        static constexpr std::size_t size = sizeof...(Values);
        using arch_type = typename batch_type::arch_type;
        using value_type = typename batch_type::value_type;
        static_assert(sizeof...(Values) == batch_type::size, "consistent batch size");

        /**
         * @brief Generate a batch of @p batch_type from this @p batch_constant
         */
        inline operator batch_type() const noexcept { return { Values... }; }

        /**
         * @brief Get the @p i th element of this @p batch_constant
         */
        constexpr value_type get(size_t i) const noexcept
        {
            return get(i, std::array<value_type, size> { Values... });
        }

    private:
        constexpr value_type get(size_t i, std::array<value_type, size> const& values) const noexcept
        {
            return values[i];
        }

        struct arithmetic_add
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x + y; }
        };
        struct arithmetic_sub
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x - y; }
        };
        struct arithmetic_mul
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x * y; }
        };
        struct arithmetic_div
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x / y; }
        };
        struct arithmetic_mod
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x % y; }
        };
        struct binary_and
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x & y; }
        };
        struct binary_or
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x | y; }
        };
        struct binary_xor
        {
            constexpr value_type operator()(value_type x, value_type y) const { return x ^ y; }
        };

        template <class F, class SelfPack, class OtherPack, size_t... Indices>
        static constexpr batch_constant<batch_type, F()(std::tuple_element<Indices, SelfPack>::type::value, std::tuple_element<Indices, OtherPack>::type::value)...>
        apply(detail::index_sequence<Indices...>)
        {
            return {};
        }

        template <class F, value_type... OtherValues>
        static constexpr auto apply(batch_constant<batch_type, Values...>, batch_constant<batch_type, OtherValues...>)
            -> decltype(apply<F, std::tuple<std::integral_constant<value_type, Values>...>, std::tuple<std::integral_constant<value_type, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>()))
        {
            static_assert(sizeof...(Values) == sizeof...(OtherValues), "compatible constant batches");
            return apply<F, std::tuple<std::integral_constant<value_type, Values>...>, std::tuple<std::integral_constant<value_type, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>());
        }

    public:
#define MAKE_BINARY_OP(OP, NAME)                                                       \
    template <value_type... OtherValues>                                               \
    constexpr auto operator OP(batch_constant<batch_type, OtherValues...> other) const \
        -> decltype(apply<NAME>(*this, other))                                         \
    {                                                                                  \
        return apply<NAME>(*this, other);                                              \
    }

        MAKE_BINARY_OP(+, arithmetic_add)
        MAKE_BINARY_OP(-, arithmetic_sub)
        MAKE_BINARY_OP(*, arithmetic_mul)
        MAKE_BINARY_OP(/, arithmetic_div)
        MAKE_BINARY_OP(%, arithmetic_mod)
        MAKE_BINARY_OP(&, binary_and)
        MAKE_BINARY_OP(|, binary_or)
        MAKE_BINARY_OP(^, binary_xor)

#undef MAKE_BINARY_OP

        constexpr batch_constant<batch_type, (value_type)-Values...> operator-() const
        {
            return {};
        }

        constexpr batch_constant<batch_type, (value_type) + Values...> operator+() const
        {
            return {};
        }

        constexpr batch_constant<batch_type, (value_type)~Values...> operator~() const
        {
            return {};
        }
    };

    namespace detail
    {
        template <class batch_type, class G, std::size_t... Is>
        inline constexpr auto make_batch_constant(detail::index_sequence<Is...>) noexcept
            -> batch_constant<batch_type, (typename batch_type::value_type)G::get(Is, sizeof...(Is))...>
        {
            return {};
        }
        template <class batch_type, class G, std::size_t... Is>
        inline constexpr auto make_batch_bool_constant(detail::index_sequence<Is...>) noexcept
            -> batch_bool_constant<batch_type, G::get(Is, sizeof...(Is))...>
        {
            return {};
        }

    } // namespace detail

    /**
     * @brief Build a @c batch_constant out of a generator function
     *
     * @tparam batch_type type of the (non-constant) batch to build
     * @tparam G type used to generate that batch. That type must have a static
     * member @c get that's used to generate the batch constant. Conversely, the
     * generated batch_constant has value `{G::get(0, batch_size), ... , G::get(batch_size - 1, batch_size)}`
     *
     * The following generator produces a batch of `(n - 1, 0, 1, ... n-2)`
     *
     * @code
     * struct Rot
     * {
     *     static constexpr unsigned get(unsigned i, unsigned n)
     *     {
     *         return (i + n - 1) % n;
     *     }
     * };
     * @endcode
     */
    template <class batch_type, class G>
    inline constexpr auto make_batch_constant() noexcept -> decltype(detail::make_batch_constant<batch_type, G>(detail::make_index_sequence<batch_type::size>()))
    {
        return detail::make_batch_constant<batch_type, G>(detail::make_index_sequence<batch_type::size>());
    }

    template <class batch_type, class G>
    inline constexpr auto make_batch_bool_constant() noexcept
        -> decltype(detail::make_batch_bool_constant<batch_type, G>(
            detail::make_index_sequence<batch_type::size>()))
    {
        return detail::make_batch_bool_constant<batch_type, G>(
            detail::make_index_sequence<batch_type::size>());
    }

} // namespace xsimd

#endif