commonmark / commonmark-spec

CommonMark spec, with reference implementations in C and JavaScript
http://commonmark.org
Other
4.85k stars 313 forks source link

Add a "private" field to struct cmark_node #287

Closed nwellnhof closed 9 years ago

nwellnhof commented 9 years ago

For bindings from other languages to libcmark, it would be useful to add a "private" field to struct cmark_node that makes it possible to store a pointer to (or other identifier of) the object that represents the node in the other language. Something like:

typedef union {
    void *ptr;
    size_t id;
} cmark_private_data;

cmark_private_data
cmark_node_get_private_data(cmark_node *node);

int
cmark_node_set_private_data(cmark_node *node, cmark_private_data priv_data);
jgm commented 9 years ago

Can you say a bit about why this would be useful/how it would be used?

nwellnhof commented 9 years ago

The biggest problem for language bindings is memory management of the node tree. The tree must only be freed if there are no more references to any of its nodes. The problematic case is when there are no more references to the root node but still some references to child nodes. So every node must somehow keep a reference to the object representing the root node or its parent node.

If a pointer to the target language object is stored in the private field, this object can be easily looked up given a only cmark_node. Because the target language only has to store pointers to cmark_nodes, this can simplify things especially for languages where its hard to store additional data (for example in a Perl SV, or a Ruby RData). It also results in a 1:1 mapping between cmark_nodes and the target language objects which is more memory-efficient.

A private field can also be useful for C users to store arbitrary stuff associated with a node.

Thinking more about it, I don't think using a union with an additional integer type is that useful. So I change my initial proposal to something like:

void*
cmark_node_get_private_data(cmark_node *node);

int
cmark_node_set_private_data(cmark_node *node, void *priv_data);
jgm commented 9 years ago

Thanks for the explanation. I have no objections to adding such a field, if you want to submit a PR!

+++ Nick Wellnhofer [Jan 19 15 05:20 ]:

The biggest problem for language bindings is memory management of the node tree. The tree must only be freed if there are no more references to any of its nodes. The problematic case is when there are no more references to the root node but still some references to child nodes. So every node must somehow keep a reference to the object representing the root node or its parent node.

If a pointer to the target language object is stored in the private field, this object can be easily looked up given a only cmark_node. Because the target language only has to store pointers to cmark_nodes, this can simplify things especially for languages where its hard to store additional data (for example in a Perl SV, or a Ruby RData). It also results in a 1:1 mapping between cmark_nodes and the target language objects which is more memory-efficient.

A private field can also be useful for C users to store arbitrary stuff associated with a node.

Thinking more about it, I don't think using a union with an additional integer type is that useful. So I change my initial proposal to something like: void cmark_node_get_private_data(cmark_node node);

int cmark_node_set_private_data(cmark_node node, void priv_data);

— Reply to this email directly or [1]view it on GitHub.

References

  1. https://github.com/jgm/CommonMark/issues/287#issuecomment-70490911