make to<bool> skip range check
authorMarc Horowitz <mhorowitz@fb.com>
Mon, 21 Sep 2015 16:42:44 +0000 (09:42 -0700)
committerfacebook-github-bot-9 <folly-bot@fb.com>
Mon, 21 Sep 2015 17:20:20 +0000 (10:20 -0700)
Summary: to<bool>(42) should return true, not throw an exception.

Reviewed By: @yfeldblum

Differential Revision: D2459766

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

index 113a14954ae27ad56d60f3de46ecbf41f4016268..7ccedcff09fe7831a0a46d613a8607ceef88cefa 100644 (file)
@@ -86,6 +86,21 @@ to(Src && value) {
  * Integral to integral
  ******************************************************************************/
 
+/**
+ * Unchecked conversion from integral to boolean. This is different from the
+ * other integral conversions because we use the C convention of treating any
+ * non-zero value as true, instead of range checking.
+ */
+template <class Tgt, class Src>
+typename std::enable_if<
+  std::is_integral<Src>::value
+  && !std::is_same<Tgt, Src>::value
+  && std::is_same<Tgt, bool>::value,
+  Tgt>::type
+to(const Src & value) {
+  return value != 0;
+}
+
 /**
  * Checked conversion from integral to integral. The checks are only
  * performed when meaningful, e.g. conversion from int to long goes
@@ -94,8 +109,9 @@ to(Src && value) {
 template <class Tgt, class Src>
 typename std::enable_if<
   std::is_integral<Src>::value
-  && std::is_integral<Tgt>::value
-  && !std::is_same<Tgt, Src>::value,
+  && !std::is_same<Tgt, Src>::value
+  && !std::is_same<Tgt, bool>::value
+  && std::is_integral<Tgt>::value,
   Tgt>::type
 to(const Src & value) {
   /* static */ if (std::numeric_limits<Tgt>::max()
index 189c96bd0b5811199205fc747f086fddb86cc223..625a651dee17b15e4466ebfb8b5a0f9ad2a087f8 100644 (file)
@@ -90,6 +90,9 @@ TEST(Conv, digits10) {
 
 // Test to<T>(T)
 TEST(Conv, Type2Type) {
+  bool boolV = true;
+  EXPECT_EQ(to<bool>(boolV), true);
+
   int intV = 42;
   EXPECT_EQ(to<int>(intV), 42);
 
@@ -109,6 +112,7 @@ TEST(Conv, Type2Type) {
   EXPECT_EQ(to<folly::StringPiece>(spV), "StringPiece");
 
   // Rvalues
+  EXPECT_EQ(to<bool>(true), true);
   EXPECT_EQ(to<int>(42), 42);
   EXPECT_EQ(to<float>(4.2f), 4.2f);
   EXPECT_EQ(to<double>(.42), .42);
@@ -725,6 +729,17 @@ TEST(Conv, EnumClassToString) {
   EXPECT_EQ("foo.65", to<string>("foo.", A::z));
 }
 
+TEST(Conv, IntegralToBool) {
+  EXPECT_FALSE(to<bool>(0));
+  EXPECT_FALSE(to<bool>(0ul));
+
+  EXPECT_TRUE(to<bool>(1));
+  EXPECT_TRUE(to<bool>(1ul));
+
+  EXPECT_TRUE(to<bool>(-42));
+  EXPECT_TRUE(to<bool>(42ul));
+}
+
 template<typename Src>
 void testStr2Bool() {
   EXPECT_FALSE(to<bool>(Src("0")));
index c54b0b54108431fa39b56a59fb0f09efdd89c9cc..8b5964f6ab5cd9903a0b4a7da6f168eb72c1f4fb 100644 (file)
@@ -150,6 +150,10 @@ TEST(Json, ParseTrailingComma) {
   EXPECT_THROW(parseJson("{\"a\":1,}", off), std::runtime_error);
 }
 
+TEST(Json, BoolConversion) {
+  EXPECT_TRUE(parseJson("42").asBool());
+}
+
 TEST(Json, JavascriptSafe) {
   auto badDouble = (1ll << 63ll) + 1;
   dynamic badDyn = badDouble;