Program Listing for File concepts.hpp

Return to documentation for file (include/concepts.hpp)

#pragma once

#include "htlist.hpp"
#include <complex>
#include <cstdint>
#include <functional>
#include <map>
#include <set>
#include <type_traits>
#include <variant>

namespace ctql {
    template <typename T>
    concept is_bits_array
        = std::is_trivially_copyable_v<typename T::value_type> && std::is_trivially_copyable_v<T>;

    template <typename T>
    concept is_complex = requires(T t) {
        typename T::value_type;
        std::is_same_v<T, std::complex<typename T::value_type>>;
    };

    template <typename T>
    concept is_vector = requires(T t) {
        typename T::value_type;
        std::is_same_v<T, std::vector<typename T::value_type>>;
    };

    template <typename T>
    concept is_map = requires(T t) {
        typename T::key_type;
        typename T::mapped_type;
        std::is_same_v<T, std::map<typename T::key_type, typename T::mapped_Type>>
            or std::is_same_v<T, std::unordered_map<typename T::key_type, typename T::mapped_Type>>
            or std::is_same_v<T, std::multimap<typename T::key_type, typename T::mapped_Type>>;
    };

    template <typename T>
    concept is_set = requires(T t) {
        typename T::value_type;
        std::is_same_v<T, std::set<typename T::value_type>>;
    };

    template <typename T>
    concept is_pair = requires(T) {
        std::is_same_v<T, std::pair<typename T::first_type, typename T::second_type>>;
    };

    namespace detail {
        template <typename T, uint64_t... Ns>
        constexpr bool is_tuple_aux(std::index_sequence<Ns...>) {
            return std::is_same_v<T, std::tuple<std::tuple_element_t<Ns, T>...>>;
        }
    } // namespace detail

    template <typename T>
    struct is_std_array : std::false_type { };

    template <typename T, std::size_t N>
    struct is_std_array<std::array<T, N>> : std::true_type { };

    template <typename T>
    concept is_array = requires(T t) {
        typename T::value_type;
        std::is_same_v<T, std::array<typename T::value_type, std::tuple_size<T>::value>>;
    };

    template <typename T>
    concept is_tuple
        = detail::is_tuple_aux<T>(std::make_index_sequence<std::tuple_size<T>::value>());

    template <class T, class U>
    struct is_same_or_const {
        static constexpr bool value = false;
    };

    template <class T>
    struct is_same_or_const<T, T> {
        static constexpr bool value = true;
    };

    template <class T>
    struct is_same_or_const<T, const T> {
        static constexpr bool value = true;
    };

    template <typename T, typename U>
    concept is_same = std::is_same_v<T, U>;

#define $type_eq(T1, T2) std::is_same_v<T1, T2>

    template <typename T, typename U>
    concept is_not_same = not is_same<T, U>;

    template <typename T, typename U>
    concept is_conv_to = std::is_convertible_v<T, U>;

    template <typename T, typename U>
    concept is_not_conv_to = not is_conv_to<T, U>;

    template <typename T, typename U>
    concept is
        = std::conditional_t<std::is_void_v<T>, std::is_void<U>, is_same_or_const<T, U>>::value;

    template <typename T, typename U>
    concept is_not = not is<T, U>;

    template <typename T>
    struct function_traits;

    template <typename Return_t, typename... Args_t>
    struct function_traits<Return_t(Args_t...)> {
        // as C literal function
        using as_c_function = Return_t(Args_t...);

        // as std::function
        using as_std_function = std::function<Return_t(Args_t...)>;

        // return type
        using return_t = typename as_std_function::result_type;

        // number of arguments
        static constexpr uint64_t n_args = sizeof...(Args_t);

        // all argument types as tuple type
        using argument_ts = std::tuple<Args_t...>;

        // type of i-th argument
        template <uint64_t i>
        using argument_type = std::tuple_element_t<i, argument_ts>;
    };

    template <typename T, uint64_t i>
    using get_nth_argument_t = std::tuple_element_t<i, typename function_traits<T>::argument_ts>;

    namespace detail {
        template <typename T>
        struct as_c_function;

        template <typename Return_t, typename... Args_t>
        struct as_c_function<Return_t(Args_t...)> {
            using value = Return_t(Args_t...);
        };

        template <typename Return_t, typename... Args_t>
        struct as_c_function<std::function<Return_t(Args_t...)>> {
            using value = Return_t(Args_t...);
        };

        template <typename T>
        using as_c_function_v = typename as_c_function<T>::value;
    } // namespace detail

    template <typename T, typename Return_t, typename... Args_t>
    concept is_function_with_signature
        = std::is_invocable_v<detail::as_c_function_v<T>, Args_t...>
          and std::conditional_t<
              std::is_void_v<Return_t>,
              std::is_void<typename function_traits<detail::as_c_function_v<T>>::return_t>,
              std::is_same<
                  typename function_traits<detail::as_c_function_v<T>>::return_t,
                  Return_t>>::value;



    // ---------- extraction helpers ----------
    template <typename>
    struct to_variant;
    template <typename... Ms>
    struct to_variant<detail::HTList<Ms...>> {
        using type = std::variant<typename Ms::type...>;
    };

    template <typename>
    struct to_tuple;
    template <typename... Ms>
    struct to_tuple<detail::HTList<Ms...>> {
        using type = std::tuple<typename Ms::type...>;
    };
}