You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2014/02/21 01:26:08 UTC

git commit: Add JSON::Boolean to stout/json.hpp.

Repository: mesos
Updated Branches:
  refs/heads/master e0ac5af92 -> dee9bd96e


Add JSON::Boolean to stout/json.hpp.

If you assign an JSON::Object a bool then it will get coerced into a
JSON::Number w/ value of 0.0 or 1.0.  This is because JSON::True and
JSON::False do not have constructors from bool.

The fix is to introduce a common super class, JSON::Boolean, which
both JSON::True and JSON::False inherit from.  JSON::Boolean has the
necessary constructor which takes a bool.

However, this leads to ambiguity when assigning a cstring to
a JSON::Value, since JSON::String already takes a const char * and
a const char * is implicitly convertable to a bool.

The solution for that is to rename the variant from JSON::Value
to JSON::inner::Variant and to create a new class JSON::Value
which inherits from JSON::inner::Variant.  The new JSON::Value
can have all the conversion constructors in a single place, so
is no ambiguity, and delegate everythign else to the Variant.

Also added a bunch of unit tests.

SEE: https://issues.apache.org/jira/browse/MESOS-939

Review: https://reviews.apache.org/r/17520


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/dee9bd96
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/dee9bd96
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/dee9bd96

Branch: refs/heads/master
Commit: dee9bd96e88053ab96c84253578ed332d343fe41
Parents: e0ac5af
Author: Charlie Carson <ch...@gmail.com>
Authored: Thu Feb 20 16:24:09 2014 -0800
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Thu Feb 20 16:24:09 2014 -0800

----------------------------------------------------------------------
 .../3rdparty/stout/include/stout/json.hpp       |  92 ++++++++++++----
 .../3rdparty/stout/tests/json_tests.cpp         | 104 +++++++++++++++++++
 2 files changed, 177 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/dee9bd96/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
index 8b64e89..778398a 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
@@ -21,6 +21,8 @@
 #include <map>
 #include <string>
 
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/utility/enable_if.hpp>
 #include <boost/variant.hpp>
 
 #include <stout/foreach.hpp>
@@ -43,23 +45,17 @@ namespace JSON {
 // (although, this does pay a 2x cost when compiling thanks to all the
 // extra template instantiations).
 
+// Note that all of these forward declarations are not necessary
+// but it serves to document the set of types which are available.
 struct String;
 struct Number;
 struct Object;
 struct Array;
 struct True;
 struct False;
+struct Boolean;
 struct Null;
-
-
-// Null needs to be first so that it is the default value.
-typedef boost::variant<boost::recursive_wrapper<Null>,
-                       boost::recursive_wrapper<String>,
-                       boost::recursive_wrapper<Number>,
-                       boost::recursive_wrapper<Object>,
-                       boost::recursive_wrapper<Array>,
-                       boost::recursive_wrapper<True>,
-                       boost::recursive_wrapper<False> > Value;
+struct Value;
 
 
 struct String
@@ -91,15 +87,78 @@ struct Array
 };
 
 
-struct True {};
+struct Boolean
+{
+  Boolean() : value(false) {}
+  Boolean(bool _value) : value(_value) {}
+  bool value;
+};
+
+
+// This is a helper so you can say JSON::True() instead of
+// JSON::Boolean(true).
+struct True : Boolean
+{
+  True() : Boolean(true) {};
+};
 
 
-struct False {};
+// This is a helper so you can say JSON::False() instead of
+// JSON::Boolean(false).
+struct False : Boolean
+{
+  False() : Boolean(false) {}
+};
 
 
 struct Null {};
 
 
+namespace internal {
+
+
+// Only Object and Array require recursive_wrapper, not sure
+// if there is a reason to wrap the others or not.
+// Null needs to be first so that it is the default value.
+typedef boost::variant<boost::recursive_wrapper<Null>,
+                       boost::recursive_wrapper<String>,
+                       boost::recursive_wrapper<Number>,
+                       boost::recursive_wrapper<Object>,
+                       boost::recursive_wrapper<Array>,
+                       boost::recursive_wrapper<Boolean> > Variant;
+
+} // namespace internal {
+
+
+struct Value : internal::Variant
+{
+  // Empty constructur gets the variant default.
+  Value() {}
+
+  // bool creates a JSON::Boolean explicitly.
+  Value(bool value) : internal::Variant(JSON::Boolean(value)) {}
+
+  // CStrings create a JSON::String explicitly.
+  Value(char* value) : internal::Variant(JSON::String(value)) {}
+  Value(const char* value) : internal::Variant(JSON::String(value)) {}
+
+  // Arithmetic types are specifically routed through Number because
+  // there would be ambiguity between JSON::Bool and JSON::Number otherwise.
+  template <typename T>
+  Value(
+      const T& value,
+      typename boost::enable_if<boost::is_arithmetic<T>, int>::type = 0)
+      : internal::Variant(Number(value)) {}
+
+  // Non-arithmetic types are passed to the default constructor of Variant.
+  template <typename T>
+  Value(
+      const T& value,
+      typename boost::disable_if<boost::is_arithmetic<T>, int>::type = 0)
+      : internal::Variant(value) {}
+};
+
+
 // Implementation of rendering JSON objects built above using standard
 // C++ output streams. The visitor pattern is used thanks to to build
 // a "renderer" with boost::static_visitor and two top-level render
@@ -182,14 +241,9 @@ struct Renderer : boost::static_visitor<>
     out << "]";
   }
 
-  void operator () (const True&) const
-  {
-    out << "true";
-  }
-
-  void operator () (const False&) const
+  void operator() (const Boolean& boolean) const
   {
-    out << "false";
+    out << (boolean.value ? "true" : "false");
   }
 
   void operator () (const Null&) const

http://git-wip-us.apache.org/repos/asf/mesos/blob/dee9bd96/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
index aafaaa6..267b5f9 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
@@ -2,6 +2,8 @@
 
 #include <gmock/gmock.h>
 
+#include <sys/stat.h>
+
 #include <string>
 
 #include <stout/json.hpp>
@@ -9,6 +11,8 @@
 
 using std::string;
 
+using boost::get;
+
 
 TEST(JsonTest, DefaultValueIsNull)
 {
@@ -38,3 +42,103 @@ TEST(JsonTest, NumberFormat)
   // Expect at least 15 digits of precision.
   EXPECT_EQ("1234567890.12345", stringify(JSON::Number(1234567890.12345)));
 }
+
+
+TEST(JsonTest, BooleanFormat)
+{
+  EXPECT_EQ("false", stringify(JSON::False()));
+  EXPECT_EQ("true", stringify(JSON::True()));
+
+  EXPECT_EQ("true", stringify(JSON::Boolean(true)));
+  EXPECT_EQ("false", stringify(JSON::Boolean(false)));
+
+  EXPECT_EQ("true", stringify(JSON::Value(true)));
+  EXPECT_EQ("false", stringify(JSON::Value(false)));
+}
+
+
+TEST(JsonTest, BooleanAssignement)
+{
+  JSON::Value v = true;
+  EXPECT_TRUE(get<JSON::Boolean>(v).value);
+
+  v = false;
+  EXPECT_FALSE(get<JSON::Boolean>(v).value);
+
+  JSON::Boolean b = true;
+  EXPECT_TRUE(b.value);
+
+  b = false;
+  EXPECT_FALSE(b.value);
+}
+
+
+TEST(JsonTest, CStringAssignment)
+{
+  JSON::Value v = "test";
+  JSON::String s = "test";
+  EXPECT_EQ(get<JSON::String>(v).value, "test");
+  EXPECT_EQ(s.value, "test");
+
+  v = "123";
+  s = "123";
+  EXPECT_EQ(get<JSON::String>(v).value, "123");
+  EXPECT_EQ(s.value, "123");
+
+  char buf[1000];
+
+  v = strcpy(buf, "bar");
+  s = strcpy(buf, "bar");
+  EXPECT_EQ(get<JSON::String>(v).value, "bar");
+  EXPECT_EQ(s.value, "bar");
+}
+
+
+TEST(JsonTest, NumericAssignment)
+{
+  // Just using this to get various numeric datatypes that
+  // are used by clients of stout.
+  struct stat s;
+
+  s.st_nlink = 1;
+  JSON::Value v = s.st_nlink;
+  JSON::Number d = s.st_nlink;
+  EXPECT_EQ(get<JSON::Number>(v).value, 1.0);
+  EXPECT_EQ(d.value, 1.0);
+
+  s.st_size = 2;
+  v = s.st_size;
+  d = s.st_size;
+  EXPECT_EQ(get<JSON::Number>(v).value, 2.0);
+  EXPECT_EQ(d.value, 2.0);
+
+  s.st_mtime = 3;
+  v = s.st_mtime;
+  d = s.st_mtime;
+  EXPECT_EQ(get<JSON::Number>(v).value, 3.0);
+  EXPECT_EQ(d.value, 3.0);
+
+  size_t st = 4;
+  v = st;
+  d = st;
+  EXPECT_EQ(get<JSON::Number>(v).value, 4.0);
+  EXPECT_EQ(d.value, 4.0);
+
+  uint64_t ui64 = 5;
+  v = ui64;
+  d = ui64;
+  EXPECT_EQ(get<JSON::Number>(v).value, 5.0);
+  EXPECT_EQ(d.value, 5.0);
+
+  const unsigned int ui = 6;
+  v = ui;
+  d = ui;
+  EXPECT_EQ(get<JSON::Number>(v).value, 6.0);
+  EXPECT_EQ(d.value, 6.0);
+
+  int i = 7;
+  v = i;
+  d = i;
+  EXPECT_EQ(get<JSON::Number>(v).value, 7.0);
+  EXPECT_EQ(d.value, 7.0);
+}