Added as<JsonArray>() as a synonym for as<JsonArray&>()... (issue #291)

This commit is contained in:
Benoit Blanchon
2016-07-17 17:22:58 +02:00
parent 2dbd94951c
commit c87a0e97ab
13 changed files with 175 additions and 30 deletions

View File

@ -5,6 +5,7 @@ HEAD
---- ----
* Improved speed of float serialization (about twice faster) * Improved speed of float serialization (about twice faster)
* Added `as<JsonArray>()` as a synonym for `as<JsonArray&>()`... (issue #291)
v5.6.2 v5.6.2
------ ------

View File

@ -0,0 +1,45 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
// A metafunction that returns the type of the value returned by
// JsonVariant::as<T>()
template <typename T>
struct JsonVariantAs {
typedef T type;
};
template <>
struct JsonVariantAs<char*> {
typedef const char* type;
};
template <>
struct JsonVariantAs<JsonArray> {
typedef JsonArray& type;
};
template <>
struct JsonVariantAs<const JsonArray> {
typedef const JsonArray& type;
};
template <>
struct JsonVariantAs<JsonObject> {
typedef JsonObject& type;
};
template <>
struct JsonVariantAs<const JsonObject> {
typedef const JsonObject& type;
};
}
}

View File

@ -137,7 +137,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Gets the value at the specified index. // Gets the value at the specified index.
template <typename T> template <typename T>
T get(size_t index) const { typename Internals::JsonVariantAs<T>::type get(size_t index) const {
node_type *node = getNodeAt(index); node_type *node = getNodeAt(index);
return node ? node->content.as<T>() : JsonVariant::defaultValue<T>(); return node ? node->content.as<T>() : JsonVariant::defaultValue<T>();
} }

View File

@ -21,13 +21,23 @@ inline bool JsonArray::setNodeValue(node_type *node, String &value) {
return true; return true;
} }
template <>
inline JsonArray &JsonVariant::defaultValue<JsonArray>() {
return JsonArray::invalid();
}
template <> template <>
inline JsonArray &JsonVariant::defaultValue<JsonArray &>() { inline JsonArray &JsonVariant::defaultValue<JsonArray &>() {
return JsonArray::invalid(); return JsonArray::invalid();
} }
template <> template <>
inline JsonArray const &JsonVariant::defaultValue<JsonArray const &>() { inline const JsonArray &JsonVariant::defaultValue<const JsonArray>() {
return JsonArray::invalid();
}
template <>
inline const JsonArray &JsonVariant::defaultValue<const JsonArray &>() {
return JsonArray::invalid(); return JsonArray::invalid();
} }

View File

@ -42,12 +42,16 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return *this; return *this;
} }
FORCE_INLINE bool success() const { return _index < _array.size(); } FORCE_INLINE bool success() const {
return _index < _array.size();
}
FORCE_INLINE operator JsonVariant() const { return _array.get(_index); } FORCE_INLINE operator JsonVariant() const {
return _array.get(_index);
}
template <typename T> template <typename T>
FORCE_INLINE T as() const { FORCE_INLINE typename Internals::JsonVariantAs<T>::type as() const {
return _array.get<T>(_index); return _array.get<T>(_index);
} }

View File

@ -106,7 +106,7 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// Gets the value associated with the specified key. // Gets the value associated with the specified key.
template <typename T> template <typename T>
T get(JsonObjectKey key) const { typename Internals::JsonVariantAs<T>::type get(JsonObjectKey key) const {
node_type* node = getNodeAt(key.c_str()); node_type* node = getNodeAt(key.c_str());
return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>(); return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>();
} }

View File

@ -26,7 +26,12 @@ inline bool JsonObject::setNodeValue(node_type *node, const String &value) {
} }
template <> template <>
inline JsonObject const &JsonVariant::defaultValue<JsonObject const &>() { inline const JsonObject &JsonVariant::defaultValue<const JsonObject &>() {
return JsonObject::invalid();
}
template <>
inline const JsonObject &JsonVariant::defaultValue<const JsonObject>() {
return JsonObject::invalid(); return JsonObject::invalid();
} }
@ -35,6 +40,11 @@ inline JsonObject &JsonVariant::defaultValue<JsonObject &>() {
return JsonObject::invalid(); return JsonObject::invalid();
} }
template <>
inline JsonObject &JsonVariant::defaultValue<JsonObject>() {
return JsonObject::invalid();
}
inline JsonObject &JsonVariant::asObject() const { inline JsonObject &JsonVariant::asObject() const {
if (_type == Internals::JSON_OBJECT) return *_content.asObject; if (_type == Internals::JSON_OBJECT) return *_content.asObject;
return JsonObject::invalid(); return JsonObject::invalid();

View File

@ -54,7 +54,7 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
} }
template <typename TValue> template <typename TValue>
FORCE_INLINE TValue as() const { FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type as() const {
return _object.get<TValue>(_key); return _object.get<TValue>(_key);
} }

View File

@ -177,28 +177,43 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// //
// JsonArray& as<JsonArray> const; // JsonArray& as<JsonArray> const;
// JsonArray& as<JsonArray&> const; // JsonArray& as<JsonArray&> const;
// JsonArray& as<const JsonArray&> const;
template <typename T> template <typename T>
typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
TypeTraits::IsSame< TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
typename TypeTraits::RemoveConst<
typename TypeTraits::RemoveReference<T>::type>::type,
JsonArray>::value, JsonArray>::value,
JsonArray &>::type JsonArray &>::type
as() const { as() const {
return asArray(); return asArray();
} }
// //
// const JsonArray& as<const JsonArray&> const;
template <typename T>
typename TypeTraits::EnableIf<
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
const JsonArray>::value,
const JsonArray &>::type
as() const {
return asArray();
}
//
// JsonObject& as<JsonObject> const; // JsonObject& as<JsonObject> const;
// JsonObject& as<JsonObject&> const; // JsonObject& as<JsonObject&> const;
template <typename T>
typename TypeTraits::EnableIf<
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
JsonObject>::value,
JsonObject &>::type
as() const {
return asObject();
}
//
// JsonObject& as<const JsonObject> const;
// JsonObject& as<const JsonObject&> const; // JsonObject& as<const JsonObject&> const;
template <typename T> template <typename T>
typename TypeTraits::EnableIf< typename TypeTraits::EnableIf<
TypeTraits::IsSame< TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
typename TypeTraits::RemoveConst< const JsonObject>::value,
typename TypeTraits::RemoveReference<T>::type>::type, const JsonObject &>::type
JsonObject>::value,
JsonObject &>::type
as() const { as() const {
return asObject(); return asObject();
} }
@ -281,7 +296,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
// Value returned if the variant has an incompatible type // Value returned if the variant has an incompatible type
template <typename T> template <typename T>
static T defaultValue() { static typename Internals::JsonVariantAs<T>::type defaultValue() {
return T(); return T();
} }

View File

@ -7,8 +7,9 @@
#pragma once #pragma once
#include "Polyfills/attributes.hpp" #include "Internals/JsonVariantAs.hpp"
#include "JsonObjectKey.hpp" #include "JsonObjectKey.hpp"
#include "Polyfills/attributes.hpp"
namespace ArduinoJson { namespace ArduinoJson {
@ -20,20 +21,35 @@ class JsonObjectSubscript;
template <typename TImpl> template <typename TImpl>
class JsonVariantBase : public Internals::JsonPrintable<TImpl> { class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
public: public:
FORCE_INLINE const char *asString() const { return as<const char *>(); } // DEPRECATED: use as<char*>() instead
FORCE_INLINE const char *asString() const {
return as<const char *>();
}
// Gets the variant as an array. // Gets the variant as an array.
// Returns a reference to the JsonArray or JsonArray::invalid() if the // Returns a reference to the JsonArray or JsonArray::invalid() if the
// variant // variant
// is not an array. // is not an array.
FORCE_INLINE operator JsonArray &() const { return as<JsonArray &>(); } FORCE_INLINE operator JsonArray &() const {
FORCE_INLINE JsonArray &asArray() const { return as<JsonArray &>(); } return as<JsonArray &>();
}
// DEPRECATED: use as<JsonArray>() instead
FORCE_INLINE JsonArray &asArray() const {
return as<JsonArray &>();
}
// Gets the variant as an object. // Gets the variant as an object.
// Returns a reference to the JsonObject or JsonObject::invalid() if the // Returns a reference to the JsonObject or JsonObject::invalid() if the
// variant is not an object. // variant is not an object.
FORCE_INLINE operator JsonObject &() const { return as<JsonObject &>(); } FORCE_INLINE operator JsonObject &() const {
FORCE_INLINE JsonObject &asObject() const { return as<JsonObject &>(); } return as<JsonObject &>();
}
// DEPRECATED: use as<JsonObject>() instead
FORCE_INLINE JsonObject &asObject() const {
return as<JsonObject &>();
}
template <typename T> template <typename T>
FORCE_INLINE operator T() const { FORCE_INLINE operator T() const {
@ -41,14 +57,16 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
} }
template <typename T> template <typename T>
FORCE_INLINE const T as() const { FORCE_INLINE const typename Internals::JsonVariantAs<T>::type as() const {
return impl()->template as<T>(); return impl()->template as<T>();
} }
// Mimics an array or an object. // Mimics an array or an object.
// Returns the size of the array or object if the variant has that type. // Returns the size of the array or object if the variant has that type.
// Returns 0 if the variant is neither an array nor an object // Returns 0 if the variant is neither an array nor an object
size_t size() const { return asArray().size() + asObject().size(); } size_t size() const {
return asArray().size() + asObject().size();
}
// Mimics an array. // Mimics an array.
// Returns the element at specified index if the variant is an array. // Returns the element at specified index if the variant is an array.
@ -68,7 +86,9 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
void writeTo(Internals::JsonWriter &writer) const; void writeTo(Internals::JsonWriter &writer) const;
private: private:
const TImpl *impl() const { return static_cast<const TImpl *>(this); } const TImpl *impl() const {
return static_cast<const TImpl *>(this);
}
}; };
template <typename TImpl, typename TComparand> template <typename TImpl, typename TComparand>

View File

@ -59,6 +59,7 @@ TEST_(StoreBoolean) {
TEST_(StoreString) { TEST_(StoreString) {
_array[0] = "hello"; _array[0] = "hello";
EXPECT_STREQ("hello", _array[0].as<const char*>()); EXPECT_STREQ("hello", _array[0].as<const char*>());
EXPECT_STREQ("hello", _array[0].as<char*>()); // <- short hand
EXPECT_TRUE(_array[0].is<const char*>()); EXPECT_TRUE(_array[0].is<const char*>());
EXPECT_FALSE(_array[0].is<int>()); EXPECT_FALSE(_array[0].is<int>());
} }
@ -69,6 +70,9 @@ TEST_(StoreNestedArray) {
_array[0] = arr; _array[0] = arr;
EXPECT_EQ(&arr, &_array[0].as<JsonArray&>()); EXPECT_EQ(&arr, &_array[0].as<JsonArray&>());
EXPECT_EQ(&arr, &_array[0].as<JsonArray>()); // <- short hand
EXPECT_EQ(&arr, &_array[0].as<const JsonArray&>());
EXPECT_EQ(&arr, &_array[0].as<const JsonArray>()); // <- short hand
EXPECT_TRUE(_array[0].is<JsonArray&>()); EXPECT_TRUE(_array[0].is<JsonArray&>());
EXPECT_FALSE(_array[0].is<int>()); EXPECT_FALSE(_array[0].is<int>());
} }
@ -79,6 +83,9 @@ TEST_(StoreNestedObject) {
_array[0] = obj; _array[0] = obj;
EXPECT_EQ(&obj, &_array[0].as<JsonObject&>()); EXPECT_EQ(&obj, &_array[0].as<JsonObject&>());
EXPECT_EQ(&obj, &_array[0].as<JsonObject>()); // <- short hand
EXPECT_EQ(&obj, &_array[0].as<const JsonObject&>());
EXPECT_EQ(&obj, &_array[0].as<const JsonObject>()); // <- short hand
EXPECT_TRUE(_array[0].is<JsonObject&>()); EXPECT_TRUE(_array[0].is<JsonObject&>());
EXPECT_FALSE(_array[0].is<int>()); EXPECT_FALSE(_array[0].is<int>());
} }

View File

@ -68,6 +68,7 @@ TEST_(StoreString) {
EXPECT_TRUE(_object["hello"].is<const char*>()); EXPECT_TRUE(_object["hello"].is<const char*>());
EXPECT_FALSE(_object["hello"].is<long>()); EXPECT_FALSE(_object["hello"].is<long>());
EXPECT_STREQ("h3110", _object["hello"].as<const char*>()); EXPECT_STREQ("h3110", _object["hello"].as<const char*>());
EXPECT_STREQ("h3110", _object["hello"].as<char*>()); // <- short hand
} }
TEST_(StoreArray) { TEST_(StoreArray) {
@ -75,8 +76,15 @@ TEST_(StoreArray) {
_object["hello"] = arr; _object["hello"] = arr;
EXPECT_EQ(&arr, &_object["hello"].asArray()); EXPECT_EQ(&arr, &_object["hello"].asArray()); // <- DEPRECATED
EXPECT_EQ(&arr, &_object["hello"].as<JsonArray&>());
EXPECT_EQ(&arr, &_object["hello"].as<JsonArray>()); // <- short hand
EXPECT_EQ(&arr, &_object["hello"].as<const JsonArray&>());
EXPECT_EQ(&arr, &_object["hello"].as<const JsonArray>()); // <- short hand
EXPECT_TRUE(_object["hello"].is<JsonArray&>()); EXPECT_TRUE(_object["hello"].is<JsonArray&>());
EXPECT_TRUE(_object["hello"].is<JsonArray>());
EXPECT_TRUE(_object["hello"].is<const JsonArray&>());
EXPECT_TRUE(_object["hello"].is<const JsonArray>());
EXPECT_FALSE(_object["hello"].is<JsonObject&>()); EXPECT_FALSE(_object["hello"].is<JsonObject&>());
} }
@ -85,8 +93,15 @@ TEST_(StoreObject) {
_object["hello"] = obj; _object["hello"] = obj;
EXPECT_EQ(&obj, &_object["hello"].asObject()); EXPECT_EQ(&obj, &_object["hello"].asObject()); // DEPRECATED
EXPECT_EQ(&obj, &_object["hello"].as<JsonObject&>());
EXPECT_EQ(&obj, &_object["hello"].as<JsonObject>()); // <- short hand
EXPECT_EQ(&obj, &_object["hello"].as<const JsonObject&>());
EXPECT_EQ(&obj, &_object["hello"].as<const JsonObject>()); // <- short hand
EXPECT_TRUE(_object["hello"].is<JsonObject&>()); EXPECT_TRUE(_object["hello"].is<JsonObject&>());
EXPECT_TRUE(_object["hello"].is<JsonObject>());
EXPECT_TRUE(_object["hello"].is<const JsonObject&>());
EXPECT_TRUE(_object["hello"].is<const JsonObject>());
EXPECT_FALSE(_object["hello"].is<JsonArray&>()); EXPECT_FALSE(_object["hello"].is<JsonArray&>());
} }

View File

@ -214,3 +214,21 @@ TEST(JsonVariant_As_Tests, ArrayAsString) {
JsonVariant variant = arr; JsonVariant variant = arr;
ASSERT_EQ(String("[4,2]"), variant.as<String>()); ASSERT_EQ(String("[4,2]"), variant.as<String>());
} }
TEST(JsonVariant_As_Tests, ArrayAsJsonArray) {
DynamicJsonBuffer buffer;
JsonArray& arr = buffer.createArray();
JsonVariant variant = arr;
ASSERT_EQ(&arr, &variant.as<JsonArray&>());
ASSERT_EQ(&arr, &variant.as<JsonArray>()); // <- shorthand
}
TEST(JsonVariant_As_Tests, ObjectAsJsonObject) {
DynamicJsonBuffer buffer;
JsonObject& arr = buffer.createObject();
JsonVariant variant = arr;
ASSERT_EQ(&arr, &variant.as<JsonObject&>());
ASSERT_EQ(&arr, &variant.as<JsonObject>()); // <- shorthand
}