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_(callbacks, tag.
len >= handle.
len);
292 _RYML_ASSERT_BASIC_(callbacks, !output.
overlaps(tag));
293 _RYML_ASSERT_BASIC_(callbacks, prefix.
len > 0);
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);
368 _c4dbgpf(
"tagd[{}]: added! handle={} prefix={} doc={}", pos, td->handle, td->prefix, td->doc_id);
390 if(doc_id == td.doc_id)
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())
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));
455 const char *errmsg =
nullptr;
464 _c4dbgp(
"tagd: no directive found");
467 _c4dbgp(
"tagd: already resolved");
470 errmsg =
"malformed tag";
477 _c4dbgp(
"tagd: already resolved");
480 errmsg =
"malformed tag";
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.
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
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...
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