// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) #include #endif #if defined(BOOST_GEOMETRY_TEST_DEBUG) #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) void print_uint128_t(std::ostream& os, boost::uint128_type i) { if (i == 0) { os << "0"; return; } 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; } std::ostream& operator<<(std::ostream& os, boost::int128_type i) { if (i < 0) { os << "-"; print_uint128_t(os, static_cast(-i)); } else { print_uint128_t(os, static_cast(i)); } return os; } std::ostream& operator<<(std::ostream& os, boost::uint128_type i) { print_uint128_t(os, i); return os; } #endif // BOOST_HAS_INT128 && BOOST_GEOMETRY_ENABLE_INT128 #endif // BOOST_GEOMETRY_TEST_DEBUG 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 min_value = (std::numeric_limits::min)(); min_value *= min_value; BOOST_CHECK(absolute_value::apply(min_value) == min_value); Promoted max_value = (std::numeric_limits::max)(); max_value *= max_value; BOOST_CHECK(absolute_value::apply(max_value) == max_value); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "integral min_value^2: " << min_value << std::endl; std::cout << "promoted max_value: " << (std::numeric_limits::max)() << std::endl; #endif } }; 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); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "integral max_value^2: " << max_value_sqr << std::endl; std::cout << "promoted max_value: " << (std::numeric_limits::max)() << std::endl; #endif } }; // helper function that returns the bit size of a type template < typename T, bool IsFundamental = boost::is_fundamental::type::value > struct bit_size_impl : boost::mpl::size_t<0> {}; template struct bit_size_impl : bg::detail::promote_integral::bit_size::type {}; #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) template < typename Backend, boost::multiprecision::expression_template_option ExpressionTemplates > struct bit_size_impl < boost::multiprecision::number, false > : bg::detail::promote_integral::bit_size < boost::multiprecision::number > {}; #endif template std::size_t bit_size() { return bit_size_impl::type::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 (bits): " << bit_size() << ", min value: " << (std::numeric_limits::min)() << ", max value: " << (std::numeric_limits::max)() << std::endl; std::cout << "detected promoted type : " << typeid(promoted_integral_type).name() << ", sizeof (bits): " << bit_size() << ", min value: " << (std::numeric_limits::min)() << ", max value: " << (std::numeric_limits::max)() << std::endl; std::cout << "expected promoted type : " << typeid(ExpectedPromotedType).name() << ", sizeof (bits): " << bit_size() << ", min value: " << (std::numeric_limits::min)() << ", 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 * bit_size() - 1; if (BOOST_GEOMETRY_CONDITION(! IsSigned)) { min_size += 2; } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "min size: " << min_size << std::endl; #endif if (bit_size() >= min_size) { tester::template apply(case_id); } else if (bit_size() >= min_size) { tester::template apply(case_id); } else if (bit_size() >= min_size) { tester::template apply(case_id); } #if defined(BOOST_HAS_LONG_LONG) else if (bit_size() >= min_size) { tester::template apply(case_id); } #endif #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) else if (bit_size() >= 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 min_size = 2 * bit_size(); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "min size: " << min_size << std::endl; #endif if (bit_size() >= min_size) { tester::apply(case_id); } else if (bit_size() >= min_size) { tester::apply(case_id); } else if (bit_size() >= min_size) { tester::apply(case_id); } else if (bit_size() >= min_size) { tester::apply(case_id); } #if defined(BOOST_HAS_LONG_LONG) else if (bit_size() >= min_size) { tester::template apply(case_id); } #endif #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) else if (bit_size() >= 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), 2 * CHAR_BIT * sizeof(T), 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"); test_promotion::apply("ulong long"); test_promotion::apply("ulong long"); } #endif #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) BOOST_AUTO_TEST_CASE( test_int128 ) { test_promotion::apply("int128_t"); test_promotion::apply("int128_t"); test_promotion::apply("uint128_t"); test_promotion::apply("uint128_t"); } #endif #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) 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"); } #endif 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 }