Fix conversion from bool to floating point value
authorMarcus Holland-Moritz <mhx@fb.com>
Fri, 24 Jun 2016 00:22:33 +0000 (17:22 -0700)
committerFacebook Github Bot 7 <facebook-github-bot-7-bot@fb.com>
Fri, 24 Jun 2016 00:23:30 +0000 (17:23 -0700)
Summary:
Due to the definition of how floating point values convert to boolean,
the check for undefined behaviour wouldn't work correctly. The result
of (1 - 0.9999999999999999) would yield 0 when converted to an integer,
but yields true (1) when converted to a boolean.

As all floating point values can thus be converted to boolean without
triggering undefined behaviour, this change overloads checkConversion()
appropriately

Reviewed By: yfeldblum

Differential Revision: D3477368

fbshipit-source-id: 5b2aeb6194629cf3a6195529aac2362c0d35799c

folly/Conv.h
folly/test/ConvTest.cpp

index c0a350fe7c99bd2faf6c05b4067541a979423893..53be6b8211382dd6c93a089315f0ea6b14506c0c 100644 (file)
@@ -1163,10 +1163,11 @@ namespace detail {
  * integer value without triggering undefined behaviour.
  */
 template <typename Tgt, typename Src>
-typename std::enable_if<
-    std::is_floating_point<Src>::value && std::is_integral<Tgt>::value,
+inline typename std::enable_if<
+    std::is_floating_point<Src>::value && std::is_integral<Tgt>::value &&
+        !std::is_same<Tgt, bool>::value,
     bool>::type
-inline checkConversion(const Src& value) {
+checkConversion(const Src& value) {
   constexpr Src tgtMaxAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::max());
   constexpr Src tgtMinAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::min());
   if (value >= tgtMaxAsSrc) {
@@ -1193,13 +1194,22 @@ inline checkConversion(const Src& value) {
 
 // Integers can always safely be converted to floating point values
 template <typename Tgt, typename Src>
-typename std::enable_if<
+constexpr typename std::enable_if<
     std::is_integral<Src>::value && std::is_floating_point<Tgt>::value,
     bool>::type
 checkConversion(const Src&) {
   return true;
 }
 
+// Also, floating point values can always be safely converted to bool
+// Per the standard, any floating point value that is not zero will yield true
+template <typename Tgt, typename Src>
+constexpr typename std::enable_if<
+    std::is_floating_point<Src>::value && std::is_same<Tgt, bool>::value,
+    bool>::type
+checkConversion(const Src&) {
+  return true;
+}
 }
 
 /**
index a14eeb2801ef510f3ef4527f825347128e59f698..cbf7510ad87edbb1021f53a44ab3b40b1ea50cee 100644 (file)
@@ -823,6 +823,16 @@ TEST(Conv, IntToFloat) {
 #endif
 }
 
+TEST(Conv, BoolToFloat) {
+  EXPECT_EQ(to<double>(true), 1.0);
+  EXPECT_EQ(to<double>(false), 0.0);
+}
+
+TEST(Conv, FloatToBool) {
+  EXPECT_EQ(to<bool>(1.0), true);
+  EXPECT_EQ(to<bool>(0.0), false);
+}
+
 TEST(Conv, NewUint64ToString) {
   char buf[21];