#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace DB { /** Позволяет получить тип результата применения функций +, -, *, /, %, div (целочисленное деление). * Правила отличаются от используемых в C++. */ namespace NumberTraits { typedef boost::mpl::false_ Unsigned; typedef boost::mpl::true_ Signed; typedef boost::mpl::false_ Integer; typedef boost::mpl::true_ Floating; typedef boost::mpl::int_<8> Bits8; typedef boost::mpl::int_<16> Bits16; typedef boost::mpl::int_<32> Bits32; typedef boost::mpl::int_<64> Bits64; typedef boost::mpl::int_<1024> BitsTooMany; struct Error {}; template struct Next; template <> struct Next { typedef Bits16 Type; }; template <> struct Next { typedef Bits32 Type; }; template <> struct Next { typedef Bits64 Type; }; template <> struct Next { typedef Bits64 Type; }; template struct ExactNext { typedef typename Next::Type Type; }; template <> struct ExactNext { typedef BitsTooMany Type; }; template struct Traits; template <> struct Traits { typedef Unsigned Sign; typedef Integer Floatness; typedef Bits8 Bits; }; template <> struct Traits { typedef Unsigned Sign; typedef Integer Floatness; typedef Bits16 Bits; }; template <> struct Traits { typedef Unsigned Sign; typedef Integer Floatness; typedef Bits32 Bits; }; template <> struct Traits { typedef Unsigned Sign; typedef Integer Floatness; typedef Bits64 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Integer Floatness; typedef Bits8 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Integer Floatness; typedef Bits16 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Integer Floatness; typedef Bits32 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Integer Floatness; typedef Bits64 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Floating Floatness; typedef Bits32 Bits; }; template <> struct Traits { typedef Signed Sign; typedef Floating Floatness; typedef Bits64 Bits; }; template struct Construct; template <> struct Construct { typedef UInt8 Type; }; template <> struct Construct { typedef UInt16 Type; }; template <> struct Construct { typedef UInt32 Type; }; template <> struct Construct { typedef UInt64 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float64 Type; }; template <> struct Construct { typedef Int8 Type; }; template <> struct Construct { typedef Int16 Type; }; template <> struct Construct { typedef Int32 Type; }; template <> struct Construct { typedef Int64 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float32 Type; }; template <> struct Construct { typedef Float64 Type; }; template struct Construct { typedef Error Type; }; template bool isErrorType() { return false; } template <> bool isErrorType() { return true; } /** Результат сложения или умножения вычисляется по следующим правилам: * - если один из аргументов с плавающей запятой, то результат - с плавающей запятой, иначе - целый; * - если одно из аргументов со знаком, то результат - со знаком, иначе - без знака; * - результат содержит больше бит (не только значащих), чем максимум в аргументах * (например, UInt8 + Int32 = Int64). */ template struct ResultOfAdditionMultiplication { typedef typename Construct< typename boost::mpl::or_::Sign, typename Traits::Sign>::type, typename boost::mpl::or_::Floatness, typename Traits::Floatness>::type, typename Next::Bits, typename Traits::Bits>::type>::Type>::Type Type; }; template struct ResultOfSubtraction { typedef typename Construct< Signed, typename boost::mpl::or_::Floatness, typename Traits::Floatness>::type, typename Next::Bits, typename Traits::Bits>::type>::Type>::Type Type; }; /** При делении всегда получается число с плавающей запятой. */ template struct ResultOfFloatingPointDivision { typedef typename Construct< Signed, Floating, typename Next::Bits, typename Traits::Bits>::type>::Type>::Type Type; }; /** При целочисленном делении получается число, битность которого равна делимому. */ template struct ResultOfIntegerDivision { typedef typename Construct< typename boost::mpl::or_::Sign, typename Traits::Sign>::type, typename boost::mpl::or_::Floatness, typename Traits::Floatness>::type, typename Traits::Bits>::Type Type; }; /** При взятии остатка получается число, битность которого равна делителю. */ template struct ResultOfModulo { typedef typename Construct< typename boost::mpl::or_::Sign, typename Traits::Sign>::type, Integer, typename Traits::Bits>::Type Type; }; template struct ResultOfNegate { typedef typename Construct< Signed, typename Traits::Floatness, typename boost::mpl::if_< typename Traits::Sign, typename Traits::Bits, typename Next::Bits>::Type>::type>::Type Type; }; /** При побитовых операциях получается целое число, битность которого равна максимальной из битностей аргументов. */ template struct ResultOfBitwise { typedef typename Construct< typename boost::mpl::or_::Sign, typename Traits::Sign>::type, Integer, typename boost::mpl::max< typename boost::mpl::if_< typename Traits::Floatness, Bits64, typename Traits::Bits>::type, typename boost::mpl::if_< typename Traits::Floatness, Bits64, typename Traits::Bits>::type>::type>::Type Type; }; template struct ResultOfBitwiseNot { typedef typename Construct< typename Traits::Sign, Integer, typename Traits::Bits>::Type Type; }; /** Приведение типов для функции if: * 1) UInt, UInt -> UInt * 2) Int, Int -> Int * 3) Float, Float -> Float * 4) UInt, Int -> Int * 5) Float, [U]Int -> Float * 6) UInt64 , Int -> Error * 7) Float, [U]Int64 -> Error */ template struct ResultOfIf { typedef /// 3) и 5) typename boost::mpl::if_< typename boost::mpl::or_< typename Traits::Floatness, typename Traits::Floatness>::type, typename Construct< Signed, Floating, typename boost::mpl::max< /// Этот максимум нужен только потому что if_ всегда вычисляет все аргументы. typename boost::mpl::max< typename boost::mpl::if_< typename Traits::Floatness, typename Traits::Bits, typename ExactNext::Bits>::Type>::type, typename boost::mpl::if_< typename Traits::Floatness, typename Traits::Bits, typename ExactNext::Bits>::Type>::type>::type, Bits32>::type>::Type, /// 1) и 2) typename boost::mpl::if_< typename boost::mpl::equal_to< typename Traits::Sign, typename Traits::Sign>::type, typename boost::mpl::if_< typename boost::mpl::less< typename Traits::Bits, typename Traits::Bits>::type, B, A>::type, /// 4) typename Construct< Signed, Integer, typename boost::mpl::max< typename boost::mpl::if_< typename Traits::Sign, typename Traits::Bits, typename ExactNext::Bits>::Type>::type, typename boost::mpl::if_< typename Traits::Sign, typename Traits::Bits, typename ExactNext::Bits>::Type>::type>::type>::Type>::type>::type Type; }; /** Перед применением оператора % и побитовых операций, операнды приводятся к целым числам. */ template struct ToInteger { typedef typename Construct< typename Traits::Sign, Integer, typename boost::mpl::if_< typename Traits::Floatness, Bits64, typename Traits::Bits>::type>::Type Type; }; } }