summaryrefslogtreecommitdiff
path: root/include/Type.h
blob: 720bfb86f3a90e72f0149474adb7efd0d1e05985 (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
 #pragma once

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

#include "Portable.h"

using std::size_t;

namespace BinSearch {

enum InstrSet { Scalar, SSE, AVX };

#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