Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Request] Macro generating from_json() and to_json() #895

Closed
unrealmistake opened this issue Dec 27, 2017 · 3 comments
Closed

[Request] Macro generating from_json() and to_json() #895

unrealmistake opened this issue Dec 27, 2017 · 3 comments
Labels
state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated

Comments

@unrealmistake
Copy link

unrealmistake commented Dec 27, 2017

Making to_json() and from_json() for all classes in my object model is a chore.
I want to create a macro that would generate bodies for these functions. I saw some clues how to make it, but my knowledge of C++ is not good enough to implement it.
I want to be able to write something like this:

class MyClass
{
...
    JsonVar(int, intvar)
    JsonVar(string, stingvar)
...
}
void to_json(json& j, const MyClass& p) {
JsonTo(MyClass)
... //some extra serialization
}
void from_json(const json& j, MyClass& p) {
JsonFrom(MyClass)
... //some extra deserialization
}

and get

class MyClass
{
...
    int intvar;
    string stringvar;
...
}
void to_json(json& j, const MyClass& p) {
j = json{ { "intvar", p.intvar},
			{ "stringvar", p.stringvar} };
... //some extra serialization
}
void from_json(const json& j, MyClass& p) {
p.intvar= j.at("intvar").get<int>();
p.stringvar= j.at("stringvar").get<string>();
... //some extra deserialization
}
@nlohmann
Copy link
Owner

I also have little experience in this. You may want to have a look at cereal (http://uscilab.github.io/cereal/index.html) which employs some nice macro magic.

@unrealmistake
Copy link
Author

unrealmistake commented Dec 28, 2017

Well, looks like I found a solution. It was inspired by a topic on StackOverflow
Macros in boost are no magic at all, they are just a bunch of overrides for each parameter count. So boost dependency can be avoided by using the same technique.
Use of variadic macros is sugar. It only helps omitting parameter number.
Also, this code probably will not work with mingw. To add mingw support, you need to change all occurrences of MACRO arg to MACRO ## arg. I didn't test it on mingw though, that's just a guess from studying the code of boost.
And I didn't expect that extracting a name of variable is so... fun. Took me some time to find that I just need to be more insistent.
Here is my code for 1 and 2 arguments:

#define REM(x) x
#define EAT(x)
#define MAKEQUOTES(x) #x
#define PLEASEMAKEQUOTES(x) MAKEQUOTES x
#define PRETTYPLEASEMAKEQUOTES(x) PLEASEMAKEQUOTES((x))

// Strip off the type
#define STRIP(x) EAT x
// Get the name of variable
#define NAMEOF(x) PRETTYPLEASEMAKEQUOTES(STRIP(x))
// Show the type without parenthesis
#define PAIR(x) REM x

#define JSONVARS1(a1) \
PAIR(a1);\
void _member_to_json(json& j) const { \
j = json{{ NAMEOF(a1), STRIP(a1) } \
		};\
} \
void _member_from_json(const json& j){ \
STRIP(a1) = j.at(NAMEOF(a1)).get<decltype(STRIP(a1))>();\
}

#define JSONVARS2(a1, a2) \
PAIR(a1);\
PAIR(a2);\
void _member_to_json(json& j) const { \
j = json{{ NAMEOF(a1), STRIP(a1) }, \
		{ NAMEOF(a2), STRIP(a2) } \
		};\
} \
void _member_from_json(const json& j){ \
STRIP(a1) = j.at(NAMEOF(a1)).get<decltype(STRIP(a1))>();\
STRIP(a2) = j.at(NAMEOF(a2)).get<decltype(STRIP(a2))>();\
}

#define TO_JSON(MyClass) inline void to_json(json& j, const MyClass& p) {\
p._member_to_json(j);

#define FROM_JSON(MyClass) inline void from_json(const json& j, MyClass& p) {\
p._member_from_json(j);

//to match the style
#define END }

Usage:

class MyClass
{
...
    JSONVARS2((int) intvar,
    (string) stingvar)
...
}
TO_JSON(MyClass)
... //some extra deserialization
END
FROM_JSON(MyClass)
... //some extra deserialization
END

Feel free to use it.

@stale
Copy link

stale bot commented Jan 27, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated label Jan 27, 2018
@stale stale bot closed this as completed Feb 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state: stale the issue has not been updated in a while and will be closed automatically soon unless it is updated
Projects
None yet
Development

No branches or pull requests

2 participants