[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 83abe82 1/5: Replace numeric_value_cast()
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 83abe82 1/5: Replace numeric_value_cast() |
Date: |
Sun, 23 Apr 2017 15:37:31 -0400 (EDT) |
branch: master
commit 83abe8294dcf84799ed79203006484cfbb3f8c4e
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Replace numeric_value_cast()
Expunged function template numeric_value_cast() was a cover function
for boost::numeric_cast() that made the latter fulfill its contract to
throw if it could not preserve value. Apparently that contract was a
documentation error, and boost's actual intention was always to permit
truncation when converting floating-point values to integers. The new
bourn_cast, now used in place of numeric_value_cast(), enforces the
no-truncation contract.
Incidentally, included only appropriate headers, and improved
documentation. Most notably, removed a suggestion that an exception
such as bad_cast be used instead of std::runtime_error: that would
decrease uniformity without offering any benefit, because lmi would
not handle such an exception differently than any other.
---
calendar_date.cpp | 6 +++---
value_cast.hpp | 46 +++++-----------------------------------------
value_cast_test.cpp | 39 +++++++++++++++++++++++++--------------
3 files changed, 33 insertions(+), 58 deletions(-)
diff --git a/calendar_date.cpp b/calendar_date.cpp
index 2b95304..91a1450 100644
--- a/calendar_date.cpp
+++ b/calendar_date.cpp
@@ -25,7 +25,7 @@
#include "alert.hpp"
#include "assert_lmi.hpp"
-#include "value_cast.hpp"
+#include "bourn_cast.hpp"
#include "zero.hpp"
#include <algorithm> // std::max(), std::min()
@@ -691,7 +691,7 @@ class birthdate_limit
double operator()(double candidate)
{
// Double parentheses circumvent the most vexing parse.
- calendar_date z((jdn_t(numeric_value_cast<int>(candidate))));
+ calendar_date z((jdn_t(bourn_cast<int>(candidate))));
return offset_ + notional_age(z, as_of_date_, alb_anb_) - limit_age_;
}
@@ -705,7 +705,7 @@ class birthdate_limit
,*this
);
LMI_ASSERT(root_not_bracketed != z.second);
- int j = numeric_value_cast<int>(z.first);
+ int j = bourn_cast<int>(z.first);
j = std::min(j, as_of_date_.julian_day_number());
j = std::max(j, a_priori_minimum_);
j = std::min(j, a_priori_maximum_);
diff --git a/value_cast.hpp b/value_cast.hpp
index 210fb57..5c30e13 100644
--- a/value_cast.hpp
+++ b/value_cast.hpp
@@ -24,13 +24,12 @@
#include "config.hpp"
+#include "bourn_cast.hpp"
#include "numeric_io_cast.hpp"
#include "stream_cast.hpp"
-#include <boost/cast.hpp>
-
-#include <sstream>
#include <stdexcept>
+#include <string>
#include <type_traits>
// INELEGANT !! Test the runtime performance of value_cast() compared
@@ -45,13 +44,10 @@
// template function value_cast for string-like types, as was done
// for template class datum_string.
-// INELEGANT !! Exceptions thrown from numeric_io_cast and stream_cast
-// ought perhaps to be derived from std::bad_cast.
-
/// Function template value_cast() converts between types, choosing a
/// conversion method in the following order of decreasing preference:
-/// numeric_value_cast for number <--> number
-/// direct conversion for intraconvertible types not both numeric
+/// bourn_cast for number <--> number
+/// direct conversion for interconvertible types not both numeric
/// numeric_io_cast for number <--> string
/// stream_cast for all other cases
///
@@ -142,38 +138,6 @@ void throw_if_null_pointer(T* t)
}
}
-/// Function template numeric_value_cast() wraps boost::numeric_cast
-/// to make it DWISOTT according to the boost-1.31.0 documentation:
-/// "An exception is thrown when a runtime value-preservation
-/// check fails."
-/// The problem is that
-/// boost::numeric_cast<int>(2.71828);
-/// returns the integer 2 without throwing, but 2.71828 and 2 are
-/// different values. It seems unreasonable to call truncation a
-/// value-preserving relation.
-
-template<typename To, typename From>
-To numeric_value_cast(From const& from)
-{
- To result = boost::numeric_cast<To>(from);
- if(result == from)
- {
- return result;
- }
- else
- {
- std::ostringstream oss;
- oss
- << "Value not preserved converting "
- << numeric_io_cast<std::string>(from)
- << " to "
- << numeric_io_cast<std::string>(result)
- << " ."
- ;
- throw std::runtime_error(oss.str());
- }
-}
-
/// Class template value_cast_choice is an appurtenance of function
/// template value_cast(); it selects the best conversion method.
///
@@ -238,7 +202,7 @@ template<typename To, typename From>
struct value_cast_chooser<To,From,e_both_numeric>
{
static cast_method method() {return e_both_numeric;}
- To operator()(From const& from) {return numeric_value_cast<To>(from);}
+ To operator()(From const& from) {return bourn_cast<To>(from);}
};
template<typename To, typename From>
diff --git a/value_cast_test.cpp b/value_cast_test.cpp
index fbb5979..2d1619b 100644
--- a/value_cast_test.cpp
+++ b/value_cast_test.cpp
@@ -141,22 +141,17 @@ int test_main(int, char*[])
// A good compiler should warn about this conversion.
// value_cast<unsigned int>(-1);
- // The boost-1.31.0 documentation says:
- // "An exception is thrown when a runtime value-preservation
- // check fails."
- // yet this does not throw, even in boost-1.33.1, whose new
- // numeric_cast delegates to boost::numeric::converter:
- i = boost::numeric_cast<int>(2.71828);
- // but these do:
+ // Forbidden truncation.
+
BOOST_TEST_THROW
(i = value_cast<int>(d)
,std::runtime_error
- ,"Value not preserved converting 2.71828 to 2 ."
+ ,lmi_test::what_regex("^Cast.*would not preserve value\\.$")
);
BOOST_TEST_THROW
- (numeric_value_cast<int>(2.71828)
+ (bourn_cast<int>(2.71828)
,std::runtime_error
- ,"Value not preserved converting 2.71828 to 2 ."
+ ,lmi_test::what_regex("^Cast.*would not preserve value\\.$")
);
// This conversion should work: value is exactly preserved.
@@ -724,9 +719,17 @@ int boost_tests()
BOOST_TEST_EQUAL(1,value_cast<int>(1.0));
- BOOST_TEST_THROW(value_cast<int>(1.23), std::runtime_error, "");
+ BOOST_TEST_THROW
+ (value_cast<int>(1.23)
+ ,std::runtime_error
+ ,lmi_test::what_regex("^Cast.*would not preserve value\\.$")
+ );
- BOOST_TEST_THROW(value_cast<int>(1e20), boost::numeric::positive_overflow,
"");
+ BOOST_TEST_THROW
+ (value_cast<int>(1e20)
+ ,std::runtime_error
+ ,"Cast would transgress upper limit."
+ );
BOOST_TEST_EQUAL(1, value_cast<int>(true));
BOOST_TEST_EQUAL(0, value_cast<int>(false));
BOOST_TEST_EQUAL(123, value_cast<int>("123"));
@@ -792,10 +795,18 @@ int boost_tests()
BOOST_TEST_EQUAL(true, value_cast<bool>('\1'));
BOOST_TEST_EQUAL(false, value_cast<bool>('\0'));
- BOOST_TEST_THROW(value_cast<bool>('A'), boost::numeric::positive_overflow,
"");
+ BOOST_TEST_THROW
+ (value_cast<bool>('A')
+ ,std::runtime_error
+ ,"Cast would transgress upper limit."
+ );
BOOST_TEST_EQUAL(true, value_cast<bool>(1));
BOOST_TEST_EQUAL(false, value_cast<bool>(0));
- BOOST_TEST_THROW(value_cast<bool>(123), boost::numeric::positive_overflow,
"");
+ BOOST_TEST_THROW
+ (value_cast<bool>(123)
+ ,std::runtime_error
+ ,"Cast would transgress upper limit."
+ );
BOOST_TEST_EQUAL(true, value_cast<bool>(1.0));
BOOST_TEST_EQUAL(false, value_cast<bool>(0.0));
BOOST_TEST_EQUAL(true, value_cast<bool>(true));