// Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_TEST_MODULE #define BOOST_TEST_MODULE test_promote_integral #endif #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_GEOMETRY_TEST_DEBUG) && defined(BOOST_HAS_INT128) std::ostream& operator<<(std::ostream& os, boost::int128_type i) { if (i == 0) { os << "0"; return os; } if (i < 0) { i = -i; os << "-"; } std::stringstream stream; while (i > 0) { stream << static_cast(i % 10); i /= 10; } std::string str = stream.str(); std::reverse(str.begin(), str.end()); os << str; return os; } #endif namespace bg = boost::geometry; template < typename T, bool Signed = boost::is_fundamental::type::value && ! boost::is_unsigned::type::value > struct absolute_value { static inline T apply(T const& t) { return t < 0 ? -t : t; } }; template struct absolute_value { static inline T apply(T const& t) { return t; } }; template < typename Integral, typename Promoted, bool Signed = ! boost::is_unsigned::type::value > struct test_max_values { static inline void apply() { Promoted max_value = std::numeric_limits::max(); max_value *= max_value; BOOST_CHECK(absolute_value::apply(max_value) == max_value); } }; template struct test_max_values { static inline void apply() { Promoted max_value = std::numeric_limits::max(); Promoted max_value_sqr = max_value * max_value; BOOST_CHECK(max_value_sqr < std::numeric_limits::max() && max_value_sqr > max_value); } }; template struct test_promote_integral { template static inline void apply(std::string const& case_id) { typedef typename bg::promote_integral < Type, PromoteUnsignedToUnsigned >::type promoted_integral_type; bool const same_types = boost::is_same < promoted_integral_type, ExpectedPromotedType >::type::value; BOOST_CHECK_MESSAGE(same_types, "case ID: " << case_id << "input type: " << typeid(Type).name() << "; detected: " << typeid(promoted_integral_type).name() << "; expected: " << typeid(ExpectedPromotedType).name()); if (BOOST_GEOMETRY_CONDITION((! boost::is_same < Type, promoted_integral_type >::type::value))) { test_max_values::apply(); } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "case ID: " << case_id << std::endl << "type : " << typeid(Type).name() << ", sizeof: " << sizeof(Type) << ", max value: " << std::numeric_limits::max() << std::endl; std::cout << "detected promoted type : " << typeid(promoted_integral_type).name() << ", sizeof: " << sizeof(promoted_integral_type) << ", max value: " << std::numeric_limits::max() << std::endl; std::cout << "expected promoted type : " << typeid(ExpectedPromotedType).name() << ", sizeof: " << sizeof(ExpectedPromotedType) << ", max value: " << std::numeric_limits::max() << std::endl; std::cout << std::endl; #endif } }; template < typename T, bool PromoteUnsignedToUnsigned = false, bool IsSigned = ! boost::is_unsigned::type::value > struct test_promotion { static inline void apply(std::string case_id) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** " << (IsSigned ? "signed" : "unsigned") << " -> signed ***" << std::endl; #endif typedef test_promote_integral tester; case_id += (PromoteUnsignedToUnsigned ? "-t" : "-f"); std::size_t min_size = 2 * sizeof(T) - 1; if (BOOST_GEOMETRY_CONDITION(! IsSigned)) { min_size += 2; } if (BOOST_GEOMETRY_CONDITION(sizeof(short) >= min_size)) { tester::template apply(case_id); } else if (BOOST_GEOMETRY_CONDITION(sizeof(int) >= min_size)) { tester::template apply(case_id); } else if (BOOST_GEOMETRY_CONDITION(sizeof(long) >= min_size)) { tester::template apply(case_id); } #if defined(BOOST_HAS_LONG_LONG) else if (BOOST_GEOMETRY_CONDITION(sizeof(boost::long_long_type) >= min_size)) { tester::template apply(case_id); } #endif #if defined(BOOST_HAS_INT128) else if (BOOST_GEOMETRY_CONDITION(sizeof(boost::int128_type) >= min_size)) { tester::template apply(case_id); } #endif else { #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) namespace bm = boost::multiprecision; typedef bm::number < bm::cpp_int_backend < 2 * CHAR_BIT * sizeof(T) + (IsSigned ? -1 : 1), 2 * CHAR_BIT * sizeof(T) + (IsSigned ? -1 : 1), bm::signed_magnitude, bm::unchecked, void > > multiprecision_integer_type; tester::template apply(case_id); #else tester::template apply(case_id); #endif } } }; template struct test_promotion { static inline void apply(std::string case_id) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** unsigned -> unsigned ***" << std::endl; #endif case_id += "-t"; typedef test_promote_integral tester; std::size_t const min_size = 2 * sizeof(T); if (BOOST_GEOMETRY_CONDITION(sizeof(unsigned short) >= min_size)) { tester::apply(case_id); } else if (BOOST_GEOMETRY_CONDITION(sizeof(unsigned int) >= min_size)) { tester::apply(case_id); } else if (BOOST_GEOMETRY_CONDITION(sizeof(unsigned long) >= min_size)) { tester::apply(case_id); } else if (BOOST_GEOMETRY_CONDITION(sizeof(std::size_t) >= min_size)) { tester::apply(case_id); } else { #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) namespace bm = boost::multiprecision; typedef bm::number < bm::cpp_int_backend < CHAR_BIT * min_size, CHAR_BIT * min_size, bm::unsigned_magnitude, bm::unchecked, void > > multiprecision_integer_type; tester::apply(case_id); #else tester::apply(case_id); #endif } } }; BOOST_AUTO_TEST_CASE( test_char ) { test_promotion::apply("char"); test_promotion::apply("char"); test_promotion::apply("schar"); test_promotion::apply("schar"); test_promotion::apply("uchar"); test_promotion::apply("uchar"); } BOOST_AUTO_TEST_CASE( test_short ) { test_promotion::apply("short"); test_promotion::apply("short"); test_promotion::apply("ushort"); test_promotion::apply("ushort"); } BOOST_AUTO_TEST_CASE( test_int ) { test_promotion::apply("int"); test_promotion::apply("int"); test_promotion::apply("uint"); test_promotion::apply("uint"); } BOOST_AUTO_TEST_CASE( test_long ) { test_promotion::apply("long"); test_promotion::apply("long"); test_promotion::apply("ulong"); test_promotion::apply("ulong"); } BOOST_AUTO_TEST_CASE( test_std_size_t ) { test_promotion::apply("size_t"); test_promotion::apply("size_t"); } #ifdef BOOST_HAS_LONG_LONG BOOST_AUTO_TEST_CASE( test_long_long ) { test_promotion::apply("long long"); test_promotion::apply("long long"); } #endif #if defined(BOOST_HAS_INT128) BOOST_AUTO_TEST_CASE( test_int128 ) { test_promotion::apply("int128_t"); test_promotion::apply("int128_t"); } #endif BOOST_AUTO_TEST_CASE( test_user_types ) { namespace bm = boost::multiprecision; typedef bm::number < bm::cpp_int_backend < 17, 17, bm::signed_magnitude, bm::unchecked, void > > user_signed_type1; typedef bm::number < bm::cpp_int_backend < 17, 17, bm::unsigned_magnitude, bm::unchecked, void > > user_unsigned_type1; typedef bm::number < bm::cpp_int_backend < 500, 500, bm::signed_magnitude, bm::unchecked, void > > user_signed_type2; typedef bm::number < bm::cpp_int_backend < 500, 500, bm::unsigned_magnitude, bm::unchecked, void > > user_unsigned_type2; // for user defined number types we do not do any promotion typedef test_promote_integral tester1; typedef test_promote_integral tester2; tester1::apply("u1s"); tester1::apply("u2s"); tester1::apply("u1u"); tester1::apply("u2u"); tester2::apply("u1s"); tester2::apply("u2s"); tester2::apply("u1u"); tester2::apply("u1u"); } BOOST_AUTO_TEST_CASE( test_floating_point ) { typedef test_promote_integral tester1; typedef test_promote_integral tester2; // for floating-point types we do not do any promotion tester1::apply("fp-f"); tester1::apply("fp-d"); tester1::apply("fp-ld"); tester2::apply("fp-f"); tester2::apply("fp-d"); tester2::apply("fp-ld"); #ifdef HAVE_TTMATH tester1::apply("fp-tt"); tester2::apply("fp-tt"); #endif }