cmark

My personal build of CMark ✏️

Commit
0c73a05dca8afca491298f3d8f07750e3fcf330d
Parent
25429c96f6554ffac415f9d865934b1183f3398e
Author
Vicent Marti <tanoku@gmail.com>
Date

node: Memory diet

Save node information in flags instead of using one boolean for each property.

Diffstat

2 files changed, 31 insertions, 15 deletions

Status File Name N° Changes Insertions Deletions
Modified src/blocks.c 35 24 11
Modified src/node.h 11 7 4
diff --git a/src/blocks.c b/src/blocks.c
@@ -30,6 +30,17 @@
 
 #define peek_at(i, n) (i)->data[n]
 
+static bool S_last_line_blank(const cmark_node *node) {
+  return (node->flags & CMARK_NODE__LAST_LINE_BLANK);
+}
+
+static void S_set_last_line_blank(cmark_node *node, bool is_blank) {
+  if (is_blank)
+    node->flags |= CMARK_NODE__LAST_LINE_BLANK;
+  else
+    node->flags &= ~CMARK_NODE__LAST_LINE_BLANK;
+}
+
 static CMARK_INLINE bool S_is_line_end_char(char c) {
   return (c == '\n' || c == '\r');
 }
@@ -51,7 +62,7 @@ static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag, int start_lin
   e = (cmark_node *)mem->calloc(1, sizeof(*e));
   cmark_strbuf_init(mem, &e->content, 32);
   e->type = tag;
-  e->open = true;
+  e->flags = CMARK_NODE__OPEN;
   e->start_line = start_line;
   e->start_column = start_column;
   e->end_line = start_line;
@@ -166,7 +177,7 @@ static CMARK_INLINE bool contains_inlines(cmark_node_type block_type) {
 static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *parser) {
   int chars_to_tab;
   int i;
-  assert(node->open);
+  assert(node->flags & CMARK_NODE__OPEN);
   if (parser->partially_consumed_tab) {
     parser->offset += 1; // skip over tab
     // add space characters:
@@ -211,7 +222,7 @@ static void remove_trailing_blank_lines(cmark_strbuf *ln) {
 static bool ends_with_blank_line(cmark_node *node) {
   cmark_node *cur = node;
   while (cur != NULL) {
-    if (cur->last_line_blank) {
+    if (S_last_line_blank(cur)) {
       return true;
     }
     if (cur->type == CMARK_NODE_LIST || cur->type == CMARK_NODE_ITEM) {
@@ -248,8 +259,8 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
   cmark_node *parent;
 
   parent = b->parent;
-  assert(b->open); // shouldn't call finalize on closed blocks
-  b->open = false;
+  assert(b->flags & CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
+  b->flags &= ~CMARK_NODE__OPEN;
 
   if (parser->curline->size == 0) {
     // end of input - line number has not been incremented
@@ -322,7 +333,7 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
 
     while (item) {
       // check for non-final non-empty list item ending with blank line:
-      if (item->last_line_blank && item->next) {
+      if (S_last_line_blank(item) && item->next) {
         b->as.list.tight = false;
         break;
       }
@@ -656,7 +667,7 @@ static void S_advance_offset(cmark_parser *parser, cmark_chunk *input,
 }
 
 static bool S_last_child_is_open(cmark_node *container) {
-  return container->last_child && container->last_child->open;
+  return container->last_child && (container->last_child->flags & CMARK_NODE__OPEN);
 }
 
 static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *input) {
@@ -1007,13 +1018,13 @@ static void add_text_to_container(cmark_parser *parser, cmark_node *container,
   S_find_first_nonspace(parser, input);
 
   if (parser->blank && container->last_child)
-    container->last_child->last_line_blank = true;
+    S_set_last_line_blank(container->last_child, true);
 
   // block quote lines are never blank as they start with >
   // and we don't count blanks in fenced code for purposes of tight/loose
   // lists or breaking out of lists.  we also don't set last_line_blank
   // on an empty list item.
-  container->last_line_blank =
+  bool last_line_blank =
       (parser->blank && container->type != CMARK_NODE_BLOCK_QUOTE &&
        container->type != CMARK_NODE_HEADING &&
        container->type != CMARK_NODE_THEMATIC_BREAK &&
@@ -1022,9 +1033,11 @@ static void add_text_to_container(cmark_parser *parser, cmark_node *container,
        !(container->type == CMARK_NODE_ITEM && container->first_child == NULL &&
          container->start_line == parser->line_number));
 
+  S_set_last_line_blank(container, last_line_blank);
+
   tmp = container;
   while (tmp->parent) {
-    tmp->parent->last_line_blank = false;
+    S_set_last_line_blank(tmp->parent, false);
     tmp = tmp->parent;
   }
 
@@ -1144,7 +1157,7 @@ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
   container = last_matched_container;
 
   // check to see if we've hit 2nd blank line, break out of list:
-  if (parser->blank && container->last_line_blank)
+  if (parser->blank && S_last_line_blank(container))
     break_out_of_lists(parser, &container);
 
   open_new_blocks(parser, &container, &input, all_matched);
diff --git a/src/node.h b/src/node.h
@@ -47,6 +47,11 @@ typedef struct {
   cmark_chunk on_exit;
 } cmark_custom;
 
+enum cmark_node__internal_flags {
+  CMARK_NODE__OPEN = (1 << 0),
+  CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
+};
+
 struct cmark_node {
   cmark_strbuf content;
 
@@ -62,10 +67,8 @@ struct cmark_node {
   int start_column;
   int end_line;
   int end_column;
-
-  cmark_node_type type;
-  bool last_line_blank;
-  bool open;
+  uint16_t type;
+  uint16_t flags;
 
   union {
     cmark_chunk literal;