JSONGenerator/Loader cleanups#5146
Conversation
1fe7fb4 to
e826ce2
Compare
c1f2e34 to
6adbb44
Compare
6adbb44 to
724bf9d
Compare
Signed-off-by: Chris Dodd <cdodd@nvidia.com>
724bf9d to
6207bfc
Compare
6207bfc to
8000578
Compare
- use unqiue_ptr to manage memory so as to not excercise the garbage collector as much Signed-off-by: Chris Dodd <cdodd@nvidia.com>
8000578 to
66c82fb
Compare
- fix escaping/reading of special characters in json strings Signed-off-by: Chris Dodd <cdodd@nvidia.com>
Signed-off-by: Chris Dodd <cdodd@nvidia.com>
66c82fb to
238d23c
Compare
| json << json.indent << "\"assertions\" : " << p4Assertions; | ||
| json.indent--; | ||
| json << json.indent << "}\n"; | ||
| auto state = json.begin_object(); |
There was a problem hiding this comment.
Just loudly thinking: (not for this PR) we might do some scope-level RAII objects that would do end_object automagically. Or make begin_object to accept a lambda. So, end_object would be called automatically. I would probably prefer RAII as it might have nesting neater.
There was a problem hiding this comment.
The point of RAII is to recover from exceptions cleanly. However, an exception when generating json would likely mean the entire json was invalid, so there's not much point in trying to fix up the superficial syntax, so there's not really anything useful for the RAII to recover/clean up.
We could add it (or a lambda) as an alternate syntax, however.
There was a problem hiding this comment.
Well, why cannot state call end_object in its destructor? We'd end with something like this:
{
auto objectScope = json.begin_object_scope();
object.emit("checkpoints", checkpoints);
...
object.emit("assertions", p4Assertions);
}Here objectScope would hold reference to json, so it could close the scope properly on destruction.
or, alternatively, with function object:
{
json.object([](auto &state) {
state.emit("checkpoints", checkpoints);
...
state.emit("assertions", p4Assertions);
});
}
Note sure which variant I like better.There was a problem hiding this comment.
Ok, I made the 'state' value returned by begin_object/_vector automatically call end_object/_vector as appropriate when it goes out of scope, if it hasn't been called yet. So now you can have an explicit end call, or you can just leave it off.
Since all these functions are inline in JSONGenerator.h, the overhead should be minimal -- it should be able to optimize away the redundant state changes and checks, and the result should be just a series of ostream outputs.
| } | ||
| out << "]"; | ||
| auto t = begin_vector(); | ||
| for (auto &el : v) emit(el); |
There was a problem hiding this comment.
maybe we can have emit_as_vector that would iterate over container?
There was a problem hiding this comment.
That's basically what this is. Perhaps make a templated generate method that can take any iterable type (any type that has iterator, begin(), and end() -- C++20 concepts would be helpful here). But there would be some ambiguity whether a type should be a vector or an object.
asl
left a comment
There was a problem hiding this comment.
Thanks! Made few small comments about possible future improvements.
Signed-off-by: Chris Dodd <cdodd@nvidia.com>
- the state object will automatically call end_object or end_vector as need when it goes out of scope. Signed-off-by: Chris Dodd <cdodd@nvidia.com>
In trying to use the JSONGenerator/Loader code for additional things, I found a number of ways in which they are tricky to use and easy to use incorrectly (as well as some ways they are used incorrectly), mostly due to having exposed internals. So I made all those internals
privateand provided a cleaner interface to be usedemitmethods to output values (rather than allowing<< arbitrary textwhich was erro prone), and ensures that objects only contain key-value pairs and vector only contain values (no keys) and things match up properly.istester methods for checking that values are the expected type, and manages its internal memory withunique_ptrso as to not require the garbage collector.