Coverage Report

Created: 2025-11-09 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}