Type.h 5.58 KB
Newer Older
Tim Dettmers's avatar
Tim Dettmers committed
1
2
3
4
5
6
7
8
9
10
11
12
 #pragma once

#include <stddef.h>
#include <vector>
#include <limits>

#include "Portable.h"

using std::size_t;

namespace BinSearch {

13
enum InstrSet { Scalar, SSE, AVX, Neon, VSX };
Tim Dettmers's avatar
Tim Dettmers committed
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

#define ALGOENUM(x, b) x,
enum Algos
    {
#include "AlgoXCodes.h"
    };
#undef ALGOENUM

namespace Details {

    template <InstrSet I>
    struct InstrIntTraits;

    template <InstrSet I, typename T>
    struct InstrFloatTraits;

    // base class for algorithm supporting the method:
    //    uint32 scalar(T z) const
    template <typename T, Algos A, typename Enable=void>
    struct AlgoScalarBase;

    // base class for algorithm supporting the following methods, constants and definitions:
    //    static const uint32 nElem
    //    struct Constants;
    //    void initConstants(Constants& cst) const
    //    void vectorial(uint32 *pr, const T *pz, const Constants& cst) const
    // The function vectorial processes nElem items
    template <InstrSet I, typename T, Algos A, typename Enable=void>
    struct AlgoVecBase;

    template <typename T> struct IntTraits;

    template <> struct IntTraits<float>
    {
        typedef uint32 itype;
    };
    template <> struct IntTraits<double>
    {
        typedef uint64 itype;
    };

    template <int N>
    struct Body
    {
        template <uint32 D, typename T, typename Expr>
        FORCE_INLINE static void iteration(const Expr& e, uint32 *ri, const T* zi, const typename Expr::Constants& cst)
        {
            e.vectorial(ri, zi, cst);
            Body<N - 1>::template iteration<D>(e, ri + D, zi + D, cst);
        }

    };

    template <>
    struct Body<0>
    {
        template <uint32 D, typename T, typename Expr, typename H>
        FORCE_INLINE static void iteration(const Expr& e, uint32 *ri, const T* zi, const H&)
        {
        }
    };

    template <typename T, typename Algo>
    struct Loop
    {
        typedef Algo algo_type;
        static const uint32 M = 4;
        static const uint32 D = algo_type::nElem;

        FORCE_INLINE static void loop(const algo_type& e, uint32 *ri, const T* zi, uint32 n)
        {
            typename algo_type::Constants cst;
            e.initConstants(cst);

            uint32 j = 0;
            while (j + (D*M) <= n) {
                Details::Body<M>::template iteration<D>(e, ri + j, zi + j, cst);
                j += (D*M);
            }
            while (j + D <= n) {
                e.vectorial(ri + j, zi + j, cst);
                j += D;
            }
            while (D > 1 && j < n) {
                ri[j] = e.scalar(zi[j]);
                j += 1;
            }
        }
    };

    template <uint32 nIterTot, uint32 nIterLeft>
    struct _Pipeliner
    {
        template <typename Expr, typename Data>
        FORCE_INLINE static void go(const Expr& e, Data* d)
        {
            e.template run<nIterTot - nIterLeft>(d);
            _Pipeliner<nIterTot, nIterLeft - 1>::go(e, d);
        }
    };

    template <uint32 nIterTot>
    struct _Pipeliner<nIterTot, 0>
    {
        template <typename Expr, typename Data>
        FORCE_INLINE static void go(const Expr& e, Data* d)
        {
        }
    };

    template <uint32 nIter>
    struct Pipeliner
    {
        template <typename Expr, typename Data>
        FORCE_INLINE static void go(const Expr& e, Data* d)
        {
            _Pipeliner<nIter, nIter>::go(e, d);
        }
    };


#if 1
    template <class T>
    char is_complete_impl(char (*)[sizeof(T)]);

    template <class>
    long is_complete_impl(...);

    template <class T>
    struct IsComplete
    {
        static const bool value = sizeof(is_complete_impl<T>(0)) == sizeof(char);
    };
#else
    template <class T, std::size_t = sizeof(T)>
    std::true_type is_complete_impl(T *);

    std::false_type is_complete_impl(...);

    template <class T>
    struct IsComplete : decltype(is_complete_impl(std::declval<T*>())) {};
#endif

template <typename T, Algos A>
struct AlgoScalarToVec : AlgoScalarBase<T,A>
{
    typedef AlgoScalarBase<T, A> base_t;

    AlgoScalarToVec(const typename base_t::Data& d) :  base_t(d) {}
    AlgoScalarToVec(const T* px, const uint32 n) :  base_t(px, n) {}

    static const uint32 nElem = 1;

    struct Constants
    {
    };

    void initConstants(Constants& cst) const
    {
    }

    FORCE_INLINE
    void vectorial(uint32 *pr, const T *pz, const Constants& cst) const
    {
        *pr = base_t::scalar(*pz);
    }
};

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

template <typename T, bool C>
struct CondData
{
    FORCE_INLINE CondData(T x) : v(x) {}
    FORCE_INLINE operator const T&() const { return v;}
private:
    T v;
};

template <typename T>
struct CondData<T,false>
{
    FORCE_INLINE CondData(T) {}
    FORCE_INLINE operator const T() const { return 0;}
};

template <InstrSet I, typename T, Algos A, bool L=false>
struct BinAlgoBase : Details::conditional< Details::IsComplete<Details::AlgoVecBase<I, T, A>>::value
                                 , Details::AlgoVecBase<I, T, A>
                                 , Details::AlgoScalarToVec<T,A>
                                 >::type
{
    typedef typename Details::conditional< Details::IsComplete<Details::AlgoVecBase<I, T, A>>::value
                                 , Details::AlgoVecBase<I, T, A>
                                 , Details::AlgoScalarToVec<T,A>
                                 >::type base_t;

    BinAlgoBase(const T* px, const uint32 n) :  base_t(px, n) {}
    BinAlgoBase(const typename base_t::Data& d) : base_t(d) {}
};

} // namespace Details

} // namespace BinSearch