<commit_before>// maketable_where.h
//
#pragma once
#ifndef __SDL_SYSTEM_MAKETABLE_WHERE_H__
#define __SDL_SYSTEM_MAKETABLE_WHERE_H__

#if defined(SDL_OS_WIN32)
#pragma warning(disable: 4503) //decorated name length exceeded, name was truncated
#endif

namespace sdl { namespace db { namespace make {
namespace where_ {

enum class condition {
    WHERE,          // 0
    IN,             // 1
    NOT,            // 2
    LESS,           // 3
    GREATER,        // 4
    LESS_EQ,        // 5
    GREATER_EQ,     // 6
    BETWEEN,        // 7
    lambda,         // 8
    order,          // 9
    top,            // 10
    _end
};

//FIXME: STContains, STIntersects, STDistance

template<condition T> 
using condition_t = Val2Type<condition, T>;

inline const char * name(condition_t<condition::WHERE>)         { return "WHERE"; }
inline const char * name(condition_t<condition::IN>)            { return "IN"; }
inline const char * name(condition_t<condition::NOT>)           { return "NOT"; }
inline const char * name(condition_t<condition::LESS>)          { return "LESS"; }
inline const char * name(condition_t<condition::GREATER>)       { return "GREATER"; }
inline const char * name(condition_t<condition::LESS_EQ>)       { return "LESS_EQ"; }
inline const char * name(condition_t<condition::GREATER_EQ>)    { return "GREATER_EQ"; }
inline const char * name(condition_t<condition::BETWEEN>)       { return "BETWEEN"; }
inline const char * name(condition_t<condition::lambda>)        { return "lambda"; }
inline const char * name(condition_t<condition::order>)         { return "ORDER_BY"; }
inline const char * name(condition_t<condition::top>)           { return "TOP"; }

template <condition value>
inline const char * condition_name() {
    return name(condition_t<value>());
}

template <condition c1, condition c2>
struct is_condition
{
    enum { value = (c1 == c2) };
};

template <condition c1, condition c2>
struct not_condition
{
    enum { value = (c1 != c2) };
};

template <condition c>
using is_condition_top = is_condition<condition::top, c>;

template <condition c>
using is_condition_order = is_condition<condition::order, c>;

template <condition c>
using is_condition_lambda = is_condition<condition::lambda, c>;

template <condition c>
struct is_condition_search {
    enum { value = (c <= condition::lambda) };
};

template <condition c>
struct is_condition_index {
    enum { value = (c < condition::lambda) && (c != condition::NOT) };
};

template <condition c>
struct has_index_hint {
    enum { value = (c < condition::lambda) };
};

//------------------------------------------------------------------------

enum class INDEX { AUTO, USE, IGNORE }; // index hint

template<INDEX T>
using INDEX_t = Val2Type<INDEX, T>;

inline const char * name(INDEX_t<INDEX::AUTO>)    { return "AUTO"; }
inline const char * name(INDEX_t<INDEX::USE>)     { return "USE"; }
inline const char * name(INDEX_t<INDEX::IGNORE>)  { return "IGNORE"; }

template <INDEX value>
inline const char * index_name() {
    return name(INDEX_t<value>());
}

//---------------------------------------------------------------

template<class T1, class T2>
struct pair_t
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair_t(T1 && v1, T2 && v2)
        : first(std::move(v1))
        , second(std::move(v2))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
    }
    pair_t(T1 && v1)
        : first(std::move(v1))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
        A_STATIC_CHECK_TYPE(NullType, second);
    }
    pair_t(pair_t && src)
        : first(std::move(src.first))
        , second(std::move(src.second))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
    }
};

//---------------------------------------------------------------

template<class val_type>
struct array_value {
private:
    using _Elem = typename std::remove_extent<val_type>::type;
    enum { length = array_info<val_type>::size };
public:
    val_type val;
    array_value(const val_type & in) {
        memcpy_pod(val, in);
        static_assert(length, "");
    }
    template <typename _Elem, size_t N>
    array_value(_Elem const(&in)[N]) {
        static_assert(N <= length, "");
        A_STATIC_ASSERT_TYPE(_Elem[length], val_type);
        A_STATIC_ASSERT_IS_POD(_Elem);
        memcpy(&val, &in, sizeof(in));
        if (N < length) {
            val[N] = _Elem{};
        }
    }
    operator val_type const & () const {
        return val;
    }
};

template <typename T> inline
std::ostream & trace(std::ostream & out, array_value<T> const & d) {
    out << to_string::type(d.val) << " (" << typeid(T).name() << ")";
    return out;
}

template <typename T> inline
std::ostream & trace(std::ostream & out, T const & d) {
    out << d;
    return out;
}

//---------------------------------------------------------------

enum class dim { vector, _1, _2 };

template<condition> struct condition_dim {
    static const dim value = dim::_1;
};
template<> struct condition_dim<condition::BETWEEN> {
    static const dim value = dim::_2;
};
template<> struct condition_dim<condition::IN> {
    static const dim value = dim::vector;
};
template<> struct condition_dim<condition::NOT> {
    static const dim value = dim::vector;
};

//---------------------------------------------------------------

template<condition cond, typename T, dim = condition_dim<cond>::value>
struct search_value;

template<condition cond, typename T>
struct search_value<cond, T, dim::vector> {
    using val_type = T;
    using values_t = std::vector<T>;
    values_t values;
    search_value(std::initializer_list<val_type> in) : values(in) {}
    search_value(search_value && src) : values(std::move(src.values)) {}    
    bool empty() const { 
        return values.empty();
    }
};

template<condition cond, typename T>
struct search_value<cond, T, dim::_1> {
    using val_type = T;
    using values_t = T;
    values_t values;
    search_value(search_value && src) : values(std::move(src.values)) {}    
    search_value(val_type && v1)
        : values(std::move(v1))
    {}
    static bool empty() { return false; }
};

template<condition cond, typename T>
struct search_value<cond, T, dim::_2> {
    using val_type = T;
    using values_t = pair_t<T, T>;
    values_t values;
    search_value(search_value && src) : values(std::move(src.values)) {}    
    search_value(val_type && v1, val_type && v2)
        : values(std::move(v1), std::move(v2))
    {}
    static bool empty() { return false; }
};

//---------------------------------------------------------------

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::vector> {
    using val_type = T[N];    
    using values_t = std::vector<array_value<val_type>>;
    values_t values;
    search_value(val_type const & in): values(1, in) {}
private:
    static void push_back() {}
    template<typename Arg1, typename... Args>
    void push_back(Arg1 const & arg1, Args const &... args) {
        values.push_back(arg1);
        push_back(args...);
    }
public:
    template<typename... Args>
    explicit search_value(Args const &... args) {
        static_assert(sizeof...(args), "");
        values.reserve(sizeof...(args));
        push_back(args...);
    }
    bool empty() const { 
        return values.empty();
    }
};

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::_1> {
    using val_type = T[N];    
    using values_t = array_value<val_type>;
    values_t values;
    template<typename Arg1>
    search_value(Arg1 const & v1): values(v1) {}
    static bool empty() { return false; }
};

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::_2> {
    using val_type = T[N];    
    using values_t = pair_t<array_value<val_type>, array_value<val_type>>;
    values_t values;
    template<typename Arg1, typename Arg2>
    search_value(Arg1 const & v1, Arg2 const & v2)
        : values(v1, v2)
    {}
    static bool empty() { return false; }
};

//---------------------------------------------------------------

template<condition cond, class T, bool is_array, INDEX, dim = condition_dim<cond>::value>
struct SEARCH;

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::vector> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::vector>;
    value_type value;
    SEARCH(std::initializer_list<col_val> in): value(in) {
        static_assert(!T::is_array, "!is_array");
    }
};

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::_1> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::_1>;
    value_type value;
    SEARCH(col_val && v1): value(std::move(v1)) {
        static_assert(!T::is_array, "!is_array");
    }
};

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::_2> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::_2>;
    value_type value;
    SEARCH(col_val && v1, col_val && v2)
        : value(std::move(v1), std::move(v2)) {
        static_assert(!T::is_array, "!is_array");
#if SDL_DEBUG
        SDL_ASSERT_1(!meta::col_less<T, sortorder::ASC>::less(value.values.second, value.values.first));
#endif
    }
};

template<condition _c, class T, INDEX _h, dim _d> // T = col::
struct SEARCH<_c, T, true, _h, _d> {
private:
    using array_type = typename T::val_type;
    using elem_type = typename std::remove_extent<array_type>::type;
    enum { array_size = array_info<array_type>::size };
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, array_type, _d>;
    value_type value;
    template<typename... Args>
    SEARCH(Args const &... args): value(args...) {
        static_assert(T::is_array, "is_array");
        static_assert(array_size, "");
        static_assert(sizeof...(args), "");
        static_assert((cond != condition::WHERE) || (sizeof...(args) == 1), "WHERE");
        static_assert((cond != condition::BETWEEN) || (sizeof...(args) == 2), "BETWEEN");
    }
};

//---------------------------------------------------------------

template<class T, INDEX h = INDEX::AUTO> using WHERE       = SEARCH<condition::WHERE,      T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using IN          = SEARCH<condition::IN,         T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using NOT         = SEARCH<condition::NOT,        T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using LESS        = SEARCH<condition::LESS,       T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using GREATER     = SEARCH<condition::GREATER,    T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using LESS_EQ     = SEARCH<condition::LESS_EQ,    T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using GREATER_EQ  = SEARCH<condition::GREATER_EQ, T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using BETWEEN     = SEARCH<condition::BETWEEN,    T, T::is_array, h>;

template<class F>
struct SELECT_IF {
    static const condition cond = condition::lambda;
    using value_type = F;
    value_type value;
    using col = void;
    SELECT_IF(value_type f) : value(f){}
    template<class record>
    bool operator()(record p) {
        return value(p);
    }
};

template<class fun_type> inline
SELECT_IF<fun_type> IF(fun_type f) {
    return SELECT_IF<fun_type>(f);
}

template<class T, sortorder ord = sortorder::ASC> // T = col::
struct ORDER_BY {
    static_assert(ord != sortorder::NONE, "ORDER_BY");
    static const condition cond = condition::order;
    using col = T;
    static const sortorder value = ord;
    enum { _order = (int)ord };  // workaround for error C2057: expected constant expression (VS 2015)
#if 0 //defined(SDL_OS_WIN32) && (_MSC_VER == 1800) // VS 2013
    // workaround for fatal error C1001: An internal error has occurred in the compiler
    //(compiler file 'f:\dd\vctools\compiler\utc\src\p2\ehexcept.c', line 956)
    ORDER_BY(std::initializer_list<int> tmp) {
        SDL_ASSERT(!tmp.size());
    }
#else
    ORDER_BY() = default; // require: && ORDER_BY (VS 2013)
#endif
};

struct TOP {
    static const condition cond = condition::top;
    using col = void;
    using value_type = size_t;
    value_type value;
    TOP(value_type v) : value(v){}
};

//-------------------------------------------------------------------

enum class operator_ { OR, AND };

template <operator_ T, class U = NullType>
struct operator_list {
    static const operator_ Head = T;
    typedef U Tail;
};

template<operator_ T>
using operator_t = Val2Type<operator_, T>;

inline const char * name(operator_t<operator_::OR>)    { return "OR"; }
inline const char * name(operator_t<operator_::AND>)   { return "AND"; }

template <operator_ value>
inline const char * operator_name() {<commit_msg>where_::condition<commit_after>// maketable_where.h
//
#pragma once
#ifndef __SDL_SYSTEM_MAKETABLE_WHERE_H__
#define __SDL_SYSTEM_MAKETABLE_WHERE_H__

#if defined(SDL_OS_WIN32)
#pragma warning(disable: 4503) //decorated name length exceeded, name was truncated
#endif

namespace sdl { namespace db { namespace make {
namespace where_ {

enum class condition {
    WHERE,          // 0
    IN,             // 1
    NOT,            // 2
    LESS,           // 3
    GREATER,        // 4
    LESS_EQ,        // 5
    GREATER_EQ,     // 6
    BETWEEN,        // 7
    lambda,         // 8
    ORDER_BY,       // 9
    TOP,            // 10
    STContains,     // 11
    STIntersects,   // 12
    STDistance,     // 13
    _end
};

template<condition T> 
using condition_t = Val2Type<condition, T>;

inline const char * name(condition_t<condition::WHERE>)         { return "WHERE"; }
inline const char * name(condition_t<condition::IN>)            { return "IN"; }
inline const char * name(condition_t<condition::NOT>)           { return "NOT"; }
inline const char * name(condition_t<condition::LESS>)          { return "LESS"; }
inline const char * name(condition_t<condition::GREATER>)       { return "GREATER"; }
inline const char * name(condition_t<condition::LESS_EQ>)       { return "LESS_EQ"; }
inline const char * name(condition_t<condition::GREATER_EQ>)    { return "GREATER_EQ"; }
inline const char * name(condition_t<condition::BETWEEN>)       { return "BETWEEN"; }
inline const char * name(condition_t<condition::lambda>)        { return "lambda"; }
inline const char * name(condition_t<condition::ORDER_BY>)      { return "ORDER_BY"; }
inline const char * name(condition_t<condition::TOP>)           { return "TOP"; }
inline const char * name(condition_t<condition::STContains>)    { return "STContains"; }
inline const char * name(condition_t<condition::STIntersects>)  { return "STIntersects"; }
inline const char * name(condition_t<condition::STDistance>)    { return "STDistance"; }

template <condition value>
inline const char * condition_name() {
    return name(condition_t<value>());
}

template <condition c1, condition c2>
struct is_condition
{
    enum { value = (c1 == c2) };
};

template <condition c1, condition c2>
struct not_condition
{
    enum { value = (c1 != c2) };
};

template <condition c>
using is_condition_top = is_condition<condition::TOP, c>;

template <condition c>
using is_condition_order = is_condition<condition::ORDER_BY, c>;

template <condition c>
using is_condition_lambda = is_condition<condition::lambda, c>;

template <condition c>
struct is_condition_search {
    enum { value = (c <= condition::lambda) };
};

template <condition c>
struct is_condition_index {
    enum { value = (c < condition::lambda) && (c != condition::NOT) };
};

template <condition c>
struct has_index_hint {
    enum { value = (c < condition::lambda) };
};

//------------------------------------------------------------------------

enum class INDEX { AUTO, USE, IGNORE }; // index hint

template<INDEX T>
using INDEX_t = Val2Type<INDEX, T>;

inline const char * name(INDEX_t<INDEX::AUTO>)    { return "AUTO"; }
inline const char * name(INDEX_t<INDEX::USE>)     { return "USE"; }
inline const char * name(INDEX_t<INDEX::IGNORE>)  { return "IGNORE"; }

template <INDEX value>
inline const char * index_name() {
    return name(INDEX_t<value>());
}

//---------------------------------------------------------------

template<class T1, class T2>
struct pair_t
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair_t(T1 && v1, T2 && v2)
        : first(std::move(v1))
        , second(std::move(v2))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
    }
    pair_t(T1 && v1)
        : first(std::move(v1))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
        A_STATIC_CHECK_TYPE(NullType, second);
    }
    pair_t(pair_t && src)
        : first(std::move(src.first))
        , second(std::move(src.second))
    {
        A_STATIC_ASSERT_NOT_TYPE(T1, NullType);
    }
};

//---------------------------------------------------------------

template<class val_type>
struct array_value {
private:
    using _Elem = typename std::remove_extent<val_type>::type;
    enum { length = array_info<val_type>::size };
public:
    val_type val;
    array_value(const val_type & in) {
        memcpy_pod(val, in);
        static_assert(length, "");
    }
    template <typename _Elem, size_t N>
    array_value(_Elem const(&in)[N]) {
        static_assert(N <= length, "");
        A_STATIC_ASSERT_TYPE(_Elem[length], val_type);
        A_STATIC_ASSERT_IS_POD(_Elem);
        memcpy(&val, &in, sizeof(in));
        if (N < length) {
            val[N] = _Elem{};
        }
    }
    operator val_type const & () const {
        return val;
    }
};

template <typename T> inline
std::ostream & trace(std::ostream & out, array_value<T> const & d) {
    out << to_string::type(d.val) << " (" << typeid(T).name() << ")";
    return out;
}

template <typename T> inline
std::ostream & trace(std::ostream & out, T const & d) {
    out << d;
    return out;
}

//---------------------------------------------------------------

enum class dim { vector, _1, _2 };

template<condition> struct condition_dim {
    static const dim value = dim::_1;
};
template<> struct condition_dim<condition::BETWEEN> {
    static const dim value = dim::_2;
};
template<> struct condition_dim<condition::IN> {
    static const dim value = dim::vector;
};
template<> struct condition_dim<condition::NOT> {
    static const dim value = dim::vector;
};

//---------------------------------------------------------------

template<condition cond, typename T, dim = condition_dim<cond>::value>
struct search_value;

template<condition cond, typename T>
struct search_value<cond, T, dim::vector> {
    using val_type = T;
    using values_t = std::vector<T>;
    values_t values;
    search_value(std::initializer_list<val_type> in) : values(in) {}
    search_value(search_value && src) : values(std::move(src.values)) {}    
    bool empty() const { 
        return values.empty();
    }
};

template<condition cond, typename T>
struct search_value<cond, T, dim::_1> {
    using val_type = T;
    using values_t = T;
    values_t values;
    search_value(search_value && src) : values(std::move(src.values)) {}    
    search_value(val_type && v1)
        : values(std::move(v1))
    {}
    static bool empty() { return false; }
};

template<condition cond, typename T>
struct search_value<cond, T, dim::_2> {
    using val_type = T;
    using values_t = pair_t<T, T>;
    values_t values;
    search_value(search_value && src) : values(std::move(src.values)) {}    
    search_value(val_type && v1, val_type && v2)
        : values(std::move(v1), std::move(v2))
    {}
    static bool empty() { return false; }
};

//---------------------------------------------------------------

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::vector> {
    using val_type = T[N];    
    using values_t = std::vector<array_value<val_type>>;
    values_t values;
    search_value(val_type const & in): values(1, in) {}
private:
    static void push_back() {}
    template<typename Arg1, typename... Args>
    void push_back(Arg1 const & arg1, Args const &... args) {
        values.push_back(arg1);
        push_back(args...);
    }
public:
    template<typename... Args>
    explicit search_value(Args const &... args) {
        static_assert(sizeof...(args), "");
        values.reserve(sizeof...(args));
        push_back(args...);
    }
    bool empty() const { 
        return values.empty();
    }
};

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::_1> {
    using val_type = T[N];    
    using values_t = array_value<val_type>;
    values_t values;
    template<typename Arg1>
    search_value(Arg1 const & v1): values(v1) {}
    static bool empty() { return false; }
};

template<condition cond, typename T, size_t N>
struct search_value<cond, T[N], dim::_2> {
    using val_type = T[N];    
    using values_t = pair_t<array_value<val_type>, array_value<val_type>>;
    values_t values;
    template<typename Arg1, typename Arg2>
    search_value(Arg1 const & v1, Arg2 const & v2)
        : values(v1, v2)
    {}
    static bool empty() { return false; }
};

//---------------------------------------------------------------

template<condition cond, class T, bool is_array, INDEX, dim = condition_dim<cond>::value>
struct SEARCH;

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::vector> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::vector>;
    value_type value;
    SEARCH(std::initializer_list<col_val> in): value(in) {
        static_assert(!T::is_array, "!is_array");
    }
};

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::_1> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::_1>;
    value_type value;
    SEARCH(col_val && v1): value(std::move(v1)) {
        static_assert(!T::is_array, "!is_array");
    }
};

template<condition _c, class T, INDEX _h> // T = col::
struct SEARCH<_c, T, false, _h, dim::_2> {
private:
    using col_val = typename T::val_type;
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, col_val, dim::_2>;
    value_type value;
    SEARCH(col_val && v1, col_val && v2)
        : value(std::move(v1), std::move(v2)) {
        static_assert(!T::is_array, "!is_array");
#if SDL_DEBUG
        SDL_ASSERT_1(!meta::col_less<T, sortorder::ASC>::less(value.values.second, value.values.first));
#endif
    }
};

template<condition _c, class T, INDEX _h, dim _d> // T = col::
struct SEARCH<_c, T, true, _h, _d> {
private:
    using array_type = typename T::val_type;
    using elem_type = typename std::remove_extent<array_type>::type;
    enum { array_size = array_info<array_type>::size };
public:
    static const condition cond = _c;
    static const INDEX hint = _h;
    using col = T;
    using value_type = search_value<cond, array_type, _d>;
    value_type value;
    template<typename... Args>
    SEARCH(Args const &... args): value(args...) {
        static_assert(T::is_array, "is_array");
        static_assert(array_size, "");
        static_assert(sizeof...(args), "");
        static_assert((cond != condition::WHERE) || (sizeof...(args) == 1), "WHERE");
        static_assert((cond != condition::BETWEEN) || (sizeof...(args) == 2), "BETWEEN");
    }
};

//---------------------------------------------------------------

template<class T, INDEX h = INDEX::AUTO> using WHERE       = SEARCH<condition::WHERE,      T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using IN          = SEARCH<condition::IN,         T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using NOT         = SEARCH<condition::NOT,        T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using LESS        = SEARCH<condition::LESS,       T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using GREATER     = SEARCH<condition::GREATER,    T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using LESS_EQ     = SEARCH<condition::LESS_EQ,    T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using GREATER_EQ  = SEARCH<condition::GREATER_EQ, T, T::is_array, h>;
template<class T, INDEX h = INDEX::AUTO> using BETWEEN     = SEARCH<condition::BETWEEN,    T, T::is_array, h>;

template<class F>
struct SELECT_IF {
    static const condition cond = condition::lambda;
    using value_type = F;
    value_type value;
    using col = void;
    SELECT_IF(value_type f) : value(f){}
    template<class record>
    bool operator()(record p) {
        return value(p);
    }
};

template<class fun_type> inline
SELECT_IF<fun_type> IF(fun_type f) {
    return SELECT_IF<fun_type>(f);
}

template<class T, sortorder ord = sortorder::ASC> // T = col::
struct ORDER_BY {
    static_assert(ord != sortorder::NONE, "ORDER_BY");
    static const condition cond = condition::ORDER_BY;
    using col = T;
    static const sortorder value = ord;
    enum { _order = (int)ord };  // workaround for error C2057: expected constant expression (VS 2015)
#if 0 //defined(SDL_OS_WIN32) && (_MSC_VER == 1800) // VS 2013
    // workaround for fatal error C1001: An internal error has occurred in the compiler
    //(compiler file 'f:\dd\vctools\compiler\utc\src\p2\ehexcept.c', line 956)
    ORDER_BY(std::initializer_list<int> tmp) {
        SDL_ASSERT(!tmp.size());
    }
#else
    ORDER_BY() = default; // require: && ORDER_BY (VS 2013)
#endif
};

struct TOP {
    static const condition cond = condition::TOP;
    using col = void;
    using value_type = size_t;
    value_type value;
    TOP(value_type v) : value(v){}
};

//-------------------------------------------------------------------

enum class operator_ { OR, AND };

template <operator_ T, class U = NullType>
struct operator_list {
    static const operator_ Head = T;
    typedef U Tail;
};

template<operator_ T>
using operator_t = Val2Type<operator_, T>;

inline const char * name(operator_t<operator_::OR>)    { return "OR"; }
inline const char * name(operator_t<operator_::AND>)   { return "AND"; }

template <operator_ value>
inline const char * operator_name() {
{'fraction_non_alphanumeric': 0.1776957163958641, 'fraction_numerical': 0.009231905465288036, 'mean_word_length': 2.8061841180604357, 'pattern_counts': {'":': 0, '<': 282, '<?xml version=': 0, '>': 252, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2749938', 'n_tokens_mistral': 8950, 'n_tokens_neox': 8741, 'n_words': 2222}