summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Wellnhofer <wellnhofer@aevum.de>2015-01-10 16:10:35 +0100
committerNick Wellnhofer <wellnhofer@aevum.de>2015-01-10 17:40:13 +0100
commit009c3847f004fda437dd5376a9452973b1cb913e (patch)
treef1e51be8affaa4c46231fd10590acc674b21bf16 /src
parentd548d56d604193e4eebb4ab81c347887763b7d69 (diff)
Rework iterators
* Advance to the next node when calling 'cmark_iter_next', not when calling 'cmark_iter_get_node'. * Add 'cmark_iter_get_event_type' accessor. * Allow deletion of nodes after an 'EXIT' event, or an 'ENTER' event for leaf nodes.
Diffstat (limited to 'src')
-rw-r--r--src/cmark.h7
-rw-r--r--src/iterator.c98
-rw-r--r--src/iterator.h10
3 files changed, 71 insertions, 44 deletions
diff --git a/src/cmark.h b/src/cmark.h
index 72650c9..b153124 100644
--- a/src/cmark.h
+++ b/src/cmark.h
@@ -83,6 +83,7 @@ typedef struct cmark_parser cmark_parser;
typedef struct cmark_iter cmark_iter;
typedef enum {
+ CMARK_EVENT_NONE,
CMARK_EVENT_DONE,
CMARK_EVENT_ENTER,
CMARK_EVENT_EXIT
@@ -204,6 +205,12 @@ CMARK_EXPORT
cmark_node*
cmark_iter_get_node(cmark_iter *iter);
+/** Returns the current event type.
+ */
+CMARK_EXPORT
+cmark_event_type
+cmark_iter_get_event_type(cmark_iter *iter);
+
/**
* ## Accessors
*/
diff --git a/src/iterator.c b/src/iterator.c
index 0354eff..7f90cc7 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <stdlib.h>
#include "config.h"
@@ -18,15 +19,19 @@ static const int S_leaf_mask =
cmark_iter*
cmark_iter_new(cmark_node *root)
{
+ if (root == NULL) {
+ return NULL;
+ }
cmark_iter *iter = (cmark_iter*)malloc(sizeof(cmark_iter));
if (iter == NULL) {
return NULL;
- } else {
- iter->root = root;
- iter->current = root;
- iter->event_type = CMARK_EVENT_ENTER;
- return iter;
}
+ iter->root = root;
+ iter->cur.ev_type = CMARK_EVENT_NONE;
+ iter->cur.node = NULL;
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = root;
+ return iter;
}
void
@@ -35,61 +40,72 @@ cmark_iter_free(cmark_iter *iter)
free(iter);
}
-cmark_event_type
-cmark_iter_next(cmark_iter *iter)
-{
- return iter->event_type;
-}
-
static bool
S_is_leaf(cmark_node *node)
{
return (1 << node->type) & S_leaf_mask;
}
-void
-cmark_iter_reset(cmark_iter *iter, cmark_node *current,
- cmark_event_type event_type)
+cmark_event_type
+cmark_iter_next(cmark_iter *iter)
{
- iter->event_type = event_type;
- iter->current = current;
-}
+ cmark_event_type ev_type = iter->next.ev_type;
+ cmark_node *node = iter->next.node;
-cmark_node*
-cmark_iter_get_node(cmark_iter *iter)
-{
- /* we'll return current */
- cmark_node *cur = iter->current;
+ iter->cur.ev_type = ev_type;
+ iter->cur.node = node;
- if (cur == NULL || iter->event_type == CMARK_EVENT_DONE) {
- return NULL;
+ if (ev_type == CMARK_EVENT_DONE) {
+ return ev_type;
}
/* roll forward to next item, setting both fields */
- if (iter->event_type == CMARK_EVENT_ENTER && !S_is_leaf(cur)) {
- if (cur->first_child == NULL) {
+ if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
+ if (node->first_child == NULL) {
/* stay on this node but exit */
- iter->event_type = CMARK_EVENT_EXIT;
+ iter->next.ev_type = CMARK_EVENT_EXIT;
} else {
- iter->current = cur->first_child;
- iter->event_type = CMARK_EVENT_ENTER;
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = node->first_child;
}
- } else if (cur == iter->root) {
+ } else if (node == iter->root) {
/* don't move past root */
- iter->event_type = CMARK_EVENT_DONE;
- iter->current = NULL;
- } else if (cur->next) {
- iter->event_type = CMARK_EVENT_ENTER;
- iter->current = cur->next;
- } else if (cur->parent) {
- iter->event_type = CMARK_EVENT_EXIT;
- iter->current = cur->parent;
+ iter->next.ev_type = CMARK_EVENT_DONE;
+ iter->next.node = NULL;
+ } else if (node->next) {
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = node->next;
+ } else if (node->parent) {
+ iter->next.ev_type = CMARK_EVENT_EXIT;
+ iter->next.node = node->parent;
} else {
- iter->event_type = CMARK_EVENT_DONE;
- iter->current = NULL;
+ assert(false);
+ iter->next.ev_type = CMARK_EVENT_DONE;
+ iter->next.node = NULL;
}
- return cur;
+ return ev_type;
+}
+
+void
+cmark_iter_reset(cmark_iter *iter, cmark_node *current,
+ cmark_event_type event_type)
+{
+ iter->next.ev_type = event_type;
+ iter->next.node = current;
+ cmark_iter_next(iter);
+}
+
+cmark_node*
+cmark_iter_get_node(cmark_iter *iter)
+{
+ return iter->cur.node;
+}
+
+cmark_event_type
+cmark_iter_get_event_type(cmark_iter *iter)
+{
+ return iter->cur.ev_type;
}
diff --git a/src/iterator.h b/src/iterator.h
index bf53112..027b10b 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -6,12 +6,16 @@ extern "C" {
#endif
#include "cmark.h"
-#include "node.h"
+
+typedef struct {
+ cmark_event_type ev_type;
+ cmark_node *node;
+} cmark_iter_state;
struct cmark_iter {
- cmark_node *current;
cmark_node *root;
- cmark_event_type event_type;
+ cmark_iter_state cur;
+ cmark_iter_state next;
};
#ifdef __cplusplus