From f7de0276176909879edd66ceecf907bb92d688c4 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Tue, 12 May 2020 18:53:26 +0200 Subject: [PATCH] Break build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0 --- CHANGELOG.md | 1 + extras/tests/FailingBuilds/CMakeLists.txt | 8 ++++++++ extras/tests/FailingBuilds/read_long_long.cpp | 20 +++++++++++++++++++ .../tests/FailingBuilds/write_long_long.cpp | 19 ++++++++++++++++++ .../MixedConfiguration/use_long_long_0.cpp | 20 +++---------------- src/ArduinoJson/Numbers/Integer.hpp | 11 ++++++++++ src/ArduinoJson/Variant/VariantAs.hpp | 1 + src/ArduinoJson/Variant/VariantData.hpp | 10 +++++----- src/ArduinoJson/Variant/VariantFunctions.hpp | 14 ++++--------- src/ArduinoJson/Variant/VariantRef.hpp | 15 +++----------- 10 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 extras/tests/FailingBuilds/read_long_long.cpp create mode 100644 extras/tests/FailingBuilds/write_long_long.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a1637e96..0f358624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ HEAD * Added support for `enum`s in `as()` and `is()` (issue #1256) * Added `JsonVariant` as an input type for `deserializeXxx()` For example, you can do: `deserializeJson(doc2, doc1["payload"])` +* Break the build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0 v6.15.1 (2020-04-08) ------- diff --git a/extras/tests/FailingBuilds/CMakeLists.txt b/extras/tests/FailingBuilds/CMakeLists.txt index 590fe9c2..986c8644 100644 --- a/extras/tests/FailingBuilds/CMakeLists.txt +++ b/extras/tests/FailingBuilds/CMakeLists.txt @@ -28,3 +28,11 @@ build_should_fail(Issue978) add_executable(Issue1189 Issue1189.cpp) build_should_fail(Issue1189) + +add_executable(read_long_long read_long_long.cpp) +set_property(TARGET read_long_long PROPERTY CXX_STANDARD 11) +build_should_fail(read_long_long) + +add_executable(write_long_long write_long_long.cpp) +set_property(TARGET write_long_long PROPERTY CXX_STANDARD 11) +build_should_fail(write_long_long) diff --git a/extras/tests/FailingBuilds/read_long_long.cpp b/extras/tests/FailingBuilds/read_long_long.cpp new file mode 100644 index 00000000..94a9499a --- /dev/null +++ b/extras/tests/FailingBuilds/read_long_long.cpp @@ -0,0 +1,20 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#define ARDUINOJSON_USE_LONG_LONG 0 +#include + +#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8 +#error This test requires sizeof(long) < 8 +#endif + +#if !ARDUINOJSON_HAS_LONG_LONG +#error This test requires C++11 +#endif + +ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(long long) +int main() { + DynamicJsonDocument doc(1024); + doc["dummy"].as(); +} diff --git a/extras/tests/FailingBuilds/write_long_long.cpp b/extras/tests/FailingBuilds/write_long_long.cpp new file mode 100644 index 00000000..094bd4c1 --- /dev/null +++ b/extras/tests/FailingBuilds/write_long_long.cpp @@ -0,0 +1,19 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#define ARDUINOJSON_USE_LONG_LONG 0 +#include + +#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8 +#error This test requires sizeof(long) < 8 +#endif + +#if !ARDUINOJSON_HAS_LONG_LONG +#error This test requires C++11 +#endif + +int main() { + DynamicJsonDocument doc(1024); + doc["dummy"] = static_cast(42); +} diff --git a/extras/tests/MixedConfiguration/use_long_long_0.cpp b/extras/tests/MixedConfiguration/use_long_long_0.cpp index a2d8770b..f467aabd 100644 --- a/extras/tests/MixedConfiguration/use_long_long_0.cpp +++ b/extras/tests/MixedConfiguration/use_long_long_0.cpp @@ -3,28 +3,14 @@ #include -template -std::string get_expected_json(); - -template <> -std::string get_expected_json<4>() { - return "{\"A\":2899336981,\"B\":2129924785}"; -} - -template <> -std::string get_expected_json<8>() { - return "{\"A\":123456789123456789,\"B\":987654321987654321}"; -} - TEST_CASE("ARDUINOJSON_USE_LONG_LONG == 0") { DynamicJsonDocument doc(4096); - JsonObject root = doc.to(); - root["A"] = 123456789123456789; - root["B"] = 987654321987654321; + doc["A"] = 42; + doc["B"] = 84; std::string json; serializeJson(doc, json); - REQUIRE(json == get_expected_json()); + REQUIRE(json == "{\"A\":42,\"B\":84}"); } diff --git a/src/ArduinoJson/Numbers/Integer.hpp b/src/ArduinoJson/Numbers/Integer.hpp index d3fed13a..bca137cf 100644 --- a/src/ArduinoJson/Numbers/Integer.hpp +++ b/src/ArduinoJson/Numbers/Integer.hpp @@ -18,4 +18,15 @@ typedef uint64_t UInt; typedef long Integer; typedef unsigned long UInt; #endif + } // namespace ARDUINOJSON_NAMESPACE + +#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ + static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ + "To use 64-bit integers with ArduinoJson, you must set " \ + "ARDUINOJSON_USE_LONG_LONG to 1. See " \ + "https://arduinojson.org/v6/api/config/use_long_long/"); +#else +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) +#endif diff --git a/src/ArduinoJson/Variant/VariantAs.hpp b/src/ArduinoJson/Variant/VariantAs.hpp index de6f7faa..e1c44151 100644 --- a/src/ArduinoJson/Variant/VariantAs.hpp +++ b/src/ArduinoJson/Variant/VariantAs.hpp @@ -55,6 +55,7 @@ struct VariantConstAs { template inline typename enable_if::value, T>::type variantAs( const VariantData* data) { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); return data != 0 ? data->asIntegral() : T(0); } diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 79ac0fba..31e2efaa 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -258,6 +258,11 @@ class VariantData { } } + void setUnsignedInteger(UInt value) { + setType(VALUE_IS_POSITIVE_INTEGER); + _content.asInteger = static_cast(value); + } + void setPositiveInteger(UInt value) { setType(VALUE_IS_POSITIVE_INTEGER); _content.asInteger = value; @@ -301,11 +306,6 @@ class VariantData { return setOwnedString(value.save(pool)); } - void setUnsignedInteger(UInt value) { - setType(VALUE_IS_POSITIVE_INTEGER); - _content.asInteger = static_cast(value); - } - CollectionData &toArray() { setType(VALUE_IS_ARRAY); _content.asCollection.clear(); diff --git a/src/ArduinoJson/Variant/VariantFunctions.hpp b/src/ArduinoJson/Variant/VariantFunctions.hpp index 7b2a9b66..eeef4c11 100644 --- a/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -105,14 +105,6 @@ inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, return var != 0 && var->setOwnedRaw(value, pool); } -template -inline bool variantSetSignedInteger(VariantData *var, T value) { - if (!var) - return false; - var->setSignedInteger(value); - return true; -} - inline bool variantSetLinkedString(VariantData *var, const char *value) { if (!var) return false; @@ -138,10 +130,12 @@ inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) { return var != 0 && var->setOwnedString(value, pool); } -inline bool variantSetUnsignedInteger(VariantData *var, UInt value) { +template +inline bool variantSetInteger(VariantData *var, T value) { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); if (!var) return false; - var->setUnsignedInteger(value); + var->setInteger(value); return true; } diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index a32bb5b1..6b2006ab 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -178,22 +178,13 @@ class VariantRef : public VariantRefBase, // set(signed int) // set(signed long) // set(signed char) - template - FORCE_INLINE bool set( - T value, - typename enable_if::value && is_signed::value>::type * = - 0) const { - return variantSetSignedInteger(_data, value); - } - // set(unsigned short) // set(unsigned int) // set(unsigned long) template FORCE_INLINE bool set( - T value, typename enable_if::value && - is_unsigned::value>::type * = 0) const { - return variantSetUnsignedInteger(_data, static_cast(value)); + T value, typename enable_if::value>::type * = 0) const { + return variantSetInteger(_data, value); } // set(SerializedValue) @@ -248,7 +239,7 @@ class VariantRef : public VariantRefBase, template FORCE_INLINE bool set( T value, typename enable_if::value>::type * = 0) const { - return variantSetSignedInteger(_data, static_cast(value)); + return variantSetInteger(_data, static_cast(value)); } template