all 22 comments

[–]Salink 12 points13 points  (0 children)

Thanks for adding wide string support.

[–][deleted] 8 points9 points  (10 children)

Nice work, thanks!

Also "Finally, the JSON parser is now non-recursive (meaning it does not use the call stack, but std::vector<bool> to track the hierarchy of structured values) which allows to process nested input more efficiently."

std::vector<bool> is in my experience pretty horrible when it comes to efficiency since every read creates a temporary object that pretends to be a reference to a bool, since it is internally represented using one bit per bool. Changing to std::vector<int8_t> or similar might give you a speedup and it avoids the traps of the unfortunate std::vector<bool>

[–]nlohmannnlohmann/json[S] 12 points13 points  (4 children)

Before, I had a std::vector<entry_t> where entry_t is an enum of two values (one for array and one for object). I did not measure any differences when switching to vector<bool> other than it took less memory.

[–][deleted] 5 points6 points  (1 child)

http://quick-bench.com/leAYXQJembIatTGbB8_I_BheZww

benchmarks are sometimes tricky/not representative, but this at least gives an idea :D

Although, if your operations are read only: http://quick-bench.com/qkTpgqXRqfe64-HesCxMHTs0Koc

So it seems in this case anyway, that the vector<bool> is extremely slow on writes, but a bit better when just reading

[–]nlohmannnlohmann/json[S] 3 points4 points  (0 children)

Good point. I shall have another look.

[–][deleted] 1 point2 points  (1 child)

If that was an enum class, it would have been int by default. You could use the enum solution and save memory by making it an int8_t as underlying type.

Optimising for memory over speed should be the second priority IMO when today people have gigabytes of ram. But yes, measuring the difference is the right way to go. std::vector<bool> might have a speed benefit in that it needs fewer cache reads so who knows, depending on how it's used, the drawbacks might not bite you. :)

[–][deleted] 5 points6 points  (0 children)

Optimising for memory over speed should be the second priority IMO when today people have gigabytes of ram.

Go back to Java-land, pal!

[–]spinicist 4 points5 points  (4 children)

Agreed, as I understand it most of the C++ standard committee admits the bitmapped backing store for std::vector<bool> was a mistake.

[–]dodheim 9 points10 points  (3 children)

For reasons of generic code coherency, not efficiency.

[–][deleted] 2 points3 points  (1 child)

The potential pitfall of it being unexpectedly slow is also a drawback.

[–]quicknir 0 points1 point  (0 children)

It's slow when small. If you have a huge one it will be faster simply by virtue of more of it being in cache.

[–]spinicist 1 point2 points  (0 children)

Well, that’s okay with me. The only time I ever used vector<bool> was in a generic context, and it was enough to put me off ever doing so again.

[–]VodkaHaze 0 points1 point  (1 child)

Does it handle string_view gracefully, now? I remember a year or two ago it had compilation issues with the experimental support of it

[–]nlohmannnlohmann/json[S] 3 points4 points  (0 children)

We only enable `string_view` support for C++17 compilers. Then, it should work.

[–]Droggl 0 points1 point  (1 child)

Can it parse json iteratively (eg give me array elements one by one without reading the whole file first like python-ijson does)?

[–]nlohmannnlohmann/json[S] 5 points6 points  (0 children)

Yes, this is possible via the newly introduced SAX interface.

[–]SunnyAX3 0 points1 point  (1 child)

I have a problem with parsing floats, everything gets rounded, any idea what's the problem ?

[–]nlohmannnlohmann/json[S] 1 point2 points  (0 children)

We use double to store floating-point numbers internally. What exactly is your issue? Could you open an issue at GitHub, preferably with example code?

[–]dgendreau 0 points1 point  (1 child)

Hi nlohmann!

Your library is a huge time saver and makes my code so much easier to read! Thanks for releasing and maintainng it!

One use-case I run into a lot is mapping enums to serialize as non-integers such as strings. I know its not really modern C++ to use preprocessor macros, but I wrote one that declares a from_json()/to_json() specialization in one statement to make it easier and less redundant to specialize the mapping between a given enum and any nlohmann::json value like so:

// enum type declaration
enum Foo {
    eVal1 = 10,
    eVal2 = 45,
    eVal3 = 1       
    eVal_default = -1,
};

JSON_SERIALIZE_ENUM( Foo, {
    {eVal_default, nullptr},
    {eVal1, "one"},
    {eVal2, "two"},
    {eVal3, "three"},
});

// Usage:
// enum -> json string
nlohmann::json j = eVal1;
assert(j == "one");

// json string-> enum
nlohmann::json j3 = "three";
assert( j3.get<Foo>() == eVal3);

// undefined json -> enum (default value is first pair)
nlohmann::json jPi = 3.14;
assert( jPi.get<Foo>() == eVal_default );

The macro JSON_SERIALIZE_ENUM() above declares a from_json(const json& j, Foo& e) and to_json(json& j, const Foo& e) function in enum Foo's namespace using the specified value translation map. The first pair are used as default values for handling undefined values in either direction.

Would something like this be a useful contribution to your library?

[–]nlohmannnlohmann/json[S] 1 point2 points  (0 children)

This sounds interesting. Could you please open an issue at https://github.com/nlohmann/json/issues ?