Comments (5)
Hi and thanks.
Yes, I like the idea. I've actually been thinking about it myself, too, in the context of #37.
I'm only concerned about the declaration of k
, v
and __json_iterator__
. If you do it like this, the declarations are not in the beginning of a block, which breaks strict C89 compatibility. You could also let the user declare them, but it makes using the macro a bit inconvenient, especially in the case of the iterator void pointer, as he doesn't even use it.
So, do you have any ideas on how to circumvent these problems?
from jansson.
Hmm, I see a few different ways of working around this.
A) First, you could keep the macro the way it is, and instruct C89 users to add an extra block around the foreach construct.
{json_object_foreach(key, value, object)
{
/* use key and value ... */
}}
But that's kind of ugly, and I'm not completely sure if C89 would accept a block like this. (But I think it should).
B) Another option is to only provide the json_object_foreach
macro to translation units in C99 mode or newer, checking for the __STDC_VERSION__
macro.
#if __STDC_VERSION__ >= 199901L
/* define json_object_foreach here */
#endif
That would sure limit the expressivity for people that need to remain using C89 on their code, but they're already quite limited (since they cannot declare variables inside for
loops, for instance). Furthermore, they can still do things manually, so it wouldn't make using the library any harder for them. It would only not make it easier.
C) Yet another solution would be to provide another macro, say json_object_foreach_declare
that would declare the variables needed for the loop (k
, v
and the "hidden" __json_iterator__
), and remove the declarations from json_object_foreach
. Their code would end up looking like:
void my_function(json_t *object)
{
json_object_foreach_declare(key, value);
/* code */
json_object_foreach(key, value, object) {
/* code */
}
}
Which isn't the ideal in terms of brevity, but is much better than doing things manually.
To allow the C99 (and C11) folks to use json_object_foreach
without json_object_foreach_declare
, we can check for the version when defining the macro.
#if __STDC_VERSION__ >= 199901L
/* define json_object_foreach with k, v, and __json_iterator__ declarations */
#else
/* define json_object_foreach without any declarations */
#endif
And to allow the code containing json_object_foreach_declare
to still be valid in C99, we can check for the version, too:
#if __STDC_VERSION__ >= 199901L
/* define json_object_foreach_declare as ((void) 0) */
#else
/* define json_object_foreach_declare normally */
#endif
I think this is the best solution, since it allows:
- C99 people to use foreach without having any previous declarations.
- C89 people to use foreach, after using a special declaration macro.
- C99 people to use the code written by the C89 people without any changes.
We still need to deal with multiple uses of json_object_foreach_declare
on the same scope, but that can be done using the token pasting operator (##
) from the C preprocessor.
I also think we need a better name than json_object_foreach_declare
.
from jansson.
Option C sounds best to me, too. However, I don't see how ##
could be used to deal with multiple uses json_object_foreach_declare
. It also seems to me that there's no way to allow using nested json_object_foreach
constructs for C89 folks.
from jansson.
Hmm... The code ends up looking a bit messy, but the idea is simple: We concatenate the k
and v
tokens with __json_iterator_
, _
and __
to form a unique token.: __json_iterator_ ## k ## _ ## v ## __
=> __json_iterator_k_v__
.
Since k
and v
are going to change with each use of json_object_foreach_declare
, the iterator token generated will also change. When we expand the json_object_foreach
macro we can get the correct iterator, since we are given both k
and v
.
#define json_object_foreach_declare(k, v) const char *k; json_t *v; void * __json_iterator_ ## k ## _ ## v ## __
#define json_object_foreach(k, v, x) for (__json_iterator_ ## k ## _ ## v ## __ = json_object_iter(x); \
__json_iterator_ ## k ## _ ## v ## __ && \
(k = json_object_iter_key(__json_iterator_ ## k ## _ ## v ## __), v = json_object_iter_value(__json_iterator_ ## k ## _ ## v ## __), 1); \
__json_iterator_ ## k ## _ ## v ## __ = json_object_iter_next(x, __json_iterator_ ## k ## _ ## v ## __))
This also allows for nested json_object_foreach
, without problems:
json_object_foreach_declare(companyName, company);
json_object_foreach_declare(employeeName, employee);
json_object_foreach(companyName, company, town) {
json_object_foreach(employeeName, employee, company) {
/* do something with employee */
}
}
Expanding to:
const char *companyName; json_t *company; void * __json_iterator_companyName_company__;
const char *employeeName; json_t *employee; void * __json_iterator_employeeName_employee__;
for (__json_iterator_companyName_company__ = json_object_iter(town);
__json_iterator_companyName_company__ &&
(companyName = json_object_iter_key(__json_iterator_companyName_company__), company = json_object_iter_value(__json_iterator_companyName_company__), 1); \
__json_iterator_companyName_company__ = json_object_iter_next(town, __json_iterator_companyName_company__)) {
for (__json_iterator_employeeName_employee__ = json_object_iter(company);
__json_iterator_employeeName_employee__ &&
(employeeName = json_object_iter_key(__json_iterator_employeeName_employee__), employee = json_object_iter_value(__json_iterator_employeeName_employee__), 1); \
__json_iterator_employeeName_employee__ = json_object_iter_next(company, __json_iterator_employeeName_employee__)) {
/* do something with employee */
}
}
Which is quite unreadable because of the variable names, but should work just fine:
const char *a; json_t *b; void *c;
const char *d; json_t *e; void *f;
for (c = json_object_iter(x); c && (a = json_object_iter_key(c), b = json_object_iter_value(c), 1); c = json_object_iter_next(x, c)) {
for (f = json_object_iter(b); f && (d = json_object_iter_key(f), e = json_object_iter_value(f), 1); f = json_object_iter_next(b, f)) {
/* do something with e */
}
}
from jansson.
Wow, that's clever. Feel free to submit a patch.
from jansson.
Related Issues (20)
- Can't create DLL on Windows for Jansson 1.2
- Cannot compile Jansson (make check fail) HOT 1
- "jansson_config.h" missing and cannot include the library in cmakelist HOT 2
- Create SECURITY.md HOT 1
- Error OOM HOT 2
- dump_string func can error return HOT 1
- json_int_t should be typedef'd as intmax_t
- Replacing values in a arbitrary JSON file HOT 1
- Target settings do not automatically populate when using CMake FetchContent HOT 1
- janssonConfig.cmake only packaged on Fedora and OpenMandriva HOT 2
- [question] multiple usage of json_set_alloc_funcs HOT 1
- Keep GitHub Actions up-to-date with dependabot
- json_dumps real value 7.6 as 7.59....96 HOT 9
- conversion from JSON to string is not multithread-safe HOT 3
- conversion from string to JSON is not multithread-safe HOT 5
- json_unpack bug (jansson 2.13.1)
- func name conflict crash HOT 2
- Parsing of \u0000 HOT 1
- Multiple hashtable symbols HOT 2
- The #define for JSON flags should be unsigned constants.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jansson.