3 #include "c4/yml/detail/dbgprint.hpp"
11 if((tag.len > 2) && (tag.str[0] ==
'!'))
13 size_t pos = tag.find(
'!', 1);
14 return pos !=
npos && pos > 1 && tag.str[1] !=
'<';
24 if(tag.begins_with(
"!<"))
26 if(tag.begins_with(
"<!"))
36 if(tag.begins_with(
"!<"))
38 if(tag.begins_with(
"<!"))
46 if(result.begins_with(
"!!"))
48 _RYML_CHECK_BASIC(!output.overlaps(tag));
50 const csubstr pfx =
"<tag:yaml.org,2002:";
51 const size_t len = pfx.len + tag.len + 1;
54 memcpy(output.str , pfx.str, pfx.len);
55 memcpy(output.str + pfx.len, tag.str, tag.len);
56 output[pfx.len + tag.len] =
'>';
57 result = output.first(len);
70 if(tag.begins_with(
"!<"))
72 if(tag.begins_with(
"!!"))
76 else if(tag.begins_with(
'!'))
82 csubstr pfx =
"<tag:yaml.org,2002:";
83 csubstr pfx2 = pfx.sub(1);
84 if(tag.begins_with(pfx2))
86 tag = tag.sub(pfx2.len);
88 else if(tag.begins_with(pfx))
90 tag = tag.sub(pfx.len);
98 else if(tag ==
"omap")
100 else if(tag ==
"pairs")
102 else if(tag ==
"set")
104 else if(tag ==
"seq")
106 else if(tag ==
"binary")
108 else if(tag ==
"bool")
110 else if(tag ==
"float")
112 else if(tag ==
"int")
114 else if(tag ==
"merge")
116 else if(tag ==
"null")
118 else if(tag ==
"str")
120 else if(tag ==
"timestamp")
122 else if(tag ==
"value")
124 else if(tag ==
"yaml")
135 return {
"<tag:yaml.org,2002:map>"};
137 return {
"<tag:yaml.org,2002:omap>"};
139 return {
"<tag:yaml.org,2002:pairs>"};
141 return {
"<tag:yaml.org,2002:set>"};
143 return {
"<tag:yaml.org,2002:seq>"};
145 return {
"<tag:yaml.org,2002:binary>"};
147 return {
"<tag:yaml.org,2002:bool>"};
149 return {
"<tag:yaml.org,2002:float>"};
151 return {
"<tag:yaml.org,2002:int>"};
153 return {
"<tag:yaml.org,2002:merge>"};
155 return {
"<tag:yaml.org,2002:null>"};
157 return {
"<tag:yaml.org,2002:str>"};
159 return {
"<tag:yaml.org,2002:timestamp>"};
161 return {
"<tag:yaml.org,2002:value>"};
163 return {
"<tag:yaml.org,2002:yaml>"};
199 return {
"!!timestamp"};
212 if(handle.begins_with(
'!') && handle.ends_with(
'!'))
214 _c4dbgpf(
"handle={}", _prs(handle,
true));
215 csubstr trimmed = handle.sub(1);
216 if(trimmed.ends_with(
'!'))
217 trimmed = trimmed.offs(0, 1);
218 _c4dbgpf(
"handle_trimmed={}", _prs(trimmed,
true));
220 for(
char c : trimmed)
222 bool ok = (c >=
'0' && c <=
'9')
223 || (c >=
'a' && c <=
'z')
224 || (c >=
'A' && c <=
'Z')
228 _c4dbgpf(
"invalid handle character: '{}'", _c4prc(c));
238 bool is_valid_tag_char(
char c)
241 bool ok = (c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
272 bool read_hex_char(csubstr suffix,
size_t pos,
char *out)
275 if(pos + 3 > suffix.len)
277 suffix = suffix.range(pos + 1, pos + 3);
279 if(C4_UNLIKELY(!
read_hex(suffix, &val) || val > 127))
281 *out =
static_cast<char>(val);
287 size_t transform_tag(substr output, csubstr handle, csubstr prefix, csubstr tag,
291 _RYML_ASSERT_BASIC_(callbacks, tag.len >= handle.len);
292 _RYML_ASSERT_BASIC_(callbacks, !output.overlaps(tag));
293 _RYML_ASSERT_BASIC_(callbacks, prefix.len > 0);
294 csubstr rest = tag.sub(handle.len);
295 _c4dbgpf(
"%TAG: rest={}", _prs(rest));
296 size_t rpos = 0, wpos = 0;
297 auto appendstr = [&](csubstr s) {
298 if(s.len && wpos + s.len <= output.len)
299 memcpy(output.str + wpos, s.str, s.len);
302 auto appendchar = [&](
char c) {
303 if(wpos < output.len)
304 output.str[wpos] = c;
310 const char *errmsg =
nullptr;
311 for(
size_t pos = 0; pos < rest.len; ++pos)
313 char c = rest.str[pos];
314 if(C4_LIKELY(is_valid_tag_char(c)))
318 else if(read_hex_char(rest, pos, &c))
320 appendstr(rest.range(rpos, pos));
327 errmsg =
"invalid tag";
330 appendstr(rest.sub(rpos));
337 _RYML_ERR_PARSE_(callbacks, ymlloc, errmsg);
341 _RYML_ERR_BASIC_(callbacks, errmsg);
364 td = &m_directives[pos];
368 _c4dbgpf(
"tagd[{}]: added! handle={} prefix={} doc={}", pos, td->handle, td->prefix, td->doc_id);
390 if(doc_id == td.doc_id)
392 first = m_directives + i;
395 else if(td.handle.empty())
403 for(
TagDirective const* C4_RESTRICT td = first; td < last; ++td)
405 if(doc_id != td->doc_id || td->handle.empty())
414 first = last = m_directives;
421 _c4dbgpf(
"tagd: searching for {}, doc_id={}", _prs(tag), doc_id);
425 if(td.handle.empty())
429 _c4dbgpf(
"tagd[{}]: handle={} prefix={} doc_id={}", i, td.handle, td.prefix, td.doc_id);
430 if(tag.begins_with(td.handle))
432 if(td.handle ==
'!' && (
433 tag.begins_with(
"!!")
434 || tag.begins_with(
'<')
435 || tag.begins_with(
"!<")
438 _c4dbgpf(
"tagd[{}]: matches handle!", i);
439 if(doc_id == td.doc_id)
441 _c4dbgpf(
"tagd[{}]: matches doc={}!", i, doc_id);
451 _RYML_ASSERT_BASIC_(callbacks, !buf.overlaps(tag));
454 csubstr handle, prefix, ret;
455 const char *errmsg =
nullptr;
464 _c4dbgp(
"tagd: no directive found");
465 if(tag.begins_with(
'<'))
467 _c4dbgp(
"tagd: already resolved");
468 if(C4_UNLIKELY(!tag.ends_with(
'>')))
470 errmsg =
"malformed tag";
475 else if(tag.begins_with(
"!<"))
477 _c4dbgp(
"tagd: already resolved");
478 if(C4_UNLIKELY(!tag.ends_with(
'>')))
480 errmsg =
"malformed tag";
485 else if(tag.begins_with(
"!!"))
491 _c4dbgpf(
"tagd: standard tag: {} -> {}", tag,
from_tag_long(tagenum));
493 return with_brackets ? tag : tag.offs(1, 1);
496 prefix =
"tag:yaml.org,2002:";
500 _c4dbgp(
"tagd: custom_tag");
501 _c4dbgpf(
"tag '{}' at id={}: no matching directive was found", tag,
id);
502 errmsg =
"tag without matching directive";
508 handle = prefix =
"!";
511 len =
transform_tag(buf, handle, prefix, tag, callbacks, ymlloc, with_brackets);
515 ret = buf.first(len);
519 _c4dbgp(
"tagd: not enough room");
527 _RYML_ERR_PARSE_(callbacks, ymlloc, errmsg);
531 _RYML_ERR_BASIC_(callbacks, errmsg);
541 if(sz < linear_threshold)
543 for(
size_t i = 0; i < sz; ++i)
545 Entry const& C4_RESTRICT e = m_entries[i];
546 if(e.tag == tag && e.doc_id == doc_id)
552 else if(e.tag > tag || ((e.tag == tag) && e.doc_id > doc_id))
568 _RYML_ASSERT_BASIC_(m_entries.m_callbacks, mid < sz);
569 Entry const& C4_RESTRICT e = m_entries[mid];
570 if(e.tag < tag || (e.tag == tag && e.doc_id < doc_id))
573 _RYML_ASSERT_BASIC_(m_entries.m_callbacks, count >= halfsz + 1);
584 Entry const& C4_RESTRICT e = m_entries[first];
585 if(e.tag == tag && e.doc_id == doc_id)
587 ret.
resolved = m_entries[first].resolved;
596 const id_type sz = m_entries.size();
597 _RYML_ASSERT_BASIC_(m_entries.m_callbacks, pos <= sz);
598 _RYML_ASSERT_BASIC_(m_entries.m_callbacks, pos == sz || tag < m_entries[pos].tag || (tag == m_entries[pos].tag && doc_id < m_entries[pos].doc_id));
599 m_entries.resize(sz + 1);
601 memmove(m_entries.m_stack + pos + 1, m_entries.m_stack + pos, (sz - pos) *
sizeof(
Entry));
602 m_entries.m_stack[pos].tag = tag;
603 m_entries.m_stack[pos].resolved = resolved;
604 m_entries.m_stack[pos].doc_id = doc_id;
605 _c4dbgpf(
"tagcache: add entry @pos={}: docid={} {} -> {}", pos, doc_id, tag, _maybe_null_str(resolved));
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
Error utilities used by ryml.
bool read_hex(csubstr s, I *v) noexcept
read an hexadecimal integer from a string.
csubstr from_tag_long(YamlTag_e tag)
bool is_valid_tag_handle(csubstr handle)
bool is_custom_tag(csubstr tag)
is a tag of the form !handle!tag?
csubstr normalize_tag_long(csubstr tag)
YamlTag_e
a bit mask for marking tags for types
size_t transform_tag(substr output, csubstr handle, csubstr prefix, csubstr tag, Callbacks const &callbacks, Location const &ymlloc, bool with_brackets)
returns the length of the transformed tag, or 0 to signal that the tag is local and cannot be resolve...
csubstr normalize_tag(csubstr tag)
csubstr from_tag(YamlTag_e tag)
YamlTag_e to_tag(csubstr tag)
#define RYML_MAX_TAG_DIRECTIVES
the maximum number of tag directives in a Tree
@ TAG_SET
!!set Unordered set of non-equal values.
@ TAG_MERGE
!!merge Specify one or more mapping to be merged with the current one.
@ TAG_INT
!!float Mathematical integers.
@ TAG_SEQ
!!seq Sequence of arbitrary values.
@ TAG_NULL
!!null Devoid of value.
@ TAG_YAML
!!yaml Specify the default value of a mapping https://yaml.org/type/yaml.html
@ TAG_TIMESTAMP
!!timestamp A point in time https://yaml.org/type/timestamp.html
@ TAG_STR
!!str A sequence of zero or more Unicode characters.
@ TAG_BOOL
!!bool Mathematical Booleans.
@ TAG_MAP
!!map Unordered set of key: value pairs without duplicates.
@ TAG_BINARY
!!binary A sequence of zero or more octets (8 bit values).
@ TAG_PAIRS
!!pairs Ordered sequence of key: value pairs allowing duplicates.
@ TAG_VALUE
!!value Specify the default value of a mapping https://yaml.org/type/value.html
@ TAG_OMAP
!!omap Ordered sequence of key: value pairs without duplicates.
@ TAG_FLOAT
!!float Floating-point approximation to real numbers.
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
@ npos
a null string position
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
A c-style callbacks class to customize behavior on errors or allocation.
holds a source or yaml file position, for example when an error is detected; See also location_format...
LookupResult find(csubstr tag, id_type doc_id, id_type linear_threshold=Entries::sso_size) const noexcept
void add(csubstr tag, csubstr resolved, id_type doc_id, const_iterator pos) RYML_NOEXCEPT
TagDirective m_directives[RYML_MAX_TAG_DIRECTIVES]
id_type size() const noexcept
TagDirectiveRange lookup_range(id_type doc_id) const noexcept
csubstr resolve(substr buf, size_t *bufsz, csubstr tag, id_type doc_id, Location const &ymlloc, Callbacks const &callbacks, bool with_brackets=true) const
TagDirective const * add(csubstr handle, csubstr prefix, id_type doc_id) noexcept
TagDirective const * lookup(csubstr tag, id_type id) const noexcept