rapidyaml  0.12.0
parse and emit YAML, and do it fast
node_type.cpp
Go to the documentation of this file.
1 #include "c4/yml/node_type.hpp"
2 
3 namespace c4 {
4 namespace yml {
5 
6 const char* NodeType::type_str(NodeType_e ty) noexcept
7 {
8  switch(ty & _TYMASK)
9  {
10  case KEYVAL:
11  return "KEYVAL";
12  case KEY:
13  return "KEY";
14  case VAL:
15  return "VAL";
16  case MAP:
17  return "MAP";
18  case SEQ:
19  return "SEQ";
20  case KEYMAP:
21  return "KEYMAP";
22  case KEYSEQ:
23  return "KEYSEQ";
24  case DOCSEQ:
25  return "DOCSEQ";
26  case DOCMAP:
27  return "DOCMAP";
28  case DOCVAL:
29  return "DOCVAL";
30  case DOC:
31  return "DOC";
32  case STREAM:
33  return "STREAM";
34  case NOTYPE:
35  return "NOTYPE";
36  default:
37  if((ty & KEYVAL) == KEYVAL)
38  return "KEYVAL***";
39  if((ty & KEYMAP) == KEYMAP)
40  return "KEYMAP***";
41  if((ty & KEYSEQ) == KEYSEQ)
42  return "KEYSEQ***";
43  if((ty & DOCSEQ) == DOCSEQ)
44  return "DOCSEQ***";
45  if((ty & DOCMAP) == DOCMAP)
46  return "DOCMAP***";
47  if((ty & DOCVAL) == DOCVAL)
48  return "DOCVAL***";
49  if(ty & KEY)
50  return "KEY***";
51  if(ty & VAL)
52  return "VAL***";
53  if(ty & MAP)
54  return "MAP***";
55  if(ty & SEQ)
56  return "SEQ***";
57  if(ty & DOC)
58  return "DOC***";
59  return "(unk)";
60  }
61 }
62 
63 csubstr NodeType::type_str(substr buf, NodeType_e flags) noexcept
64 {
65  size_t pos = 0;
66  bool gotone = false;
67 
68  #define _prflag(fl, txt) \
69  do { \
70  if((flags & (fl)) == (fl)) \
71  { \
72  if(gotone) \
73  { \
74  if(pos + 1 < buf.len) \
75  buf[pos] = '|'; \
76  ++pos; \
77  } \
78  csubstr fltxt = txt; \
79  if(pos + fltxt.len <= buf.len) \
80  memcpy(buf.str + pos, fltxt.str, fltxt.len); \
81  pos += fltxt.len; \
82  gotone = true; \
83  flags = (flags & ~(fl)); /*remove the flag*/ \
84  } \
85  } while(0)
86 
87  _prflag(STREAM, "STREAM");
88  _prflag(DOC, "DOC");
89  // key properties
90  _prflag(KEY, "KEY");
91  _prflag(KEYNIL, "KNIL");
92  _prflag(KEYTAG, "KTAG");
93  _prflag(KEYANCH, "KANCH");
94  _prflag(KEYREF, "KREF");
95  _prflag(KEY_LITERAL, "KLITERAL");
96  _prflag(KEY_FOLDED, "KFOLDED");
97  _prflag(KEY_SQUO, "KSQUO");
98  _prflag(KEY_DQUO, "KDQUO");
99  _prflag(KEY_PLAIN, "KPLAIN");
100  _prflag(KEY_UNFILT, "KUNFILT");
101  // val properties
102  _prflag(VAL, "VAL");
103  _prflag(VALNIL, "VNIL");
104  _prflag(VALTAG, "VTAG");
105  _prflag(VALANCH, "VANCH");
106  _prflag(VALREF, "VREF");
107  _prflag(VAL_UNFILT, "VUNFILT");
108  _prflag(VAL_LITERAL, "VLITERAL");
109  _prflag(VAL_FOLDED, "VFOLDED");
110  _prflag(VAL_SQUO, "VSQUO");
111  _prflag(VAL_DQUO, "VDQUO");
112  _prflag(VAL_PLAIN, "VPLAIN");
113  _prflag(VAL_UNFILT, "VUNFILT");
114  // container properties
115  _prflag(MAP, "MAP");
116  _prflag(SEQ, "SEQ");
117  _prflag(FLOW_SL, "FLOWSL");
118  _prflag(FLOW_ML, "FLOWML");
119  _prflag(BLOCK, "BLCK");
120  if(pos == 0)
121  _prflag(NOTYPE, "NOTYPE");
122 
123  #undef _prflag
124 
125  if(pos < buf.len)
126  {
127  buf[pos] = '\0';
128  return buf.first(pos);
129  }
130  else
131  {
132  csubstr failed;
133  failed.len = pos + 1;
134  failed.str = nullptr;
135  return failed;
136  }
137 }
138 
139 
140 //-----------------------------------------------------------------------------
141 
142 // see https://www.yaml.info/learn/quote.html#noplain
143 bool scalar_style_query_squo(csubstr s) noexcept
144 {
145  return ! s.first_of_any("\n ", "\n\t");
146 }
147 
148 // see https://www.yaml.info/learn/quote.html#noplain
149 bool scalar_style_query_plain(csubstr s) noexcept
150 {
151  if(s.begins_with("-."))
152  {
153  if(s == "-.inf" || s == "-.INF")
154  return true;
155  else if(s.sub(2).is_number())
156  return true;
157  }
158  else if(s.begins_with_any("0123456789.-+") && s.is_number())
159  {
160  return true;
161  }
162  return ( ! s.begins_with_any("-:?*&,'\"{}[]|>%#@`\r")) // @ and ` are reserved characters
163  && ( ! s.ends_with_any(":#"))
164  // make this check in the last place, as it has linear
165  // complexity, while the previous ones are
166  // constant-time
167  && (s.first_of("\n#:[]{},") == npos);
168 }
169 
170 NodeType_e scalar_style_choose(csubstr s) noexcept
171 {
172  if(s.len)
173  {
174  if(s.begins_with_any(" \n\t")
175  ||
176  s.ends_with_any(" \n\t"))
177  {
178  return SCALAR_DQUO;
179  }
180  else if( ! scalar_style_query_plain(s))
181  {
183  }
184  // nothing remarkable - use plain
185  return SCALAR_PLAIN;
186  }
187  return s.str ? SCALAR_SQUO : SCALAR_PLAIN;
188 }
189 
191 {
192  // do not quote special cases
193  bool plain = (
194  (s == "true" || s == "false" || s == "null")
195  ||
196  (
197  // do not quote numbers
198  s.is_number()
199  &&
200  (
201  (
202  // quote integral numbers if they have a leading 0
203  // https://github.com/biojppm/rapidyaml/issues/291
204  (!(s.len > 1 && s.begins_with('0')))
205  // do not quote reals with leading 0
206  // https://github.com/biojppm/rapidyaml/issues/313
207  || (s.find('.') != csubstr::npos)
208  )
209  )
210  )
211  ||
212  (
213  (s.len > 3)
214  &&
215  (
216  (s[0] == '.' && (s == ".inf" || s == ".Inf" || s == ".INF"
217  ||
218  s == ".nan" || s == ".NaN" || s == ".NAN"))
219  ||
220  (s[0] == '-' && (s == "-.inf" || s == "-.Inf" || s == "-.INF"))
221  )
222  )
223  );
224  return plain ? SCALAR_PLAIN : SCALAR_DQUO;
225 }
226 
227 } // namespace yml
228 } // namespace c4
NodeType_e scalar_style_json_choose(csubstr s) noexcept
choose a json style based on the scalar's contents
Definition: node_type.cpp:190
bool scalar_style_query_squo(csubstr s) noexcept
query whether a scalar can be encoded using single quotes.
Definition: node_type.cpp:143
bool scalar_style_query_plain(csubstr s) noexcept
query whether a scalar can be encoded using plain style (no quotes, not a literal/folded block scalar...
Definition: node_type.cpp:149
NodeType_e scalar_style_choose(csubstr s) noexcept
choose a YAML emitting style based on the scalar's contents
Definition: node_type.cpp:170
NodeType_e
a bit mask for marking node types and styles
Definition: node_type.hpp:34
@ VALANCH
the val has an &anchor
Definition: node_type.hpp:46
@ NOTYPE
no node type or style is set
Definition: node_type.hpp:36
@ KEY_DQUO
mark key scalar as double quoted "
Definition: node_type.hpp:69
@ VALREF
a *reference: the val references an &anchor
Definition: node_type.hpp:44
@ VALNIL
the val is null (eg {a : } results in a null val)
Definition: node_type.hpp:50
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:39
@ STREAM
a stream: a seq of docs
Definition: node_type.hpp:42
@ KEY
is member of a map
Definition: node_type.hpp:37
@ VAL_FOLDED
mark val scalar as multiline, block folded >
Definition: node_type.hpp:66
@ KEYTAG
the key has a tag
Definition: node_type.hpp:47
@ SCALAR_SQUO
Definition: node_type.hpp:87
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
Definition: node_type.hpp:60
@ FLOW_ML
mark container with multi-line flow style (seqs as '[ val1, val2 ], maps as '{ key: val,...
Definition: node_type.hpp:61
@ VAL_UNFILT
the val scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:56
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:38
@ VALTAG
the val has a tag
Definition: node_type.hpp:48
@ _TYMASK
all the bits up to here
Definition: node_type.hpp:51
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:40
@ SCALAR_DQUO
Definition: node_type.hpp:88
@ VAL_SQUO
mark val scalar as single quoted '
Definition: node_type.hpp:68
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:72
@ KEYREF
a *reference: the key references an &anchor
Definition: node_type.hpp:43
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
Definition: node_type.hpp:62
@ KEYANCH
the key has an &anchor
Definition: node_type.hpp:45
@ VAL_DQUO
mark val scalar as double quoted "
Definition: node_type.hpp:70
@ KEY_UNFILT
the key scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:55
@ KEY_SQUO
mark key scalar as single quoted '
Definition: node_type.hpp:67
@ VAL_LITERAL
mark val scalar as multiline, block literal |
Definition: node_type.hpp:64
@ KEY_LITERAL
mark key scalar as multiline, block literal |
Definition: node_type.hpp:63
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:71
@ SCALAR_PLAIN
Definition: node_type.hpp:89
@ KEY_FOLDED
mark key scalar as multiline, block folded >
Definition: node_type.hpp:65
@ KEYNIL
the key is null (eg { : b} results in a null key)
Definition: node_type.hpp:49
@ DOC
a document
Definition: node_type.hpp:41
@ npos
a null string position
Definition: common.hpp:258
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
#define _prflag(fl, txt)
const char * type_str() const noexcept
return a preset string based on the node type
Definition: node_type.hpp:154