Added JsonVariant::operator| to return a default value

This commit is contained in:
Benoit Blanchon
2017-11-29 09:49:40 +01:00
parent 126f7ab819
commit d3a1203782
5 changed files with 206 additions and 173 deletions

View File

@ -3,8 +3,26 @@ ArduinoJson: change log
HEAD HEAD
---- ----
* Added `JsonVariant::operator|` to return a default value (see bellow)
* Rewrote example `JsonHttpClient.ino` (issue #600) * Rewrote example `JsonHttpClient.ino` (issue #600)
> ### How to use the new feature?
>
> If you have a block like this:
>
> ```c++
> const char* ssid = root["ssid"];
> if (!ssid)
> ssid = "default ssid";
> ```
>
> You can simplify like that:
>
> ```c++
> const char* ssid = root["ssid"] | "default ssid";
> ```
v5.11.2 v5.11.2
------- -------
@ -46,27 +64,26 @@ v5.10.0
* Fixed error `IsBaseOf is not a member of ArduinoJson::TypeTraits` (issue #495) * Fixed error `IsBaseOf is not a member of ArduinoJson::TypeTraits` (issue #495)
* Fixed error `forming reference to reference` (issue #495) * Fixed error `forming reference to reference` (issue #495)
### BREAKING CHANGES :warning: > ### BREAKING CHANGES :warning:
>
| Old syntax | New syntax | > | Old syntax | New syntax |
|:--------------------------------|:--------------------| > |:--------------------------------|:--------------------|
| `double_with_n_digits(3.14, 2)` | `3.14` | > | `double_with_n_digits(3.14, 2)` | `3.14` |
| `float_with_n_digits(3.14, 2)` | `3.14f` | > | `float_with_n_digits(3.14, 2)` | `3.14f` |
| `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` | > | `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` |
| `arr.add(3.14, 2)` | `arr.add(3.14)` | > | `arr.add(3.14, 2)` | `arr.add(3.14)` |
>
| Input | Old output | New output | > | Input | Old output | New output |
|:----------|:-----------|:-----------| > |:----------|:-----------|:-----------|
| `3.14159` | `3.14` | `3.14159` | > | `3.14159` | `3.14` | `3.14159` |
| `42.0` | `42.00` | `42` | > | `42.0` | `42.00` | `42` |
| `0.0` | `0.00` | `0` | > | `0.0` | `0.00` | `0` |
>
| Expression | Old result | New result | > | Expression | Old result | New result |
|:-------------------------------|:-----------|:-----------| > |:-------------------------------|:-----------|:-----------|
| `JsonVariant(42).is<int>()` | `true` | `true` | > | `JsonVariant(42).is<int>()` | `true` | `true` |
| `JsonVariant(42).is<float>()` | `false` | `true` | > | `JsonVariant(42).is<float>()` | `false` | `true` |
| `JsonVariant(42).is<double>()` | `false` | `true` | > | `JsonVariant(42).is<double>()` | `false` | `true` |
v5.9.0 v5.9.0
------ ------
@ -120,24 +137,23 @@ v5.8.0
* Added support for `Stream` (issue #300) * Added support for `Stream` (issue #300)
* Reduced memory consumption by not duplicating spaces and comments * Reduced memory consumption by not duplicating spaces and comments
### BREAKING CHANGES :warning: > ### BREAKING CHANGES :warning:
>
`JsonBuffer::parseObject()` and `JsonBuffer::parseArray()` have been pulled down to the derived classes `DynamicJsonBuffer` and `StaticJsonBufferBase`. > `JsonBuffer::parseObject()` and `JsonBuffer::parseArray()` have been pulled down to the derived classes `DynamicJsonBuffer` and `StaticJsonBufferBase`.
>
This means that if you have code like: > This means that if you have code like:
>
```c++ > ```c++
void myFunction(JsonBuffer& jsonBuffer); > void myFunction(JsonBuffer& jsonBuffer);
``` > ```
>
you need to replace it with one of the following: > you need to replace it with one of the following:
>
```c++ > ```c++
void myFunction(DynamicJsonBuffer& jsonBuffer); > void myFunction(DynamicJsonBuffer& jsonBuffer);
void myFunction(StaticJsonBufferBase& jsonBuffer); > void myFunction(StaticJsonBufferBase& jsonBuffer);
template<typename TJsonBuffer> void myFunction(TJsonBuffer& jsonBuffer); > template<typename TJsonBuffer> void myFunction(TJsonBuffer& jsonBuffer);
``` > ```
v5.7.3 v5.7.3
------ ------
@ -170,27 +186,26 @@ v5.7.0
* Added example `StringExample.ino` to show where `String` can be used * Added example `StringExample.ino` to show where `String` can be used
* Increased default nesting limit to 50 when compiled for a computer (issue #349) * Increased default nesting limit to 50 when compiled for a computer (issue #349)
### BREAKING CHANGES :warning: > ### BREAKING CHANGES :warning:
>
The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return. > The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return.
>
Old code: > Old code:
>
```c++ > ```c++
#define ARDUINOJSON_USE_ARDUINO_STRING 0 > #define ARDUINOJSON_USE_ARDUINO_STRING 0
JsonVariant value1 = myObject.get("myKey"); > JsonVariant value1 = myObject.get("myKey");
JsonVariant value2 = myArray.get(0); > JsonVariant value2 = myArray.get(0);
``` > ```
>
New code: > New code:
>
```c++ > ```c++
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 > #define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#define ARDUINOJSON_ENABLE_STD_STRING 1 > #define ARDUINOJSON_ENABLE_STD_STRING 1
JsonVariant value1 = myObject.get<JsonVariant>("myKey"); > JsonVariant value1 = myObject.get<JsonVariant>("myKey");
JsonVariant value2 = myArray.get<JsonVariant>(0); > JsonVariant value2 = myArray.get<JsonVariant>(0);
``` > ```
v5.6.7 v5.6.7
------ ------
@ -282,8 +297,9 @@ v5.1.0
* Added support of `long long` (issue #171) * Added support of `long long` (issue #171)
* Moved all build settings to `ArduinoJson/Configuration.hpp` * Moved all build settings to `ArduinoJson/Configuration.hpp`
**BREAKING CHANGE**: > ### BREAKING CHANGE :warning:
If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`. >
> If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`.
v5.0.8 v5.0.8
------ ------
@ -297,10 +313,10 @@ v5.0.7
* Made library easier to use from a CMake project: simply `add_subdirectory(ArduinoJson/src)` * Made library easier to use from a CMake project: simply `add_subdirectory(ArduinoJson/src)`
* Changed `String` to be a `typedef` of `std::string` (issues #142 and #161) * Changed `String` to be a `typedef` of `std::string` (issues #142 and #161)
### BREAKING CHANGES :warning: > ### BREAKING CHANGES :warning:
>
- `JsonVariant(true).as<String>()` now returns `"true"` instead of `"1"` > - `JsonVariant(true).as<String>()` now returns `"true"` instead of `"1"`
- `JsonVariant(false).as<String>()` now returns `"false"` instead of `"0"` > - `JsonVariant(false).as<String>()` now returns `"false"` instead of `"0"`
v5.0.6 v5.0.6
------ ------
@ -354,11 +370,11 @@ v5.0.0
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66) * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66)
* Switched to new the library layout (requires Arduino 1.0.6 or above) * Switched to new the library layout (requires Arduino 1.0.6 or above)
### BREAKING CHANGES :warning: > ### BREAKING CHANGES :warning:
>
- `JsonObject::add()` was renamed to `set()` > - `JsonObject::add()` was renamed to `set()`
- `JsonArray::at()` and `JsonObject::at()` were renamed to `get()` > - `JsonArray::at()` and `JsonObject::at()` were renamed to `get()`
- Number of digits of floating point value are now set with `double_with_n_digits()` > - Number of digits of floating point value are now set with `double_with_n_digits()`
**Personal note about the `String` class**: **Personal note about the `String` class**:
Support of the `String` class has been added to the library because many people use it in their programs. Support of the `String` class has been added to the library because many people use it in their programs.
@ -411,106 +427,7 @@ v4.0
* Unified parser and generator API (issue #23) * Unified parser and generator API (issue #23)
* Updated library layout, now requires Arduino 1.0.6 or newer * Updated library layout, now requires Arduino 1.0.6 or newer
**BREAKING CHANGE**: API changed significantly, see [Migrating code to the new API](https://github.com/bblanchon/ArduinoJson/wiki/Migrating-code-to-the-new-API). > ### BREAKING CHANGES :warning:
>
> API changed significantly since v3, see [Migrating code to the new API](http://arduinojson.org/doc/migration/).
v3.4
----
* Fixed escaped char parsing (issue #16)
v3.3
----
* Added indented output for the JSON generator (issue #11), see example bellow.
* Added `IndentedPrint`, a decorator for `Print` to allow indented output
Example:
JsonOject<2> json;
json["key"] = "value";
json.prettyPrintTo(Serial);
v3.2
----
* Fixed a bug when adding nested object in `JsonArray` (bug introduced in v3.1).
v3.1
----
* Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value`
* Added `Generator::JsonObject::operator[]`, see bellow the new API
* Added `Generator::JsonObject::remove()` (issue #9)
Old generator API:
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
New generator API:
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
v3.0
----
* New parser API, see bellow
* Renamed `JsonHashTable` into `JsonObject`
* Added iterators for `JsonArray` and `JsonObject` (issue #4)
Old parser API:
JsonHashTable root = parser.parseHashTable(json);
char* sensor = root.getString("sensor");
long time = root.getLong("time");
double latitude = root.getArray("data").getDouble(0);
double longitude = root.getArray("data").getDouble(1);
New parser API:
JsonObject root = parser.parse(json);
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
v2.1
----
* Fixed case `#include "jsmn.cpp"` which caused an error in Linux (issue #6)
* Fixed a buffer overrun in JSON Parser (issue #5)
v2.0
----
* Added JSON encoding (issue #2)
* Renamed the library `ArduinoJsonParser` becomes `ArduinoJson`
**Breaking change**: you need to add the following line at the top of your program.
using namespace ArduinoJson::Parser;
v1.2
----
* Fixed error in JSON parser example (issue #1)
v1.1
----
* Example: changed `char* json` into `char[] json` so that the bytes are not write protected
* Fixed parsing bug when the JSON contains multi-dimensional arrays
v1.0
----
Initial release

View File

@ -6,6 +6,7 @@
#include "JsonVariantCasts.hpp" #include "JsonVariantCasts.hpp"
#include "JsonVariantComparisons.hpp" #include "JsonVariantComparisons.hpp"
#include "JsonVariantOr.hpp"
#include "JsonVariantSubscripts.hpp" #include "JsonVariantSubscripts.hpp"
#include "Serialization/JsonPrintable.hpp" #include "Serialization/JsonPrintable.hpp"
@ -15,6 +16,7 @@ template <typename TImpl>
class JsonVariantBase : public Internals::JsonPrintable<TImpl>, class JsonVariantBase : public Internals::JsonPrintable<TImpl>,
public JsonVariantCasts<TImpl>, public JsonVariantCasts<TImpl>,
public JsonVariantComparisons<TImpl>, public JsonVariantComparisons<TImpl>,
public JsonVariantOr<TImpl>,
public JsonVariantSubscripts<TImpl>, public JsonVariantSubscripts<TImpl>,
public TypeTraits::JsonVariantTag {}; public TypeTraits::JsonVariantTag {};
} }

View File

@ -0,0 +1,36 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2017
// MIT License
#pragma once
#include "Data/JsonVariantAs.hpp"
#include "Polyfills/attributes.hpp"
namespace ArduinoJson {
template <typename TImpl>
class JsonVariantOr {
public:
// Returns the default value if the JsonVariant is undefined of incompatible
template <typename T>
T operator|(const T &defaultValue) const {
if (impl()->template is<T>())
return impl()->template as<T>();
else
return defaultValue;
}
// Returns the default value if the JsonVariant is undefined of incompatible
// Special case for string: null is treated as undefined
const char *operator|(const char *defaultValue) const {
const char *value = impl()->template as<const char *>();
return value ? value : defaultValue;
}
private:
const TImpl *impl() const {
return static_cast<const TImpl *>(this);
}
};
}

View File

@ -7,6 +7,7 @@ add_executable(JsonVariantTests
compare.cpp compare.cpp
copy.cpp copy.cpp
is.cpp is.cpp
or.cpp
printTo.cpp printTo.cpp
set_get.cpp set_get.cpp
subscript.cpp subscript.cpp

77
test/JsonVariant/or.cpp Normal file
View File

@ -0,0 +1,77 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2017
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
static const JsonVariant undefined;
static const JsonVariant null = static_cast<const char*>(0);
TEST_CASE("JsonVariant::operator|()") {
SECTION("undefined | const char*") {
std::string result = undefined | "default";
REQUIRE(result == "default");
}
SECTION("undefined | int") {
int result = undefined | 42;
REQUIRE(result == 42);
}
SECTION("undefined | bool") {
bool result = undefined | true;
REQUIRE(result == true);
}
SECTION("null | const char*") {
std::string result = null | "default";
REQUIRE(result == "default");
}
SECTION("null | int") {
int result = null | 42;
REQUIRE(result == 42);
}
SECTION("null | bool") {
bool result = null | true;
REQUIRE(result == true);
}
SECTION("int | const char*") {
JsonVariant variant = 42;
std::string result = variant | "default";
REQUIRE(result == "default");
}
SECTION("int | int") {
JsonVariant variant = 0;
int result = variant | 666;
REQUIRE(result == 0);
}
SECTION("bool | bool") {
JsonVariant variant = false;
bool result = variant | true;
REQUIRE(result == false);
}
SECTION("int | bool") {
JsonVariant variant = 0;
bool result = variant | true;
REQUIRE(result == true);
}
SECTION("const char* | const char*") {
JsonVariant variant = "not default";
std::string result = variant | "default";
REQUIRE(result == "not default");
}
SECTION("const char* | int") {
JsonVariant variant = "not default";
int result = variant | 42;
REQUIRE(result == 42);
}
}