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);
+}