diff options
author | Nick Wellnhofer <wellnhofer@aevum.de> | 2015-01-10 16:10:35 +0100 |
---|---|---|
committer | Nick Wellnhofer <wellnhofer@aevum.de> | 2015-01-10 17:40:13 +0100 |
commit | 009c3847f004fda437dd5376a9452973b1cb913e (patch) | |
tree | f1e51be8affaa4c46231fd10590acc674b21bf16 /src | |
parent | d548d56d604193e4eebb4ab81c347887763b7d69 (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.h | 7 | ||||
-rw-r--r-- | src/iterator.c | 98 | ||||
-rw-r--r-- | src/iterator.h | 10 |
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 |