kelunit/source/kelunit/unit_reduction.h

134 lines
5.3 KiB
C++

#pragma once
#include <cstdint>
#include <type_traits>
namespace kelun {
template<typename... T>
constexpr bool is_always_false = false;
template<typename UnitType, int64_t Exponent>
struct unit_base;
template<typename StorageT, typename... T>
class unit;
namespace impl {
template<typename T, typename U>
class unit_matching;
template<typename... T>
class unit_redux_list {
static_assert(sizeof...(T) == 0, "Template type not supported");
using reduced_typed = unit_redux_list<>;
};
template<typename T0, int64_t E0, typename... TL, int64_t... EL>
struct unit_redux_list<unit_base<T0,E0>, unit_base<TL,EL>...> {
using reduced_type = typename unit_matching<unit_redux_list<unit_base<T0,E0>, unit_base<TL,EL>...>, unit_redux_list<>>::type;
};
template<typename T, typename U, typename V>
class unit_matching_reduce {
public:
static_assert(is_always_false<T, U, V>, "Template type not supported");
};
template<typename T, int64_t E, typename T0, int64_t E0, typename... TL, int64_t... EL, typename... TR, int64_t... ER>
class unit_matching_reduce<unit_base<T,E>, unit_redux_list<unit_base<T0,E0>,unit_base<TL,EL>...>, unit_redux_list<unit_base<TR,ER>...>> {
public:
static constexpr bool is_same = std::is_same_v<T,T0>;
using match_reduce_type = typename std::conditional<is_same, unit_base<T,E+E0>, unit_base<T,E>>::type;
using match_reduce_unit_redux_list = typename std::conditional<is_same, unit_redux_list<unit_base<TR,ER>...>, unit_redux_list<unit_base<TR,ER>..., unit_base<T0,E0>>>::type;
using value_type = typename unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::value_type;
using unit_redux_list_type = typename unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::unit_redux_list_type;
static constexpr int64_t value_num = unit_matching_reduce<match_reduce_type, unit_redux_list<unit_base<TL,EL>...>, match_reduce_unit_redux_list>::value_num;
};
template<typename T, int64_t E, typename... TR, int64_t... ER>
class unit_matching_reduce<unit_base<T,E>, unit_redux_list<>, unit_redux_list<unit_base<TR,ER>...>> {
public:
using value_type = unit_base<T,E>;
using unit_redux_list_type = unit_redux_list<unit_base<TR,ER>...>;
static constexpr int64_t value_num = E;
};
template<typename T, typename U>
class unit_matching {
static_assert(is_always_false<T, U>, "Template type not supported");
};
template<typename... T, int64_t... E>
class unit_matching<unit_redux_list<>,unit_redux_list<unit_base<T,E>...>> {
public:
using type = unit_redux_list<unit_base<T,E>...>;
};
template<typename T0, int64_t E0, typename... TL, int64_t... EL, typename... TR, int64_t... ER>
class unit_matching<unit_redux_list<unit_base<T0,E0>,unit_base<TL,EL>...>, unit_redux_list<unit_base<TR,ER>...>> {
public:
using reduced_value_type = typename unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::value_type;
using reduced_unit_redux_list_type = typename unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::unit_redux_list_type;
static constexpr int64_t reduced_value_num = unit_matching_reduce<unit_base<T0,E0>, unit_redux_list<unit_base<TL,EL>...>, unit_redux_list<>>::value_num;
using reduced_result_unit_redux_list = typename std::conditional<reduced_value_num == 0, unit_redux_list<unit_base<TR,ER>...>, unit_redux_list<unit_base<TR,ER>...,reduced_value_type>>::type;
using type = typename unit_matching<reduced_unit_redux_list_type, reduced_result_unit_redux_list>::type;
};
template<typename List, typename StorageT>
class unit_matching_add_storage {
public:
static_assert(is_always_false<List,StorageT>, "Template type not supported");
};
template<typename StorageT, typename... UnitTypes, int64_t... UnitExponents>
class unit_matching_add_storage<unit_redux_list<unit_base<UnitTypes,UnitExponents>...>, StorageT> {
public:
using type = unit<StorageT, unit_base<UnitTypes,UnitExponents>...>;
};
}
template<typename StorageT, typename... T>
class unit_reduction {
static_assert(is_always_false<StorageT,T...>, "Template type not supported");
};
template<typename StorageT, typename... UnitT, int64_t... UnitE>
class unit_reduction<StorageT, unit_base<UnitT, UnitE>...> {
public:
using list_type = typename impl::unit_matching<impl::unit_redux_list<unit_base<UnitT, UnitE>...>, impl::unit_redux_list<>>::type;
using type = typename impl::unit_matching_add_storage<list_type, StorageT>::type;
};
template<typename StorageT, typename... T>
class unit_invert {
static_assert(is_always_false<StorageT, T...>, "Template type not supported");
};
template<typename StorageT, typename... UnitT, int64_t... UnitE>
class unit_invert<StorageT, unit_base<UnitT, UnitE>...> {
public:
using type = unit<StorageT, unit_base<UnitT, -UnitE>...>;
};
template<typename T, typename U>
class unit_multiplication{
static_assert(is_always_false<T, U>, "Template type not supported");
};
template<typename StorageT, typename... UnitT, int64_t... UnitE, typename... UnitRhsT, int64_t... UnitRhsE>
class unit_multiplication<unit<StorageT, unit_base<UnitT,UnitE>...>, unit<StorageT, unit_base<UnitRhsT, UnitRhsE>...>> {
public:
using type = typename unit_reduction<StorageT, unit_base<UnitT,UnitE>..., unit_base<UnitRhsT, UnitRhsE>...>::type;
};
}