#pragma once #include #include #include #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 struct InstrIntTraits; template struct InstrFloatTraits; // base class for algorithm supporting the method: // uint32 scalar(T z) const template 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 struct AlgoVecBase; template struct IntTraits; template <> struct IntTraits { typedef uint32 itype; }; template <> struct IntTraits { typedef uint64 itype; }; template struct Body { template FORCE_INLINE static void iteration(const Expr& e, uint32 *ri, const T* zi, const typename Expr::Constants& cst) { e.vectorial(ri, zi, cst); Body::template iteration(e, ri + D, zi + D, cst); } }; template <> struct Body<0> { template FORCE_INLINE static void iteration(const Expr& e, uint32 *ri, const T* zi, const H&) { } }; template 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::template iteration(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 struct _Pipeliner { template FORCE_INLINE static void go(const Expr& e, Data* d) { e.template run(d); _Pipeliner::go(e, d); } }; template struct _Pipeliner { template FORCE_INLINE static void go(const Expr& e, Data* d) { } }; template struct Pipeliner { template FORCE_INLINE static void go(const Expr& e, Data* d) { _Pipeliner::go(e, d); } }; #if 1 template char is_complete_impl(char (*)[sizeof(T)]); template long is_complete_impl(...); template struct IsComplete { static const bool value = sizeof(is_complete_impl(0)) == sizeof(char); }; #else template std::true_type is_complete_impl(T *); std::false_type is_complete_impl(...); template struct IsComplete : decltype(is_complete_impl(std::declval())) {}; #endif template struct AlgoScalarToVec : AlgoScalarBase { typedef AlgoScalarBase 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 struct conditional { typedef T type; }; template struct conditional { typedef F type; }; template struct CondData { FORCE_INLINE CondData(T x) : v(x) {} FORCE_INLINE operator const T&() const { return v;} private: T v; }; template struct CondData { FORCE_INLINE CondData(T) {} FORCE_INLINE operator const T() const { return 0;} }; template struct BinAlgoBase : Details::conditional< Details::IsComplete>::value , Details::AlgoVecBase , Details::AlgoScalarToVec >::type { typedef typename Details::conditional< Details::IsComplete>::value , Details::AlgoVecBase , Details::AlgoScalarToVec >::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