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] !=
'<';
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;
56 output[pfx.
len + tag.
len] =
'>';
57 result = output.
first(len);
82 csubstr pfx =
"<tag:yaml.org,2002:";
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"};
214 _c4dbgpf(
"handle={}", prs_(handle,
true));
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));
238bool is_valid_tag_char(
char c)
241 bool ok = (c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
272bool 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);
291 RYML_ASSERT_BASIC_CB_(callbacks, tag.len >= handle.len);
292 RYML_ASSERT_BASIC_CB_(callbacks, !output.overlaps(tag));
293 RYML_ASSERT_BASIC_CB_(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))
320 else if(read_hex_char(rest, pos, &c))
322 appendstr(rest.
range(rpos, pos));
329 errmsg =
"invalid tag";
332 appendstr(rest.
sub(rpos));
339 RYML_ERR_PARSE_CB_(callbacks, ymlloc, errmsg);
343 RYML_ERR_BASIC_CB_(callbacks, errmsg);
370 _c4dbgpf(
"tagd[{}]: added! handle={} prefix={} doc={}", pos, td->handle, td->prefix, td->doc_id);
392 if(doc_id == td.doc_id)
397 else if(td.handle.empty())
405 for(
TagDirective const* C4_RESTRICT td = first; td < last; ++td)
407 if(doc_id != td->doc_id || td->handle.empty())
423 _c4dbgpf(
"tagd: searching for {}, doc_id={}", prs_(tag), doc_id);
427 if(td.handle.empty())
431 _c4dbgpf(
"tagd[{}]: handle={} prefix={} doc_id={}", i, td.handle, td.prefix, td.doc_id);
432 if(tag.begins_with(td.handle))
434 if(td.handle ==
'!' && (
435 tag.begins_with(
"!!")
436 || tag.begins_with(
'<')
437 || tag.begins_with(
"!<")
440 _c4dbgpf(
"tagd[{}]: matches handle!", i);
441 if(doc_id == td.doc_id)
443 _c4dbgpf(
"tagd[{}]: matches doc={}!", i, doc_id);
453 RYML_ASSERT_BASIC_CB_(callbacks, !buf.
overlaps(tag));
457 const char *errmsg =
nullptr;
466 _c4dbgp(
"tagd: no directive found");
469 _c4dbgp(
"tagd: already resolved");
472 errmsg =
"malformed tag";
479 _c4dbgp(
"tagd: already resolved");
482 errmsg =
"malformed tag";
493 _c4dbgpf(
"tagd: standard tag: {} -> {}", tag,
from_tag_long(tagenum));
495 return with_brackets ? tag : tag.
offs(1, 1);
498 prefix =
"tag:yaml.org,2002:";
502 _c4dbgp(
"tagd: custom_tag");
503 _c4dbgpf(
"tag '{}' at id={}: no matching directive was found", tag,
id);
504 errmsg =
"tag without matching directive";
510 handle = prefix =
"!";
513 len =
transform_tag(buf, handle, prefix, tag, callbacks, ymlloc, with_brackets);
517 ret = buf.
first(len);
521 _c4dbgp(
"tagd: not enough room");
529 RYML_ERR_PARSE_CB_(callbacks, ymlloc, errmsg);
533 RYML_ERR_BASIC_CB_(callbacks, errmsg);
543 if(sz < linear_threshold)
545 for(
size_t i = 0; i < sz; ++i)
547 Entry const& C4_RESTRICT e = m_entries[i];
548 if(e.tag == tag && e.doc_id == doc_id)
554 else if(e.tag > tag || ((e.tag == tag) && e.doc_id > doc_id))
570 RYML_ASSERT_BASIC_CB_(m_entries.m_callbacks, mid < sz);
571 Entry const& C4_RESTRICT e = m_entries[mid];
572 if(e.tag < tag || (e.tag == tag && e.doc_id < doc_id))
575 RYML_ASSERT_BASIC_CB_(m_entries.m_callbacks, count >= halfsz + 1);
586 Entry const& C4_RESTRICT e = m_entries[first];
587 if(e.tag == tag && e.doc_id == doc_id)
589 ret.
resolved = m_entries[first].resolved;
598 const id_type sz = m_entries.size();
599 RYML_ASSERT_BASIC_CB_(m_entries.m_callbacks, pos <= sz);
600 RYML_ASSERT_BASIC_CB_(m_entries.m_callbacks, pos == sz || tag < m_entries[pos].tag || (tag == m_entries[pos].tag && doc_id < m_entries[pos].doc_id));
601 m_entries.resize(sz + 1);
603 memmove(m_entries.m_stack + pos + 1, m_entries.m_stack + pos, (sz - pos) *
sizeof(
Entry));
604 m_entries.m_stack[pos].tag = tag;
605 m_entries.m_stack[pos].resolved = resolved;
606 m_entries.m_stack[pos].doc_id = doc_id;
607 _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.
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
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
@ npos
a null string position
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...
basic_substring range(size_t first, size_t last=npos) const noexcept
return [first,last[.
bool begins_with(const C c) const noexcept
true if the first character of the string is c
basic_substring offs(size_t left, size_t right) const noexcept
offset from the ends: return [left,len-right[ ; ie, trim a number of characters from the left and rig...
size_t len
the length of the substring
bool ends_with(const C c) const noexcept
true if the last character of the string is c
size_t find(const C c, size_t start_pos=0) const
bool overlaps(ro_substr const that) const noexcept
true if there is overlap of at least one element between that and *this
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
basic_substring sub(size_t first) const noexcept
return [first,len[
C * str
a restricted pointer to the first character of the substring
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