Added Visitable to reduce the number of definitions of operator<<

This commit is contained in:
Benoit Blanchon
2018-10-12 17:59:50 +02:00
parent b0560cbd99
commit 02d809f3f4
13 changed files with 118 additions and 102 deletions

View File

@ -6,7 +6,8 @@
#include "../Serialization/measure.hpp" #include "../Serialization/measure.hpp"
#include "../Serialization/serialize.hpp" #include "../Serialization/serialize.hpp"
#include "./JsonWriter.hpp" #include "../Visitable.hpp"
#include "JsonWriter.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -103,32 +104,9 @@ size_t measureJson(const TSource &source) {
} }
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream &operator<<(std::ostream &os, const JsonArray &source) { template <typename T>
serializeJson(source, os); inline typename enable_if<IsVisitable<T>::value, std::ostream &>::type
return os; operator<<(std::ostream &os, const T &source) {
}
inline std::ostream &operator<<(std::ostream &os, const JsonObject &source) {
serializeJson(source, os);
return os;
}
inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
serializeJson(source, os);
return os;
}
inline std::ostream &operator<<(std::ostream &os, JsonVariantConst source) {
os << serializeJson(source, os);
return os;
}
inline std::ostream &operator<<(std::ostream &os,
const JsonArraySubscript &source) {
serializeJson(source, os);
return os;
}
template <typename TKey>
inline std::ostream &operator<<(std::ostream &os,
const JsonObjectSubscript<TKey> &source) {
serializeJson(source, os); serializeJson(source, os);
return os; return os;
} }

View File

@ -38,13 +38,22 @@ class JsonArrayProxy {
TData* _data; TData* _data;
}; };
class JsonArrayConst : public JsonArrayProxy<const JsonArrayData> { class JsonArrayConst : public JsonArrayProxy<const JsonArrayData>,
public Visitable {
friend class JsonArray; friend class JsonArray;
typedef JsonArrayProxy<const JsonArrayData> proxy_type; typedef JsonArrayProxy<const JsonArrayData> proxy_type;
public: public:
typedef JsonArrayConstIterator iterator; typedef JsonArrayConstIterator iterator;
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
if (_data)
visitor.visitArray(*this);
else
visitor.visitNull();
}
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_data->head); return iterator(_data->head);
@ -62,7 +71,7 @@ class JsonArrayConst : public JsonArrayProxy<const JsonArrayData> {
} }
}; };
class JsonArray : public JsonArrayProxy<JsonArrayData> { class JsonArray : public JsonArrayProxy<JsonArrayData>, public Visitable {
typedef JsonArrayProxy<JsonArrayData> proxy_type; typedef JsonArrayProxy<JsonArrayData> proxy_type;
public: public:
@ -224,10 +233,7 @@ class JsonArray : public JsonArrayProxy<JsonArrayData> {
template <typename Visitor> template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const { FORCE_INLINE void accept(Visitor& visitor) const {
if (_data) JsonArrayConst(_data).accept(visitor);
visitor.visitArray(*this);
else
visitor.visitNull();
} }
private: private:

View File

@ -13,7 +13,8 @@
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript>,
public Visitable {
public: public:
FORCE_INLINE JsonArraySubscript(JsonArray array, size_t index) FORCE_INLINE JsonArraySubscript(JsonArray array, size_t index)
: _array(array), _index(index) {} : _array(array), _index(index) {}

View File

@ -12,7 +12,7 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TMemoryPool> template <typename TMemoryPool>
class JsonDocument { class JsonDocument : public Visitable {
public: public:
uint8_t nestingLimit; uint8_t nestingLimit;

View File

@ -33,6 +33,10 @@ class JsonObjectProxy {
return objectContainsKey(_data, makeString(key)); return objectContainsKey(_data, makeString(key));
} }
FORCE_INLINE bool isNull() const {
return _data == 0;
}
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return objectSize(_data); return objectSize(_data);
} }
@ -42,7 +46,8 @@ class JsonObjectProxy {
TData* _data; TData* _data;
}; };
class JsonObjectConst : public JsonObjectProxy<const JsonObjectData> { class JsonObjectConst : public JsonObjectProxy<const JsonObjectData>,
public Visitable {
friend class JsonObject; friend class JsonObject;
typedef JsonObjectProxy<const JsonObjectData> proxy_type; typedef JsonObjectProxy<const JsonObjectData> proxy_type;
@ -52,6 +57,14 @@ class JsonObjectConst : public JsonObjectProxy<const JsonObjectData> {
JsonObjectConst() : proxy_type(0) {} JsonObjectConst() : proxy_type(0) {}
JsonObjectConst(const JsonObjectData* data) : proxy_type(data) {} JsonObjectConst(const JsonObjectData* data) : proxy_type(data) {}
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
if (_data)
visitor.visitObject(*this);
else
visitor.visitNull();
}
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_data->head); return iterator(_data->head);
@ -110,7 +123,7 @@ class JsonObjectConst : public JsonObjectProxy<const JsonObjectData> {
} }
}; };
class JsonObject : public JsonObjectProxy<JsonObjectData> { class JsonObject : public JsonObjectProxy<JsonObjectData>, public Visitable {
typedef JsonObjectProxy<JsonObjectData> proxy_type; typedef JsonObjectProxy<JsonObjectData> proxy_type;
public: public:
@ -304,16 +317,9 @@ class JsonObject : public JsonObjectProxy<JsonObjectData> {
return set_impl(key); return set_impl(key);
} }
FORCE_INLINE bool isNull() const {
return _data == 0;
}
template <typename Visitor> template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const { FORCE_INLINE void accept(Visitor& visitor) const {
if (_data) JsonObjectConst(_data).accept(visitor);
visitor.visitObject(JsonObjectConst(_data));
else
visitor.visitNull();
} }
private: private:

View File

@ -17,7 +17,8 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TStringRef> template <typename TStringRef>
class JsonObjectSubscript class JsonObjectSubscript
: public JsonVariantBase<JsonObjectSubscript<TStringRef> > { : public JsonVariantBase<JsonObjectSubscript<TStringRef> >,
public Visitable {
typedef JsonObjectSubscript<TStringRef> this_type; typedef JsonObjectSubscript<TStringRef> this_type;
public: public:

View File

@ -16,6 +16,7 @@
#include "Numbers/parseFloat.hpp" #include "Numbers/parseFloat.hpp"
#include "Numbers/parseInteger.hpp" #include "Numbers/parseInteger.hpp"
#include "Polyfills/type_traits.hpp" #include "Polyfills/type_traits.hpp"
#include "Visitable.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -117,7 +118,8 @@ class JsonVariantProxy {
// - a string (const char*) // - a string (const char*)
// - a reference to a JsonArray or JsonObject // - a reference to a JsonArray or JsonObject
class JsonVariant : public JsonVariantProxy<JsonVariantData>, class JsonVariant : public JsonVariantProxy<JsonVariantData>,
public JsonVariantBase<JsonVariant> { public JsonVariantBase<JsonVariant>,
public Visitable {
typedef JsonVariantProxy<JsonVariantData> proxy_type; typedef JsonVariantProxy<JsonVariantData> proxy_type;
friend class JsonVariantConst; friend class JsonVariantConst;
@ -279,7 +281,8 @@ class JsonVariant : public JsonVariantProxy<JsonVariantData>,
}; };
class JsonVariantConst : public JsonVariantProxy<const JsonVariantData>, class JsonVariantConst : public JsonVariantProxy<const JsonVariantData>,
public JsonVariantBase<JsonVariantConst> { public JsonVariantBase<JsonVariantConst>,
public Visitable {
typedef JsonVariantProxy<const JsonVariantData> proxy_type; typedef JsonVariantProxy<const JsonVariantData> proxy_type;
public: public:
@ -318,15 +321,4 @@ class JsonVariantConst : public JsonVariantProxy<const JsonVariantData>,
return JsonVariantConst(objectGet(variantAsObject(_data), makeString(key))); return JsonVariantConst(objectGet(variantAsObject(_data), makeString(key)));
} }
}; };
class JsonVariantLocal : public JsonVariant {
public:
explicit JsonVariantLocal(MemoryPool *memoryPool)
: JsonVariant(memoryPool, &_localData) {
_localData.type = JSON_NULL;
}
private:
JsonVariantData _localData;
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -278,7 +278,8 @@ class MsgPackDeserializer {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit; --_nestingLimit;
for (; n; --n) { for (; n; --n) {
JsonVariantLocal key(_memoryPool); JsonVariantData keyData;
JsonVariant key(_memoryPool, &keyData);
DeserializationError err = parse(key); DeserializationError err = parse(key);
if (err) return err; if (err) return err;
if (!key.is<char *>()) return DeserializationError::NotSupported; if (!key.is<char *>()) return DeserializationError::NotSupported;

View File

@ -18,8 +18,7 @@ class is_base_of {
static No &probe(...); static No &probe(...);
public: public:
enum { static const bool value =
value = sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes) sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes);
};
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,18 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Polyfills/type_traits.hpp"
namespace ARDUINOJSON_NAMESPACE {
struct Visitable {
// template<Visitor>
// void accept(Visitor&) const;
};
template <typename T>
struct IsVisitable : is_base_of<Visitable, T> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -6,39 +6,29 @@
#include <catch.hpp> #include <catch.hpp>
TEST_CASE("JsonArray::isNull()") { TEST_CASE("JsonArray::isNull()") {
SECTION("returns true for undefined JsonArray") { DynamicJsonDocument doc;
JsonArray array;
REQUIRE(array.isNull() == true); SECTION("returns true") {
JsonArray arr;
REQUIRE(arr.isNull() == true);
} }
SECTION("returns false when allocation succeeds") { SECTION("returns false") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc; JsonArray arr = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>(); REQUIRE(arr.isNull() == false);
REQUIRE(array.isNull() == false);
} }
/* SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}*/
} }
TEST_CASE("JsonArrayConst::isNull()") { TEST_CASE("JsonArrayConst::isNull()") {
SECTION("returns true for undefined JsonArray") { DynamicJsonDocument doc;
JsonArrayConst array;
REQUIRE(array.isNull() == true); SECTION("returns true") {
JsonArrayConst arr;
REQUIRE(arr.isNull() == true);
} }
SECTION("returns false when allocation succeeds") { SECTION("returns false") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc; JsonArrayConst arr = doc.to<JsonArray>();
JsonArrayConst array = doc.to<JsonArray>(); REQUIRE(arr.isNull() == false);
REQUIRE(array.isNull() == false);
} }
/* SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}*/
} }

View File

@ -6,20 +6,29 @@
#include <catch.hpp> #include <catch.hpp>
TEST_CASE("JsonObject::isNull()") { TEST_CASE("JsonObject::isNull()") {
SECTION("returns true for undefined JsonObject") { DynamicJsonDocument doc;
JsonObject array;
REQUIRE(array.isNull() == true); SECTION("returns true") {
JsonObject obj;
REQUIRE(obj.isNull() == true);
} }
SECTION("returns false when allocation succeeds") { SECTION("returns false") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc; JsonObject obj = doc.to<JsonObject>();
JsonObject array = doc.to<JsonObject>(); REQUIRE(obj.isNull() == false);
REQUIRE(array.isNull() == false); }
}
TEST_CASE("JsonObjectConst::isNull()") {
DynamicJsonDocument doc;
SECTION("returns true") {
JsonObjectConst obj;
REQUIRE(obj.isNull() == true);
}
SECTION("returns false") {
JsonObjectConst obj = doc.to<JsonObject>();
REQUIRE(obj.isNull() == false);
} }
/* SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == true);
}*/
} }

View File

@ -50,4 +50,19 @@ TEST_CASE("Polyfills/type_traits") {
CHECK(is_unsigned<float>::value == false); CHECK(is_unsigned<float>::value == false);
CHECK(is_unsigned<double>::value == false); CHECK(is_unsigned<double>::value == false);
} }
SECTION("IsVisitable") {
CHECK(IsVisitable<DeserializationError>::value == false);
CHECK(IsVisitable<JsonPair>::value == false);
CHECK(IsVisitable<JsonVariant>::value == true);
CHECK(IsVisitable<JsonVariantConst>::value == true);
CHECK(IsVisitable<JsonArray>::value == true);
CHECK(IsVisitable<JsonArraySubscript>::value == true);
CHECK(IsVisitable<JsonArrayConst>::value == true);
CHECK(IsVisitable<JsonObject>::value == true);
CHECK(IsVisitable<JsonObjectSubscript<const char*> >::value == true);
CHECK(IsVisitable<JsonObjectConst>::value == true);
CHECK(IsVisitable<DynamicJsonDocument>::value == true);
CHECK(IsVisitable<StaticJsonDocument<10> >::value == true);
}
} }