#pragma once
namespace ss {
////////////////
// all except
////////////////
template <typename T, auto... Values>
struct ax {
private:
    template <auto X, auto... Xs>
    bool ss_valid_impl(const T& x) const {
        if constexpr (sizeof...(Xs) != 0) {
            return x != X && ss_valid_impl<Xs...>(x);
        }
        return x != X;
    }
public:
    bool ss_valid(const T& value) const {
        return ss_valid_impl<Values...>(value);
    }
    const char* error() const {
        return "value excluded";
    }
};
////////////////
// none except
////////////////
template <typename T, auto... Values>
struct nx {
private:
    template <auto X, auto... Xs>
    bool ss_valid_impl(const T& x) const {
        if constexpr (sizeof...(Xs) != 0) {
            return x == X || ss_valid_impl<Xs...>(x);
        }
        return x == X;
    }
public:
    bool ss_valid(const T& value) const {
        return ss_valid_impl<Values...>(value);
    }
    const char* error() const {
        return "value excluded";
    }
};
////////////////
// greater than or equal to
// greater than
// less than
// less than or equal to
////////////////
template <typename T, auto N>
struct gt {
    bool ss_valid(const T& value) const {
        return value > N;
    }
};
template <typename T, auto N>
struct gte {
    bool ss_valid(const T& value) const {
        return value >= N;
    }
};
template <typename T, auto N>
struct lt {
    bool ss_valid(const T& value) const {
        return value < N;
    }
};
template <typename T, auto N>
struct lte {
    bool ss_valid(const T& value) const {
        return value <= N;
    }
};
////////////////
// in range
////////////////
template <typename T, auto Min, auto Max>
struct ir {
    bool ss_valid(const T& value) const {
        return value >= Min && value <= Max;
    }
};
////////////////
// out of range
////////////////
template <typename T, auto Min, auto Max>
struct oor {
    bool ss_valid(const T& value) const {
        return value < Min || value > Max;
    }
};
////////////////
// non empty
////////////////
template <typename T>
struct ne {
    bool ss_valid(const T& value) const {
        return !value.empty();
    }
    const char* error() const {
        return "empty field";
    }
};
} /* ss */