Skip to content

Commit 65e5900

Browse files
committed
POC with JsonDocument::set()
I must review all the changes before moving on
1 parent 6c71ce4 commit 65e5900

File tree

11 files changed

+172
-52
lines changed

11 files changed

+172
-52
lines changed

extras/tests/JsonDocument/set.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,45 @@ TEST_CASE("JsonDocument::set()") {
1111
SpyingAllocator spy;
1212
JsonDocument doc(&spy);
1313

14+
SECTION("nullptr") {
15+
doc.set(nullptr);
16+
17+
REQUIRE(doc.isNull());
18+
REQUIRE(spy.log() == AllocatorLog{});
19+
}
20+
21+
SECTION("integer&") {
22+
int toto = 42;
23+
doc.set(toto);
24+
25+
REQUIRE(doc.as<std::string>() == "42");
26+
REQUIRE(spy.log() == AllocatorLog{});
27+
}
28+
1429
SECTION("integer") {
1530
doc.set(42);
1631

1732
REQUIRE(doc.as<std::string>() == "42");
1833
REQUIRE(spy.log() == AllocatorLog{});
1934
}
2035

21-
SECTION("const char*") {
36+
SECTION("string literal") {
2237
doc.set("example");
2338

2439
REQUIRE(doc.as<const char*>() == "example"_s);
2540
REQUIRE(spy.log() == AllocatorLog{});
2641
}
2742

43+
SECTION("const char*") {
44+
const char* value = "example";
45+
doc.set(value);
46+
47+
REQUIRE(doc.as<const char*>() == "example"_s);
48+
REQUIRE(spy.log() == AllocatorLog{
49+
Allocate(sizeofString("example")),
50+
});
51+
}
52+
2853
SECTION("std::string") {
2954
doc.set("example"_s);
3055

extras/tests/Misc/StringAdapters.cpp

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,72 +14,90 @@
1414

1515
using namespace ArduinoJson::detail;
1616

17-
TEST_CASE("ZeroTerminatedRamString") {
18-
SECTION("null") {
19-
ZeroTerminatedRamString s = adaptString(static_cast<const char*>(0));
17+
TEST_CASE("String literal") {
18+
auto s = adaptString("bravo");
2019

21-
CHECK(s.isNull() == true);
22-
CHECK(s.size() == 0);
23-
}
20+
CHECK(s.isNull() == false);
21+
CHECK(s.size() == 5);
22+
CHECK(s.isLinked() == true);
23+
}
2424

25-
SECTION("non-null") {
26-
ZeroTerminatedRamString s = adaptString("bravo");
25+
TEST_CASE("null const char*") {
26+
auto s = adaptString(static_cast<const char*>(0));
2727

28-
CHECK(s.isNull() == false);
29-
CHECK(s.size() == 5);
30-
}
28+
CHECK(s.isNull() == true);
29+
CHECK(s.size() == 0);
30+
CHECK(s.isLinked() == false);
3131
}
3232

33-
TEST_CASE("SizedRamString") {
34-
SECTION("null") {
35-
SizedRamString s = adaptString(static_cast<const char*>(0), 10);
33+
TEST_CASE("const char*") {
34+
const char* p = "bravo";
35+
ZeroTerminatedRamString s = adaptString(p);
3636

37-
CHECK(s.isNull() == true);
38-
}
37+
CHECK(s.isNull() == false);
38+
CHECK(s.size() == 5);
39+
CHECK(s.isLinked() == false);
40+
}
3941

40-
SECTION("non-null") {
41-
SizedRamString s = adaptString("bravo", 5);
42+
TEST_CASE("char[]") {
43+
char p[] = "bravo";
44+
ZeroTerminatedRamString s = adaptString(p);
4245

43-
CHECK(s.isNull() == false);
44-
CHECK(s.size() == 5);
45-
}
46+
CHECK(s.isNull() == false);
47+
CHECK(s.size() == 5);
48+
CHECK(s.isLinked() == false);
4649
}
4750

48-
TEST_CASE("FlashString") {
49-
SECTION("null") {
50-
FlashString s = adaptString(static_cast<const __FlashStringHelper*>(0));
51+
TEST_CASE("null const char* + size") {
52+
auto s = adaptString(static_cast<const char*>(0), 10);
5153

52-
CHECK(s.isNull() == true);
53-
CHECK(s.size() == 0);
54-
}
54+
CHECK(s.isNull() == true);
55+
CHECK(s.isLinked() == false);
56+
}
5557

56-
SECTION("non-null") {
57-
FlashString s = adaptString(F("bravo"));
58+
TEST_CASE("const char* + size") {
59+
auto s = adaptString("bravo", 5);
5860

59-
CHECK(s.isNull() == false);
60-
CHECK(s.size() == 5);
61-
}
61+
CHECK(s.isNull() == false);
62+
CHECK(s.size() == 5);
63+
CHECK(s.isLinked() == false);
64+
}
65+
66+
TEST_CASE("null Flash string") {
67+
auto s = adaptString(static_cast<const __FlashStringHelper*>(0));
68+
69+
CHECK(s.isNull() == true);
70+
CHECK(s.size() == 0);
71+
CHECK(s.isLinked() == false);
72+
}
73+
74+
TEST_CASE("Flash string") {
75+
FlashString s = adaptString(F("bravo"));
76+
77+
CHECK(s.isNull() == false);
78+
CHECK(s.size() == 5);
79+
CHECK(s.isLinked() == false);
6280
}
6381

6482
TEST_CASE("std::string") {
6583
std::string orig("bravo");
66-
SizedRamString s = adaptString(orig);
84+
auto s = adaptString(orig);
6785

6886
CHECK(s.isNull() == false);
6987
CHECK(s.size() == 5);
7088
}
7189

7290
TEST_CASE("Arduino String") {
7391
::String orig("bravo");
74-
SizedRamString s = adaptString(orig);
92+
auto s = adaptString(orig);
7593

7694
CHECK(s.isNull() == false);
7795
CHECK(s.size() == 5);
7896
}
7997

8098
TEST_CASE("custom_string") {
8199
custom_string orig("bravo");
82-
SizedRamString s = adaptString(orig);
100+
auto s = adaptString(orig);
83101

84102
CHECK(s.isNull() == false);
85103
CHECK(s.size() == 5);
@@ -88,17 +106,25 @@ TEST_CASE("custom_string") {
88106
struct EmptyStruct {};
89107

90108
TEST_CASE("IsString<T>") {
109+
char charArray[8];
110+
91111
CHECK(IsString<std::string>::value == true);
92112
CHECK(IsString<std::basic_string<wchar_t>>::value == false);
93113
CHECK(IsString<custom_string>::value == true);
94114
CHECK(IsString<const __FlashStringHelper*>::value == true);
95115
CHECK(IsString<const char*>::value == true);
96-
CHECK(IsString<const char[8]>::value == true);
116+
CHECK(IsString<decltype(charArray)>::value == true);
97117
CHECK(IsString<::String>::value == true);
98118
CHECK(IsString<::StringSumHelper>::value == true);
99119
CHECK(IsString<const EmptyStruct*>::value == false);
100120
}
101121

122+
TEST_CASE("IsStringLiteral") {
123+
CHECK(IsStringLiteral<const char*>::value == false);
124+
CHECK(IsStringLiteral<decltype("toto")>::value == true);
125+
CHECK(IsStringLiteral<char[8]>::value == false);
126+
}
127+
102128
TEST_CASE("stringCompare") {
103129
SECTION("ZeroTerminatedRamString vs ZeroTerminatedRamString") {
104130
CHECK(stringCompare(adaptString("bravo"), adaptString("alpha")) > 0);

extras/tests/Misc/TypeTraits.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,23 @@ TEST_CASE("Polyfills/type_traits") {
211211
CHECK(is_enum<bool>::value == false);
212212
CHECK(is_enum<double>::value == false);
213213
}
214+
215+
SECTION("remove_cv") {
216+
CHECK(is_same<remove_cv_t<const int>, int>::value);
217+
CHECK(is_same<remove_cv_t<volatile int>, int>::value);
218+
CHECK(is_same<remove_cv_t<const volatile int>, int>::value);
219+
CHECK(is_same<remove_cv_t<int>, int>::value);
220+
CHECK(is_same<remove_cv_t<decltype("toto")>, decltype("toto")>::value);
221+
}
222+
223+
SECTION("decay") {
224+
CHECK(is_same<decay_t<int>, int>::value);
225+
CHECK(is_same<decay_t<int&>, int>::value);
226+
CHECK(is_same<decay_t<int&&>, int>::value);
227+
CHECK(is_same<decay_t<int[]>, int*>::value);
228+
CHECK(is_same<decay_t<int[10]>, int*>::value);
229+
CHECK(is_same<decay_t<decltype("toto")>, const char*>::value);
230+
}
214231
}
215232

216233
TEST_CASE("is_std_string") {

src/ArduinoJson/Document/JsonDocument.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
138138
// https://arduinojson.org/v7/api/jsondocument/set/
139139
template <typename T>
140140
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, bool> set(
141-
const T& src) {
142-
return to<JsonVariant>().set(src);
141+
T&& src) {
142+
return to<JsonVariant>().set(detail::forward<T>(src));
143143
}
144144

145145
// Replaces the root with the specified value.
146146
// https://arduinojson.org/v7/api/jsondocument/set/
147-
template <typename TChar>
147+
template <typename TChar,
148+
typename = detail::enable_if_t<!detail::is_const<TChar>::value>>
148149
bool set(TChar* src) {
149150
return to<JsonVariant>().set(src);
150151
}
@@ -265,13 +266,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
265266
// Appends a value to the root array.
266267
// https://arduinojson.org/v7/api/jsondocument/add/
267268
template <typename TValue>
268-
bool add(const TValue& value) {
269-
return data_.addValue(value, &resources_);
269+
bool add(TValue&& value) {
270+
return data_.addValue(detail::forward<TValue>(value), &resources_);
270271
}
271272

272273
// Appends a value to the root array.
273274
// https://arduinojson.org/v7/api/jsondocument/add/
274-
template <typename TChar>
275+
template <typename TChar,
276+
typename = detail::enable_if_t<!detail::is_const<TChar>::value>>
275277
bool add(TChar* value) {
276278
return data_.addValue(value, &resources_);
277279
}

src/ArduinoJson/Polyfills/type_traits.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include "type_traits/conditional.hpp"
8+
#include "type_traits/decay.hpp"
89
#include "type_traits/enable_if.hpp"
910
#include "type_traits/function_traits.hpp"
1011
#include "type_traits/integral_constant.hpp"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ArduinoJson - https://arduinojson.org
2+
// Copyright © 2014-2024, Benoit BLANCHON
3+
// MIT License
4+
5+
#pragma once
6+
7+
#include <ArduinoJson/Namespace.hpp>
8+
9+
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
10+
11+
template <typename T>
12+
struct decay {
13+
using type = T;
14+
};
15+
16+
template <typename T>
17+
struct decay<T&> : decay<T> {};
18+
19+
template <typename T>
20+
struct decay<T&&> : decay<T> {};
21+
22+
template <typename T>
23+
struct decay<T[]> : decay<T*> {};
24+
25+
template <typename T, size_t N>
26+
struct decay<T[N]> : decay<T*> {};
27+
28+
template <typename T>
29+
using decay_t = typename decay<T>::type;
30+
31+
ARDUINOJSON_END_PRIVATE_NAMESPACE

src/ArduinoJson/Strings/Adapters/StringLiteral.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class StringLiteral {
4747
};
4848

4949
template <size_t N>
50-
struct StringAdapter<const char[N]> {
50+
struct StringAdapter<const char (&)[N]> {
5151
using AdaptedString = StringLiteral<N>;
5252

5353
static AdaptedString adapt(const char (&p)[N]) {

src/ArduinoJson/Strings/StringAdapter.hpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,35 @@
44

55
#pragma once
66

7+
#include <ArduinoJson/Polyfills/utility.hpp>
8+
79
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
810

11+
// a meta function that tells if the type is a string literal (const char[N])
12+
template <typename T>
13+
struct IsStringLiteral : false_type {};
14+
15+
template <size_t N>
16+
struct IsStringLiteral<const char (&)[N]> : true_type {};
17+
918
template <typename TString, typename Enable = void>
1019
struct StringAdapter;
1120

1221
template <typename TString, typename Enable = void>
1322
struct SizedStringAdapter;
1423

1524
template <typename TString>
16-
typename StringAdapter<TString>::AdaptedString adaptString(const TString& s) {
17-
return StringAdapter<TString>::adapt(s);
25+
using AdapterParam = conditional_t<IsStringLiteral<TString>::value, TString,
26+
remove_cv_t<remove_reference_t<TString>>>;
27+
28+
template <typename TString>
29+
typename StringAdapter<AdapterParam<TString>>::AdaptedString adaptString(
30+
TString&& s) {
31+
return StringAdapter<AdapterParam<TString>>::adapt(
32+
detail::forward<TString>(s));
1833
}
1934

20-
template <typename TChar>
35+
template <typename TChar, typename = enable_if_t<!is_const<TChar>::value>>
2136
typename StringAdapter<TChar*>::AdaptedString adaptString(TChar* p) {
2237
return StringAdapter<TChar*>::adapt(p);
2338
}

src/ArduinoJson/Variant/ConverterImpl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct Converter {
3131
// clang-format on
3232
}
3333

34-
static T fromJson(JsonVariantConst src) {
34+
static detail::decay_t<T> fromJson(JsonVariantConst src) {
3535
static_assert(!detail::is_same<T, char*>::value,
3636
"type 'char*' is not supported, use 'const char*' instead");
3737

src/ArduinoJson/Variant/VariantRefBase.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,16 @@ class VariantRefBase : public VariantTag {
7676
// Copies the specified value.
7777
// https://arduinojson.org/v7/api/jsonvariant/set/
7878
template <typename T>
79-
bool set(const T& value) const {
80-
return doSet<Converter<remove_cv_t<T>>>(value);
79+
bool set(T&& value) const {
80+
using TypeForConverter = conditional_t<IsStringLiteral<T>::value, T,
81+
remove_cv_t<remove_reference_t<T>>>;
82+
return doSet<Converter<TypeForConverter>>(value);
8183
}
8284

8385
// Copies the specified value.
8486
// https://arduinojson.org/v7/api/jsonvariant/set/
85-
template <typename T>
87+
template <typename T,
88+
typename = detail::enable_if_t<!detail::is_const<T>::value>>
8689
bool set(T* value) const {
8790
return doSet<Converter<T*>>(value);
8891
}

0 commit comments

Comments
 (0)