Skip to content

Commit dd0625f

Browse files
committed
Add support of multi-dim C-style array member of struct.
* Support up to 4 dimensional array. * Modify pretty-print logic to print multi-dim array's inner most dimension in the same line for better readability.
1 parent a259ecc commit dd0625f

File tree

5 files changed

+183
-12
lines changed

5 files changed

+183
-12
lines changed

include/nlohmann/detail/conversions/from_json.hpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,54 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
190190
}
191191
}
192192

193+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2>
194+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
195+
-> decltype(j.template get<T>(), void())
196+
{
197+
for (std::size_t i1 = 0; i1 < N1; ++i1)
198+
{
199+
for (std::size_t i2 = 0; i2 < N2; ++i2)
200+
{
201+
arr[i1][i2] = j.at(i1).at(i2).template get<T>();
202+
}
203+
}
204+
}
205+
206+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3>
207+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
208+
-> decltype(j.template get<T>(), void())
209+
{
210+
for (std::size_t i1 = 0; i1 < N1; ++i1)
211+
{
212+
for (std::size_t i2 = 0; i2 < N2; ++i2)
213+
{
214+
for (std::size_t i3 = 0; i3 < N3; ++i3)
215+
{
216+
arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get<T>();
217+
}
218+
}
219+
}
220+
}
221+
222+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3, std::size_t N4>
223+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
224+
-> decltype(j.template get<T>(), void())
225+
{
226+
for (std::size_t i1 = 0; i1 < N1; ++i1)
227+
{
228+
for (std::size_t i2 = 0; i2 < N2; ++i2)
229+
{
230+
for (std::size_t i3 = 0; i3 < N3; ++i3)
231+
{
232+
for (std::size_t i4 = 0; i4 < N4; ++i4)
233+
{
234+
arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get<T>();
235+
}
236+
}
237+
}
238+
}
239+
}
240+
193241
template<typename BasicJsonType>
194242
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
195243
{

include/nlohmann/detail/output/serializer.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,10 @@ class serializer
193193
return;
194194
}
195195

196-
if (pretty_print)
196+
// For multi-dim number arrays, print the inner most dimension in one line to improve readability.
197+
value_t elem_type = val.m_data.m_value.array->cbegin()->m_data.m_type;
198+
bool elem_is_number = value_t::number_float == elem_type || value_t::number_integer == elem_type || value_t::number_unsigned == elem_type;
199+
if (pretty_print && (!elem_is_number || value_t::array == elem_type))
197200
{
198201
o->write_characters("[\n", 2);
199202

single_include/nlohmann/json.hpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4817,6 +4817,54 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
48174817
}
48184818
}
48194819

4820+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2>
4821+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4822+
-> decltype(j.template get<T>(), void())
4823+
{
4824+
for (std::size_t i1 = 0; i1 < N1; ++i1)
4825+
{
4826+
for (std::size_t i2 = 0; i2 < N2; ++i2)
4827+
{
4828+
arr[i1][i2] = j.at(i1).at(i2).template get<T>();
4829+
}
4830+
}
4831+
}
4832+
4833+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3>
4834+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4835+
-> decltype(j.template get<T>(), void())
4836+
{
4837+
for (std::size_t i1 = 0; i1 < N1; ++i1)
4838+
{
4839+
for (std::size_t i2 = 0; i2 < N2; ++i2)
4840+
{
4841+
for (std::size_t i3 = 0; i3 < N3; ++i3)
4842+
{
4843+
arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get<T>();
4844+
}
4845+
}
4846+
}
4847+
}
4848+
4849+
template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3, std::size_t N4>
4850+
auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4851+
-> decltype(j.template get<T>(), void())
4852+
{
4853+
for (std::size_t i1 = 0; i1 < N1; ++i1)
4854+
{
4855+
for (std::size_t i2 = 0; i2 < N2; ++i2)
4856+
{
4857+
for (std::size_t i3 = 0; i3 < N3; ++i3)
4858+
{
4859+
for (std::size_t i4 = 0; i4 < N4; ++i4)
4860+
{
4861+
arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get<T>();
4862+
}
4863+
}
4864+
}
4865+
}
4866+
}
4867+
48204868
template<typename BasicJsonType>
48214869
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
48224870
{
@@ -18202,7 +18250,10 @@ class serializer
1820218250
return;
1820318251
}
1820418252

18205-
if (pretty_print)
18253+
// For multi-dim number arrays, print the inner most dimension in one line to improve readability.
18254+
value_t elem_type = val.m_data.m_value.array->cbegin()->m_data.m_type;
18255+
bool elem_is_number = value_t::number_float == elem_type || value_t::number_integer == elem_type || value_t::number_unsigned == elem_type;
18256+
if (pretty_print && (!elem_is_number || value_t::array == elem_type))
1820618257
{
1820718258
o->write_characters("[\n", 2);
1820818259

tests/src/unit-conversions.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,64 @@ TEST_CASE("value conversion")
344344
CHECK(std::equal(std::begin(nbs), std::end(nbs), std::begin(nbs2)));
345345
}
346346

347+
SECTION("built-in arrays: 2D")
348+
{
349+
const int nbs[][3] = {{0, 1, 2}, {3, 4, 5}}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
350+
int nbs2[][3] = {{0, 0, 0}, {0, 0, 0}}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
351+
352+
const json j2 = nbs;
353+
j2.get_to(nbs2);
354+
CHECK(std::equal(std::begin(nbs[0]), std::end(nbs[1]), std::begin(nbs2[0])));
355+
}
356+
357+
SECTION("built-in arrays: 3D")
358+
{
359+
const int nbs[][2][3] = {\
360+
{{0, 1, 2}, {3, 4, 5}}, \
361+
{{10, 11, 12}, {13, 14, 15}}\
362+
}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
363+
int nbs2[][2][3] = {\
364+
{{0, 0, 0}, {0, 0, 0}}, \
365+
{{0, 0, 0}, {0, 0, 0}}\
366+
}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
367+
368+
const json j2 = nbs;
369+
j2.get_to(nbs2);
370+
CHECK(std::equal(std::begin(nbs[0][0]), std::end(nbs[1][1]), std::begin(nbs2[0][0])));
371+
}
372+
373+
SECTION("built-in arrays: 4D")
374+
{
375+
const int nbs[][2][2][3] = {\
376+
{
377+
\
378+
{{0, 1, 2}, {3, 4, 5}}, \
379+
{{10, 11, 12}, {13, 14, 15}}\
380+
}, \
381+
{
382+
\
383+
{{20, 21, 22}, {23, 24, 25}}, \
384+
{{30, 31, 32}, {33, 34, 35}}\
385+
}\
386+
}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
387+
int nbs2[][2][2][3] = {\
388+
{
389+
\
390+
{{0, 0, 0}, {0, 0, 0}}, \
391+
{{0, 0, 0}, {0, 0, 0}}\
392+
}, \
393+
{
394+
\
395+
{{0, 0, 0}, {0, 0, 0}}, \
396+
{{0, 0, 0}, {0, 0, 0}}\
397+
}\
398+
}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
399+
400+
const json j2 = nbs;
401+
j2.get_to(nbs2);
402+
CHECK(std::equal(std::begin(nbs[0][0][0]), std::end(nbs[1][1][1]), std::begin(nbs2[0][0][0])));
403+
}
404+
347405
SECTION("std::deque<json>")
348406
{
349407
std::deque<json> a{"previous", "value"};

tests/src/unit-inspection.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -202,44 +202,55 @@ TEST_CASE("object inspection")
202202

203203
SECTION("serialization")
204204
{
205-
json const j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
205+
json const j
206+
{
207+
{"object", json::object()},
208+
{"array", {1, 2, 3, 4}},
209+
{"array2d", {{1, 2, 3}, {4, 5, 6}}},
210+
{"array3d", {{{1, 2, 3}, {4, 5, 6}}, {{2, 3, 4}, {5, 6, 7}}}},
211+
{"array4d", {{{{1, 2, 3}, {4, 5, 6}}, {{2, 3, 4}, {5, 6, 7}}}, {{{11, 12, 13}, {14, 15, 16}}, {{12, 13, 14}, {15, 16, 17}}}}},
212+
{"number", 42},
213+
{"boolean", false},
214+
{"null", nullptr},
215+
{"string", "Hello world"}
216+
};
206217

207218
SECTION("no indent / indent=-1")
208219
{
209220
CHECK(j.dump() ==
210-
"{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
221+
"{\"array\":[1,2,3,4],\"array2d\":[[1,2,3],[4,5,6]],\"array3d\":[[[1,2,3],[4,5,6]],[[2,3,4],[5,6,7]]],\"array4d\":[[[[1,2,3],[4,5,6]],[[2,3,4],[5,6,7]]],[[[11,12,13],[14,15,16]],[[12,13,14],[15,16,17]]]],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
211222

212223
CHECK(j.dump() == j.dump(-1));
213224
}
214225

215226
SECTION("indent=0")
216227
{
217228
CHECK(j.dump(0) ==
218-
"{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
229+
"{\n\"array\": [1,2,3,4],\n\"array2d\": [\n[1,2,3],\n[4,5,6]\n],\n\"array3d\": [\n[\n[1,2,3],\n[4,5,6]\n],\n[\n[2,3,4],\n[5,6,7]\n]\n],\n\"array4d\": [\n[\n[\n[1,2,3],\n[4,5,6]\n],\n[\n[2,3,4],\n[5,6,7]\n]\n],\n[\n[\n[11,12,13],\n[14,15,16]\n],\n[\n[12,13,14],\n[15,16,17]\n]\n]\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
219230
}
220231

221232
SECTION("indent=1, space='\t'")
222233
{
223234
CHECK(j.dump(1, '\t') ==
224-
"{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"string\": \"Hello world\"\n}");
235+
"{\n\t\"array\": [1,2,3,4],\n\t\"array2d\": [\n\t\t[1,2,3],\n\t\t[4,5,6]\n\t],\n\t\"array3d\": [\n\t\t[\n\t\t\t[1,2,3],\n\t\t\t[4,5,6]\n\t\t],\n\t\t[\n\t\t\t[2,3,4],\n\t\t\t[5,6,7]\n\t\t]\n\t],\n\t\"array4d\": [\n\t\t[\n\t\t\t[\n\t\t\t\t[1,2,3],\n\t\t\t\t[4,5,6]\n\t\t\t],\n\t\t\t[\n\t\t\t\t[2,3,4],\n\t\t\t\t[5,6,7]\n\t\t\t]\n\t\t],\n\t\t[\n\t\t\t[\n\t\t\t\t[11,12,13],\n\t\t\t\t[14,15,16]\n\t\t\t],\n\t\t\t[\n\t\t\t\t[12,13,14],\n\t\t\t\t[15,16,17]\n\t\t\t]\n\t\t]\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"string\": \"Hello world\"\n}");
225236
}
226237

227238
SECTION("indent=4")
228239
{
229240
CHECK(j.dump(4) ==
230-
"{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}");
241+
"{\n \"array\": [1,2,3,4],\n \"array2d\": [\n [1,2,3],\n [4,5,6]\n ],\n \"array3d\": [\n [\n [1,2,3],\n [4,5,6]\n ],\n [\n [2,3,4],\n [5,6,7]\n ]\n ],\n \"array4d\": [\n [\n [\n [1,2,3],\n [4,5,6]\n ],\n [\n [2,3,4],\n [5,6,7]\n ]\n ],\n [\n [\n [11,12,13],\n [14,15,16]\n ],\n [\n [12,13,14],\n [15,16,17]\n ]\n ]\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}");
231242
}
232243

233244
SECTION("indent=x")
234245
{
235-
CHECK(j.dump().size() == 94);
236-
CHECK(j.dump(1).size() == 127);
237-
CHECK(j.dump(2).size() == 142);
238-
CHECK(j.dump(512).size() == 7792);
246+
CHECK(j.dump().size() == 270);
247+
CHECK(j.dump(1).size() == 422);
248+
CHECK(j.dump(2).size() == 522);
249+
CHECK(j.dump(512).size() == 51522);
239250

240251
// important test, because it yields a resize of the indent_string
241252
// inside the dump() function
242-
CHECK(j.dump(1024).size() == 15472);
253+
CHECK(j.dump(1024).size() == 102722);
243254

244255
const auto binary = json::binary({1, 2, 3}, 128);
245256
CHECK(binary.dump(1024).size() == 2086);

0 commit comments

Comments
 (0)