mirror of
https://github.com/biojppm/rapidyaml.git
synced 2026-01-18 21:41:18 +01:00
do not use std::string in the event handlers
This commit is contained in:
@@ -72,8 +72,9 @@ void test_new_parser_events_from_yaml(ReferenceYaml const& yaml, std::string con
|
||||
ParseEngine<EventHandlerYamlStd> parser(&handler);
|
||||
std::string copy = yaml.parsed;
|
||||
parser.parse_in_place_ev("(testyaml)", to_substr(copy));
|
||||
_c4dbgpf("~~~\n{}~~~\n", sink.result);
|
||||
EXPECT_EQ(sink.result, expected_events);
|
||||
csubstr result = sink;
|
||||
_c4dbgpf("~~~\n{}~~~\n", result);
|
||||
EXPECT_EQ(std::string(result.str, result.len), expected_events);
|
||||
}
|
||||
|
||||
void test_new_parser_tree_from_yaml(ReferenceYaml const& yaml)
|
||||
|
||||
@@ -42,8 +42,9 @@ C4_NO_INLINE void test_new_parser_str_from_events(std::string const& expected_ev
|
||||
handler.reset();
|
||||
EventProducerFn<EventHandlerYamlStd> event_producer;
|
||||
event_producer(handler);
|
||||
_c4dbgpf("~~~\n{}~~~\n", sink.result);
|
||||
EXPECT_EQ(sink.result, expected_events);
|
||||
csubstr result = sink;
|
||||
_c4dbgpf("~~~\n{}~~~\n", result);
|
||||
EXPECT_EQ(std::string(result.str, result.len), expected_events);
|
||||
}
|
||||
|
||||
template<template<class> class EventProducerFn>
|
||||
@@ -214,7 +215,7 @@ inline void _print_handler_info(EventHandlerYamlStd const& ps, csubstr stmt)
|
||||
};
|
||||
for(id_type i = 0; i < ps.m_stack.size(); ++i)
|
||||
{
|
||||
auto const& str = ps._buf_(i).get();
|
||||
csubstr const& str = ps._buf_(i);
|
||||
indent(i);
|
||||
_dbg_printf("[{}]\n", i);
|
||||
for(csubstr line : str.split('\n'))
|
||||
|
||||
@@ -299,11 +299,11 @@ struct TestSequenceLevel
|
||||
if(prev)
|
||||
receive_src(*prev);
|
||||
_nfo_logf("level[{}]: parsing source:\n{}", level, src_evts);
|
||||
evt_str_sink.reset();
|
||||
evt_str_sink.clear();
|
||||
evt_handler_str_sink.reset();
|
||||
evt_handler_str_sink.m_stack.m_callbacks = get_callbacks();
|
||||
parser_str_sink.parse_in_place_ev(filename, to_substr(src_evts));
|
||||
EXPECT_NE(evt_str_sink.result, "");
|
||||
EXPECT_NE(evt_str_sink.size(), 0);
|
||||
events_were_generated = true;
|
||||
}
|
||||
|
||||
@@ -655,7 +655,8 @@ struct TestSequenceData
|
||||
for(size_t i = 0; i < num; ++i)
|
||||
{
|
||||
levels[i].parse_yaml_to_events();
|
||||
events->compare_emitted_events_to_reference_events(levels[i].evt_str_sink.result,
|
||||
csubstr result = levels[i].evt_str_sink;
|
||||
events->compare_emitted_events_to_reference_events(std::string(result.str, result.len),
|
||||
/*ignore_container_style*/false,
|
||||
/*ignore_scalar_style*/(num>0));
|
||||
}
|
||||
|
||||
424
test/test_suite/string.hpp
Normal file
424
test/test_suite/string.hpp
Normal file
@@ -0,0 +1,424 @@
|
||||
#ifndef _C4_YML_EXTRA_STRING_HPP_
|
||||
#define _C4_YML_EXTRA_STRING_HPP_
|
||||
|
||||
#ifdef RYML_SINGLE_HEADER
|
||||
#ifndef _RYML_SINGLE_HEADER_AMALGAMATED_HPP_
|
||||
#include <ryml_all.hpp>
|
||||
#endif
|
||||
#else
|
||||
#ifndef _C4_YML_COMMON_HPP_
|
||||
#include "c4/yml/common.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
|
||||
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
|
||||
|
||||
#ifndef RYML_STRING_SSO_SIZE
|
||||
#define RYML_STRING_SSO_SIZE 128
|
||||
#endif
|
||||
|
||||
#ifndef RYML_STRING_LIST_SSO_SIZE
|
||||
#define RYML_STRING_LIST_SSO_SIZE 66
|
||||
#endif
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
namespace extra {
|
||||
|
||||
/** an owning string class used by the yaml std event handler (and the
|
||||
* YamlScript handler). we use this instead of std::string because:
|
||||
* 1) this spares the dependency on the standard library
|
||||
* 2) enables possibility of adding borrowing semantics (in the future) */
|
||||
struct string
|
||||
{
|
||||
enum : id_type { sso_size = RYML_STRING_SSO_SIZE };
|
||||
char m_buf[sso_size];
|
||||
char *C4_RESTRICT m_str;
|
||||
id_type m_size;
|
||||
id_type m_capacity;
|
||||
|
||||
public:
|
||||
|
||||
string()
|
||||
: m_buf()
|
||||
, m_str(m_buf)
|
||||
, m_size(0)
|
||||
, m_capacity(sso_size)
|
||||
{}
|
||||
~string() noexcept
|
||||
{
|
||||
_free();
|
||||
}
|
||||
|
||||
string(string const& that) RYML_NOEXCEPT : string()
|
||||
{
|
||||
resize(that.m_size);
|
||||
_cp(&that);
|
||||
}
|
||||
|
||||
string(string &&that) noexcept : string()
|
||||
{
|
||||
_mv(&that);
|
||||
}
|
||||
|
||||
string& operator= (string const& that) RYML_NOEXCEPT
|
||||
{
|
||||
resize(that.m_size);
|
||||
_cp(&that);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator= (string &&that) noexcept
|
||||
{
|
||||
_mv(&that);
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
C4_ALWAYS_INLINE C4_HOT operator csubstr() const noexcept { return {m_str, m_size}; }
|
||||
C4_ALWAYS_INLINE C4_HOT operator substr() noexcept { return {m_str, m_size}; }
|
||||
|
||||
public:
|
||||
|
||||
id_type size() const noexcept { return m_size; }
|
||||
id_type capacity() const noexcept { return m_capacity; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void resize(id_type sz)
|
||||
{
|
||||
reserve(sz);
|
||||
m_size = sz;
|
||||
}
|
||||
|
||||
void reserve(id_type sz)
|
||||
{
|
||||
if(sz <= m_capacity)
|
||||
return;
|
||||
id_type cap = m_capacity < string::sso_size ? string::sso_size : 2 * m_capacity;
|
||||
cap = cap > sz ? cap : sz;
|
||||
if(cap <= sso_size)
|
||||
return;
|
||||
Callbacks cb = get_callbacks();
|
||||
char *buf = (char*) _RYML_CB_ALLOC(cb, char, cap);
|
||||
if(m_size)
|
||||
memcpy(buf, m_str, (size_t)m_size);
|
||||
if(m_str != m_buf)
|
||||
{
|
||||
_RYML_CB_FREE(cb, m_str, char, m_size);
|
||||
}
|
||||
m_str = buf;
|
||||
m_capacity = cap;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
C4_ALWAYS_INLINE C4_HOT void append(char c)
|
||||
{
|
||||
if(C4_UNLIKELY(m_size == m_capacity))
|
||||
reserve(m_size + 1);
|
||||
m_str[m_size++] = c;
|
||||
}
|
||||
C4_ALWAYS_INLINE C4_HOT void append(csubstr cs)
|
||||
{
|
||||
if(cs.len)
|
||||
{
|
||||
const id_type ilen = (id_type)cs.len;
|
||||
if(C4_UNLIKELY(m_size + ilen > m_capacity))
|
||||
reserve(m_size + ilen);
|
||||
memcpy(m_str + m_size, cs.str, cs.len);
|
||||
m_size += ilen;
|
||||
}
|
||||
}
|
||||
C4_ALWAYS_INLINE void insert(char c, id_type pos)
|
||||
{
|
||||
RYML_ASSERT(pos <= m_size);
|
||||
if(pos < m_size)
|
||||
{
|
||||
if(C4_UNLIKELY(m_size == m_capacity))
|
||||
reserve(m_size + 1);
|
||||
char *C4_RESTRICT src = m_str + pos;
|
||||
memmove(src + 1, src, m_size - pos);
|
||||
*src = c;
|
||||
++m_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
append(c);
|
||||
}
|
||||
}
|
||||
C4_NO_INLINE void insert(csubstr cs, id_type pos)
|
||||
{
|
||||
RYML_ASSERT(pos <= m_size);
|
||||
if(cs.len)
|
||||
{
|
||||
if(pos < m_size)
|
||||
{
|
||||
const id_type ilen = (id_type)cs.len;
|
||||
if(C4_UNLIKELY(m_size + ilen > m_capacity))
|
||||
reserve(m_size + ilen);
|
||||
char *C4_RESTRICT src = m_str + pos;
|
||||
memmove(src + cs.len, src, m_size - pos);
|
||||
memcpy(src, cs.str, cs.len);
|
||||
m_size += ilen;
|
||||
}
|
||||
else
|
||||
{
|
||||
append(cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
C4_NO_INLINE size_t find_last(csubstr pattern) RYML_NOEXCEPT
|
||||
{
|
||||
RYML_ASSERT(pattern.len);
|
||||
if(m_size >= pattern.len)
|
||||
{
|
||||
for(size_t i = m_size - pattern.len; i != (size_t)-1; --i)
|
||||
{
|
||||
if(m_str[i] == pattern[0])
|
||||
{
|
||||
bool gotit = true;
|
||||
for(size_t j = 1; j < pattern.len; ++j)
|
||||
{
|
||||
if(m_str[i + j] != pattern[j])
|
||||
{
|
||||
gotit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(gotit)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void _free()
|
||||
{
|
||||
RYML_ASSERT(m_str != nullptr); // this structure cannot be memset() to zero
|
||||
if(m_str != m_buf)
|
||||
{
|
||||
_RYML_CB_FREE(get_callbacks(), m_str, char, (size_t)m_capacity);
|
||||
m_str = m_buf;
|
||||
m_capacity = sso_size;
|
||||
}
|
||||
RYML_ASSERT(m_capacity == sso_size);
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void _cp(string const* C4_RESTRICT that)
|
||||
{
|
||||
#if RYML_USE_ASSERT
|
||||
if(that->m_str != that->m_buf)
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity > sso_size);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity <= sso_size);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
}
|
||||
#endif
|
||||
memcpy(m_str, that->m_str, that->m_size);
|
||||
m_size = that->m_size;
|
||||
m_capacity = that->m_size < sso_size ? sso_size : that->m_size;
|
||||
}
|
||||
|
||||
void _mv(string *C4_RESTRICT that)
|
||||
{
|
||||
if(that->m_str != that->m_buf)
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity > sso_size);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
m_str = that->m_str;
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(that->m_capacity <= sso_size);
|
||||
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||
memcpy(m_buf, that->m_buf, that->m_size);
|
||||
m_str = m_buf;
|
||||
}
|
||||
m_size = that->m_size;
|
||||
m_capacity = that->m_capacity;
|
||||
// make sure no deallocation happens on destruction
|
||||
RYML_ASSERT(that->m_str != this->m_buf);
|
||||
that->m_str = that->m_buf;
|
||||
that->m_capacity = sso_size;
|
||||
that->m_size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** a string collection used by the event handler. using this instead of
|
||||
* std::vector spares the dependency on the standard library. */
|
||||
struct string_vector
|
||||
{
|
||||
enum : id_type { sso_size = RYML_STRING_LIST_SSO_SIZE };
|
||||
union {
|
||||
alignas(string) string m_buf[sso_size];
|
||||
alignas(string) char m_buf_bytes[sso_size * sizeof(string)];
|
||||
};
|
||||
string *C4_RESTRICT m_arr;
|
||||
id_type m_size;
|
||||
id_type m_capacity;
|
||||
|
||||
public:
|
||||
|
||||
string_vector()
|
||||
: m_arr(m_buf)
|
||||
, m_size(0)
|
||||
, m_capacity(sso_size)
|
||||
{}
|
||||
~string_vector() noexcept
|
||||
{
|
||||
_free();
|
||||
}
|
||||
|
||||
string_vector(string_vector const& that) RYML_NOEXCEPT : string_vector()
|
||||
{
|
||||
reserve(that.m_size);
|
||||
m_size = that.m_size;
|
||||
for(id_type i = 0; i < that.m_size; ++i)
|
||||
new ((void*)(m_arr+i)) string(that.m_arr[i]);
|
||||
}
|
||||
|
||||
string_vector(string_vector &&that) noexcept : string_vector()
|
||||
{
|
||||
reserve(that.m_size);
|
||||
m_size = that.m_size;
|
||||
for(id_type i = 0; i < that.m_size; ++i)
|
||||
new ((void*)(m_arr+i)) string(std::move(that.m_arr[i]));
|
||||
that.~string_vector();
|
||||
}
|
||||
|
||||
string_vector& operator= (string_vector const& that) RYML_NOEXCEPT
|
||||
{
|
||||
_free();
|
||||
reserve(that.m_size);
|
||||
for(id_type i = 0; i < that.m_size; ++i)
|
||||
m_arr[i].operator=(that.m_arr[i]);
|
||||
m_size = that.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string_vector& operator= (string_vector &&that) noexcept
|
||||
{
|
||||
_free();
|
||||
reserve(that.m_size);
|
||||
for(id_type i = 0; i < that.m_size; ++i)
|
||||
m_arr[i].operator=(std::move(that.m_arr[i]));
|
||||
m_size = that.m_size;
|
||||
that.~string_vector();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void _free()
|
||||
{
|
||||
RYML_ASSERT(m_arr != nullptr); // this structure cannot be memset() to zero
|
||||
for(id_type i = 0; i < m_size; ++i)
|
||||
m_arr[i].~string();
|
||||
if(m_arr != m_buf)
|
||||
{
|
||||
_RYML_CB_FREE(get_callbacks(), m_arr, string, (size_t)m_capacity);
|
||||
m_arr = m_buf;
|
||||
m_capacity = sso_size;
|
||||
}
|
||||
RYML_ASSERT(m_capacity == sso_size);
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
id_type size() const noexcept { return m_size; }
|
||||
id_type capacity() const noexcept { return m_capacity; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
resize(0);
|
||||
}
|
||||
|
||||
void resize(id_type sz)
|
||||
{
|
||||
reserve(sz);
|
||||
if(sz >= m_size)
|
||||
{
|
||||
for(id_type i = m_size; i < sz; ++i)
|
||||
new ((void*)(m_arr + i)) string();
|
||||
}
|
||||
else
|
||||
{
|
||||
for(id_type i = sz; i < m_size; ++i)
|
||||
m_arr[i].~string();
|
||||
}
|
||||
m_size = sz;
|
||||
}
|
||||
|
||||
void reserve(id_type sz)
|
||||
{
|
||||
if(sz <= m_capacity)
|
||||
return;
|
||||
id_type cap = m_capacity < string::sso_size ? string::sso_size : 2 * m_capacity;
|
||||
cap = cap > sz ? cap : sz;
|
||||
if(cap <= sso_size)
|
||||
return;
|
||||
Callbacks cb = get_callbacks();
|
||||
string *buf = (string*) _RYML_CB_ALLOC(cb, string, cap);
|
||||
for(id_type i = 0; i < m_size; ++i)
|
||||
new ((void*)(buf + i)) string(std::move(m_arr[i]));
|
||||
if(m_arr != m_buf)
|
||||
{
|
||||
_RYML_CB_FREE(cb, m_arr, string, m_size);
|
||||
}
|
||||
m_arr = buf;
|
||||
m_capacity = cap;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
string& emplace_back()
|
||||
{
|
||||
RYML_ASSERT(m_size < m_capacity);
|
||||
if(m_size == m_capacity)
|
||||
reserve(m_size + 1);
|
||||
string& ret = m_arr[m_size++];
|
||||
new ((void*)&ret) string();
|
||||
return ret;
|
||||
}
|
||||
string& operator[] (id_type i)
|
||||
{
|
||||
RYML_ASSERT(m_size <= m_capacity);
|
||||
RYML_ASSERT(i < m_size);
|
||||
return m_arr[i];
|
||||
}
|
||||
string const& operator[] (id_type i) const
|
||||
{
|
||||
RYML_ASSERT(m_size <= m_capacity);
|
||||
RYML_ASSERT(i < m_size);
|
||||
return m_arr[i];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace extra
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
|
||||
#endif /* _C4_YML_EXTRA_STRING_HPP_ */
|
||||
@@ -12,15 +12,14 @@ namespace yml {
|
||||
// instantiate the template
|
||||
template class ParseEngine<EventHandlerYamlStd>;
|
||||
|
||||
|
||||
void EventHandlerYamlStd::EventSink::append_escaped(csubstr val)
|
||||
void append_escaped(extra::string *es, csubstr val)
|
||||
{
|
||||
#define _c4flush_use_instead(repl, skip) \
|
||||
do { \
|
||||
this->append(val.range(prev, i)); \
|
||||
this->append(repl); \
|
||||
prev = i + skip; \
|
||||
} \
|
||||
#define _c4flush_use_instead(i, repl, skip) \
|
||||
do { \
|
||||
es->append(val.range(prev, i)); \
|
||||
es->append(repl); \
|
||||
prev = i + skip; \
|
||||
} \
|
||||
while(0)
|
||||
uint8_t const* C4_RESTRICT s = reinterpret_cast<uint8_t const*>(val.str);
|
||||
size_t prev = 0;
|
||||
@@ -29,33 +28,33 @@ void EventHandlerYamlStd::EventSink::append_escaped(csubstr val)
|
||||
switch(s[i])
|
||||
{
|
||||
case UINT8_C(0x0a): // \n
|
||||
_c4flush_use_instead("\\n", 1); break;
|
||||
_c4flush_use_instead(i, "\\n", 1); break;
|
||||
case UINT8_C(0x5c): // '\\'
|
||||
_c4flush_use_instead("\\\\", 1); break;
|
||||
_c4flush_use_instead(i, "\\\\", 1); break;
|
||||
case UINT8_C(0x09): // \t
|
||||
_c4flush_use_instead("\\t", 1); break;
|
||||
_c4flush_use_instead(i, "\\t", 1); break;
|
||||
case UINT8_C(0x0d): // \r
|
||||
_c4flush_use_instead("\\r", 1); break;
|
||||
_c4flush_use_instead(i, "\\r", 1); break;
|
||||
case UINT8_C(0x00): // \0
|
||||
_c4flush_use_instead("\\0", 1); break;
|
||||
_c4flush_use_instead(i, "\\0", 1); break;
|
||||
case UINT8_C(0x0c): // \f (form feed)
|
||||
_c4flush_use_instead("\\f", 1); break;
|
||||
_c4flush_use_instead(i, "\\f", 1); break;
|
||||
case UINT8_C(0x08): // \b (backspace)
|
||||
_c4flush_use_instead("\\b", 1); break;
|
||||
_c4flush_use_instead(i, "\\b", 1); break;
|
||||
case UINT8_C(0x07): // \a (bell)
|
||||
_c4flush_use_instead("\\a", 1); break;
|
||||
_c4flush_use_instead(i, "\\a", 1); break;
|
||||
case UINT8_C(0x0b): // \v (vertical tab)
|
||||
_c4flush_use_instead("\\v", 1); break;
|
||||
_c4flush_use_instead(i, "\\v", 1); break;
|
||||
case UINT8_C(0x1b): // \e (escape)
|
||||
_c4flush_use_instead("\\e", 1); break;
|
||||
_c4flush_use_instead(i, "\\e", 1); break;
|
||||
case UINT8_C(0xc2):
|
||||
if(i+1 < val.len)
|
||||
{
|
||||
const uint8_t np1 = s[i+1];
|
||||
if(np1 == UINT8_C(0xa0))
|
||||
_c4flush_use_instead("\\_", 2);
|
||||
_c4flush_use_instead(i, "\\_", 2);
|
||||
else if(np1 == UINT8_C(0x85))
|
||||
_c4flush_use_instead("\\N", 2);
|
||||
_c4flush_use_instead(i, "\\N", 2);
|
||||
}
|
||||
break;
|
||||
case UINT8_C(0xe2):
|
||||
@@ -64,9 +63,9 @@ void EventHandlerYamlStd::EventSink::append_escaped(csubstr val)
|
||||
if(s[i+1] == UINT8_C(0x80))
|
||||
{
|
||||
if(s[i+2] == UINT8_C(0xa8))
|
||||
_c4flush_use_instead("\\L", 3);
|
||||
_c4flush_use_instead(i, "\\L", 3);
|
||||
else if(s[i+2] == UINT8_C(0xa9))
|
||||
_c4flush_use_instead("\\P", 3);
|
||||
_c4flush_use_instead(i, "\\P", 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#ifndef _C4_YML_EXTRA_STRING_HPP_
|
||||
#include "./string.hpp"
|
||||
#endif
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
|
||||
@@ -28,6 +30,9 @@ namespace yml {
|
||||
/** @addtogroup doc_event_handlers
|
||||
* @{ */
|
||||
|
||||
void append_escaped(extra::string *s, csubstr val);
|
||||
|
||||
|
||||
/** The stack state needed specifically by @ref EventHandlerYamlStd */
|
||||
struct EventHandlerYamlStdState : public ParserState
|
||||
{
|
||||
@@ -53,19 +58,7 @@ struct EventHandlerYamlStd : public EventHandlerStack<EventHandlerYamlStd, Event
|
||||
// our internal state must inherit from parser state
|
||||
using state = EventHandlerYamlStdState;
|
||||
|
||||
struct EventSink
|
||||
{
|
||||
std::string result;
|
||||
void reset() noexcept { result.clear(); }
|
||||
void append(csubstr s) noexcept { result.append(s.str, s.len); }
|
||||
void append(char c) noexcept { result += c; }
|
||||
void insert(csubstr s, size_t pos) noexcept { result.insert(pos, s.str, s.len); }
|
||||
void insert(char c, size_t pos) noexcept { result.insert(pos, 1, c); }
|
||||
csubstr get() const { return csubstr(&result[0], result.size()); }
|
||||
substr get() { return substr(&result[0], result.size()); }
|
||||
size_t find_last(csubstr s) const { return result.rfind(s.str, std::string::npos, s.len); }
|
||||
void append_escaped(csubstr val);
|
||||
};
|
||||
using EventSink = extra::string;
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -73,11 +66,11 @@ public:
|
||||
|
||||
/** @cond dev */
|
||||
EventSink *C4_RESTRICT m_sink;
|
||||
std::vector<EventSink> m_val_buffers;
|
||||
char m_key_tag_buf[256];
|
||||
char m_val_tag_buf[256];
|
||||
extra::string_vector m_val_buffers;
|
||||
extra::string m_key_tag_buf;
|
||||
extra::string m_val_tag_buf;
|
||||
TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES];
|
||||
std::string m_arena;
|
||||
extra::string m_arena;
|
||||
|
||||
// undefined at the end
|
||||
#define _enable_(bits) _enable__<bits>()
|
||||
@@ -90,9 +83,9 @@ public:
|
||||
/** @name construction and resetting
|
||||
* @{ */
|
||||
|
||||
EventHandlerYamlStd() : EventHandlerStack(), m_sink(), m_val_buffers(), m_tag_directives(), m_arena() {}
|
||||
EventHandlerYamlStd(Callbacks const& cb) : EventHandlerStack(cb), m_sink(), m_val_buffers(), m_tag_directives(), m_arena() {}
|
||||
EventHandlerYamlStd(EventSink *sink, Callbacks const& cb) : EventHandlerStack(cb), m_sink(sink), m_val_buffers(), m_tag_directives(), m_arena()
|
||||
EventHandlerYamlStd() : EventHandlerStack(), m_sink(), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_arena() {}
|
||||
EventHandlerYamlStd(Callbacks const& cb) : EventHandlerStack(cb), m_sink(), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_arena() {}
|
||||
EventHandlerYamlStd(EventSink *sink, Callbacks const& cb) : EventHandlerStack(cb), m_sink(sink), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_arena()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@@ -107,6 +100,8 @@ public:
|
||||
m_val_buffers.resize((size_t)m_stack.size());
|
||||
m_arena.clear();
|
||||
m_arena.reserve(1024);
|
||||
m_key_tag_buf.resize(256);
|
||||
m_val_tag_buf.resize(256);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -359,7 +354,7 @@ public:
|
||||
void actually_val_is_first_key_of_new_map_block()
|
||||
{
|
||||
EventSink &sink = _buf_();
|
||||
substr full = sink.get();(void)full;
|
||||
substr full = sink;(void)full;
|
||||
// interpolate +MAP\n after the last +DOC\n
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, full.len);
|
||||
_RYML_CB_ASSERT(m_stack.m_callbacks, !full.count('\r'));
|
||||
@@ -531,13 +526,13 @@ public:
|
||||
{
|
||||
_c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
|
||||
_enable_(KEYTAG);
|
||||
m_curr->ev_data.m_key.tag = _transform_directive(tag, m_key_tag_buf);
|
||||
m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
|
||||
}
|
||||
void set_val_tag(csubstr tag)
|
||||
{
|
||||
_c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
|
||||
_enable_(VALTAG);
|
||||
m_curr->ev_data.m_val.tag = _transform_directive(tag, m_val_tag_buf);
|
||||
m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -568,7 +563,7 @@ public:
|
||||
substr alloc_arena(size_t len)
|
||||
{
|
||||
const size_t sz = m_arena.size();
|
||||
csubstr prev = to_csubstr(m_arena);
|
||||
csubstr prev = m_arena;
|
||||
m_arena.resize(sz + len);
|
||||
substr out = to_substr(m_arena).sub(sz);
|
||||
substr curr = to_substr(m_arena);
|
||||
@@ -579,7 +574,7 @@ public:
|
||||
|
||||
substr alloc_arena(size_t len, substr *relocated)
|
||||
{
|
||||
csubstr prev = to_csubstr(m_arena);
|
||||
csubstr prev = m_arena;
|
||||
if(!prev.is_super(*relocated))
|
||||
return alloc_arena(len);
|
||||
substr out = alloc_arena(len);
|
||||
@@ -601,7 +596,7 @@ public:
|
||||
{
|
||||
_stack_push();
|
||||
_buf_ensure_(m_stack.size() + id_type(1));
|
||||
_buf_().reset();
|
||||
_buf_().clear();
|
||||
m_curr->ev_data = {};
|
||||
_c4dbgpf("pushed! level={}", m_curr->level);
|
||||
}
|
||||
@@ -652,8 +647,8 @@ public:
|
||||
|
||||
static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
|
||||
{
|
||||
dst.append(src.get());
|
||||
src.reset();
|
||||
dst.append(src);
|
||||
src.clear();
|
||||
}
|
||||
|
||||
void _buf_flush_to_(id_type level_src, id_type level_dst) noexcept
|
||||
@@ -753,7 +748,7 @@ public:
|
||||
return i;
|
||||
return RYML_MAX_TAG_DIRECTIVES;
|
||||
}
|
||||
csubstr _transform_directive(csubstr tag, substr output)
|
||||
csubstr _transform_directive(csubstr tag, extra::string *output)
|
||||
{
|
||||
// lookup from the end. We want to find the first directive that
|
||||
// matches the tag and has a target node id leq than the given
|
||||
@@ -765,15 +760,24 @@ public:
|
||||
continue;
|
||||
if(tag.begins_with(td.handle))
|
||||
{
|
||||
size_t len = td.transform(tag, output, m_stack.m_callbacks);
|
||||
bool retry = false;
|
||||
again1:
|
||||
size_t len = td.transform(tag, *output, m_stack.m_callbacks);
|
||||
if(len == 0)
|
||||
{
|
||||
if(tag.begins_with("!<"))
|
||||
return tag.sub(1);
|
||||
return tag;
|
||||
}
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, len <= output.len);
|
||||
return output.first(len);
|
||||
if(len > output->size())
|
||||
{
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !retry);
|
||||
retry = true;
|
||||
output->resize(len);
|
||||
output->resize(output->capacity());
|
||||
goto again1;
|
||||
}
|
||||
return csubstr(*output).first(len);
|
||||
}
|
||||
}
|
||||
if(tag.begins_with('!'))
|
||||
@@ -783,15 +787,23 @@ public:
|
||||
_RYML_CB_ERR_(m_stack.m_callbacks, "tag not found", m_curr->pos);
|
||||
}
|
||||
}
|
||||
csubstr result = normalize_tag_long(tag, output);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, result.len > 0);
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, result.str);
|
||||
bool retry = false;
|
||||
again2:
|
||||
csubstr result = normalize_tag_long(tag, *output);
|
||||
if(!result.str)
|
||||
{
|
||||
_RYML_CB_CHECK(m_stack.m_callbacks, !retry);
|
||||
retry = true;
|
||||
output->resize(result.len);
|
||||
output->resize(output->capacity());
|
||||
goto again2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#undef _enable_
|
||||
#undef _disable_
|
||||
#undef _has_any_
|
||||
#undef _enable_
|
||||
#undef _disable_
|
||||
#undef _has_any_
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
@@ -15,7 +15,8 @@ std::string emit_events_from_source(substr src)
|
||||
EventHandlerYamlStd handler(&sink);
|
||||
ParseEngine<EventHandlerYamlStd> parser(&handler);
|
||||
parser.parse_in_place_ev("(testyaml)", src);
|
||||
return sink.result;
|
||||
csubstr result = sink;
|
||||
return std::string(result.str, result.len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -58,9 +58,12 @@ TEST_P(EventsTest, from_parser)
|
||||
ParseEngine<EventHandlerYamlStd> parser(&handler);
|
||||
std::string src_copy(ec.src.str, ec.src.len);
|
||||
parser.parse_in_place_ev("(testyaml)", to_substr(src_copy));
|
||||
_c4dbgpf("~~~\n{}~~~\n", sink.result);
|
||||
csubstr result = sink;
|
||||
_c4dbgpf("~~~\n{}~~~\n", result);
|
||||
// use the diff from std::string which is nice
|
||||
std::string exp_copy(ec.expected_events_from_parser.str, ec.expected_events_from_parser.len);
|
||||
EXPECT_EQ(sink.result, exp_copy); // use the diff from std::string which is nice
|
||||
std::string result_copy(result.str, result.len);
|
||||
EXPECT_EQ(result_copy, exp_copy);
|
||||
}
|
||||
|
||||
TEST_P(EventsTest, from_tree)
|
||||
|
||||
@@ -118,7 +118,8 @@ std::string emit_events_direct(csubstr filename, substr filecontents)
|
||||
EventHandlerYamlStd handler(&sink, create_custom_callbacks());
|
||||
ParseEngine<EventHandlerYamlStd> parser(&handler);
|
||||
parser.parse_in_place_ev(filename, filecontents);
|
||||
return sink.result;
|
||||
csubstr result = sink;
|
||||
return std::string(result.str, result.len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user