/src/cmark/src/iterator.c
Line | Count | Source |
1 | | #include <assert.h> |
2 | | #include <stdbool.h> |
3 | | #include <stdlib.h> |
4 | | |
5 | | #include "node.h" |
6 | | #include "cmark.h" |
7 | | #include "iterator.h" |
8 | | |
9 | | static const int S_leaf_mask = |
10 | | (1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) | |
11 | | (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) | |
12 | | (1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) | |
13 | | (1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE); |
14 | | |
15 | 302k | cmark_iter *cmark_iter_new(cmark_node *root) { |
16 | 302k | if (root == NULL) { |
17 | 0 | return NULL; |
18 | 0 | } |
19 | 302k | cmark_mem *mem = root->mem; |
20 | 302k | cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter)); |
21 | 302k | iter->mem = mem; |
22 | 302k | iter->root = root; |
23 | 302k | iter->cur.ev_type = CMARK_EVENT_NONE; |
24 | 302k | iter->cur.node = NULL; |
25 | 302k | iter->next.ev_type = CMARK_EVENT_ENTER; |
26 | 302k | iter->next.node = root; |
27 | 302k | return iter; |
28 | 302k | } |
29 | | |
30 | 302k | void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); } |
31 | | |
32 | 92.0M | static bool S_is_leaf(cmark_node *node) { |
33 | 92.0M | return ((1 << node->type) & S_leaf_mask) != 0; |
34 | 92.0M | } |
35 | | |
36 | 171M | cmark_event_type cmark_iter_next(cmark_iter *iter) { |
37 | 171M | cmark_event_type ev_type = iter->next.ev_type; |
38 | 171M | cmark_node *node = iter->next.node; |
39 | | |
40 | 171M | iter->cur.ev_type = ev_type; |
41 | 171M | iter->cur.node = node; |
42 | | |
43 | 171M | if (ev_type == CMARK_EVENT_DONE) { |
44 | 302k | return ev_type; |
45 | 302k | } |
46 | | |
47 | | /* roll forward to next item, setting both fields */ |
48 | 170M | if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) { |
49 | 78.8M | if (node->first_child == NULL) { |
50 | | /* stay on this node but exit */ |
51 | 22.3M | iter->next.ev_type = CMARK_EVENT_EXIT; |
52 | 56.5M | } else { |
53 | 56.5M | iter->next.ev_type = CMARK_EVENT_ENTER; |
54 | 56.5M | iter->next.node = node->first_child; |
55 | 56.5M | } |
56 | 92.0M | } else if (node == iter->root) { |
57 | | /* don't move past root */ |
58 | 302k | iter->next.ev_type = CMARK_EVENT_DONE; |
59 | 302k | iter->next.node = NULL; |
60 | 91.7M | } else if (node->next) { |
61 | 35.2M | iter->next.ev_type = CMARK_EVENT_ENTER; |
62 | 35.2M | iter->next.node = node->next; |
63 | 56.4M | } else if (node->parent) { |
64 | 56.4M | iter->next.ev_type = CMARK_EVENT_EXIT; |
65 | 56.4M | iter->next.node = node->parent; |
66 | 56.4M | } else { |
67 | 0 | assert(false); |
68 | 0 | iter->next.ev_type = CMARK_EVENT_DONE; |
69 | 0 | iter->next.node = NULL; |
70 | 0 | } |
71 | | |
72 | 170M | return ev_type; |
73 | 171M | } |
74 | | |
75 | | void cmark_iter_reset(cmark_iter *iter, cmark_node *current, |
76 | 28.1k | cmark_event_type event_type) { |
77 | 28.1k | iter->next.ev_type = event_type; |
78 | 28.1k | iter->next.node = current; |
79 | 28.1k | cmark_iter_next(iter); |
80 | 28.1k | } |
81 | | |
82 | 166M | cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; } |
83 | | |
84 | 0 | cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) { |
85 | 0 | return iter->cur.ev_type; |
86 | 0 | } |
87 | | |
88 | 0 | cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; } |
89 | | |
90 | 115k | void cmark_consolidate_text_nodes(cmark_node *root) { |
91 | 115k | if (root == NULL) { |
92 | 314 | return; |
93 | 314 | } |
94 | 115k | cmark_iter *iter = cmark_iter_new(root); |
95 | 115k | cmark_strbuf buf = CMARK_BUF_INIT(iter->mem); |
96 | 115k | cmark_event_type ev_type; |
97 | 115k | cmark_node *cur, *tmp, *next; |
98 | | |
99 | 24.8M | while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { |
100 | 24.7M | cur = cmark_iter_get_node(iter); |
101 | 24.7M | if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT && |
102 | 1.08M | cur->next && cur->next->type == CMARK_NODE_TEXT) { |
103 | 495k | cmark_strbuf_clear(&buf); |
104 | 495k | cmark_strbuf_put(&buf, cur->data, cur->len); |
105 | 495k | tmp = cur->next; |
106 | 4.47M | while (tmp && tmp->type == CMARK_NODE_TEXT) { |
107 | 3.98M | cmark_iter_next(iter); // advance pointer |
108 | 3.98M | cmark_strbuf_put(&buf, tmp->data, tmp->len); |
109 | 3.98M | cur->end_column = tmp->end_column; |
110 | 3.98M | next = tmp->next; |
111 | 3.98M | cmark_node_free(tmp); |
112 | 3.98M | tmp = next; |
113 | 3.98M | } |
114 | 495k | iter->mem->free(cur->data); |
115 | 495k | cur->len = buf.size; |
116 | 495k | cur->data = cmark_strbuf_detach(&buf); |
117 | 495k | } |
118 | 24.7M | } |
119 | | |
120 | 115k | cmark_strbuf_free(&buf); |
121 | 115k | cmark_iter_free(iter); |
122 | 115k | } |