mirror of
https://github.com/biojppm/rapidyaml.git
synced 2026-01-18 21:41:18 +01:00
168 lines
7.1 KiB
C++
168 lines
7.1 KiB
C++
// This file shows a quick example of parsing YAML to an int events
|
|
// buffer. Since this functionality is meant to implement in other
|
|
// programming languages, the code is kept very simple, and using only
|
|
// C-like idioms.
|
|
|
|
// ryml can be used as a single header, or as a simple library:
|
|
#if defined(RYML_SINGLE_HEADER) // using the single header directly in the executable
|
|
#define RYML_SINGLE_HDR_DEFINE_NOW
|
|
#ifndef RYML_SINGLE_HEADER_INTS
|
|
#include <ryml_all.hpp>
|
|
#else
|
|
#include <ryml_ints.hpp>
|
|
#endif
|
|
#elif defined(RYML_SINGLE_HEADER_LIB) // using the single header from a library
|
|
#ifndef RYML_SINGLE_HEADER_INTS
|
|
#include <ryml_all.hpp>
|
|
#else
|
|
#include <ryml_ints.hpp>
|
|
#endif
|
|
#else
|
|
#include <c4/yml/parse_engine.def.hpp>
|
|
#endif
|
|
|
|
#ifndef RYML_SINGLE_HEADER_INTS
|
|
#include <c4/yml/extra/event_handler_ints.hpp>
|
|
#include <c4/yml/extra/ints_utils.hpp> // to print
|
|
#endif
|
|
|
|
|
|
// NOLINTBEGIN(hicpp-signed-bitwise)
|
|
|
|
int main(int, const char *[])
|
|
{
|
|
using namespace c4::yml::extra::ievt;
|
|
auto PSTR_ = c4::yml::extra::ievt::PSTR; // PSTR does not work in windows
|
|
// YAML code to be parsed in place
|
|
char yaml[] = "do: a deer, a female deer\n"
|
|
"re: a drop of golden sun\n"
|
|
"mi: a name I call myself\n"
|
|
"fa: a long long way to run\n";
|
|
// these are the event values we expect
|
|
const int expected_events[] = {
|
|
BSTR,
|
|
BDOC,
|
|
VAL_|BMAP|BLCK,
|
|
//
|
|
KEY_|SCLR|PLAI, 0, 2, // "do"
|
|
VAL_|SCLR|PLAI|PSTR_, 4, 21, // "a deer, a female deer"
|
|
//
|
|
KEY_|SCLR|PLAI|PSTR_, 26, 2, // "re"
|
|
VAL_|SCLR|PLAI|PSTR_, 30, 20, // "a drop of golden sun"
|
|
//
|
|
KEY_|SCLR|PLAI|PSTR_, 51, 2, // "mi"
|
|
VAL_|SCLR|PLAI|PSTR_, 55, 20, // "a name I call myself"
|
|
//
|
|
KEY_|SCLR|PLAI|PSTR_, 76, 2, // "fa"
|
|
VAL_|SCLR|PLAI|PSTR_, 80, 22, // "a long long way to run"
|
|
//
|
|
EMAP|PSTR_,
|
|
EDOC,
|
|
ESTR,
|
|
};
|
|
|
|
/* the output should be this:
|
|
*
|
|
* success! YAML requires event size 30, estimated=49 (required_arena=0 actual=99)
|
|
* pos=0 event[0]: BSTR = 0x00000001
|
|
* pos=1 event[1]: BDOC = 0x00000004
|
|
* pos=2 event[2]: VAL_|BMAP|BLCK = 0x00140010
|
|
* pos=3 event[3]: KEY_|SCLR|PLAI = 0x00081100 str=(0,2) 'do'
|
|
* pos=6 event[4]: VAL_|SCLR|PLAI|PSTR = 0x04101100 str=(4,21) 'a deer, a female deer'
|
|
* pos=9 event[5]: KEY_|SCLR|PLAI|PSTR = 0x04081100 str=(26,2) 're'
|
|
* pos=12 event[6]: VAL_|SCLR|PLAI|PSTR = 0x04101100 str=(30,20) 'a drop of golden sun'
|
|
* pos=15 event[7]: KEY_|SCLR|PLAI|PSTR = 0x04081100 str=(51,2) 'mi'
|
|
* pos=18 event[8]: VAL_|SCLR|PLAI|PSTR = 0x04101100 str=(55,20) 'a name I call myself'
|
|
* pos=21 event[9]: KEY_|SCLR|PLAI|PSTR = 0x04081100 str=(76,2) 'fa'
|
|
* pos=24 event[10]: VAL_|SCLR|PLAI|PSTR = 0x04101100 str=(80,22) 'a long long way to run'
|
|
* pos=27 event[11]: EMAP|PSTR = 0x04000020
|
|
* pos=28 event[12]: EDOC = 0x00000008
|
|
* pos=29 event[13]: ESTR = 0x00000002
|
|
*/
|
|
|
|
// buffer to where we will write the events
|
|
constexpr const int events_size = 100;
|
|
int events[events_size] = {};
|
|
static_assert(events_size >= sizeof(expected_events)/sizeof(expected_events[0]), "buffer too small");
|
|
// buffer for placing any scalars/tags that cannot be filtered
|
|
// in-place
|
|
char arena[100] = {};
|
|
|
|
|
|
// ensure the estimation will succeed vs required size
|
|
int estimated_size = c4::yml::extra::estimate_events_ints_size(yaml);
|
|
if (estimated_size > events_size)
|
|
{
|
|
printf("the estimated size (%d) will not fit the events array (%d)\n", estimated_size, events_size); // LCOV_EXCL_LINE
|
|
return 1; // LCOV_EXCL_LINE
|
|
}
|
|
|
|
// parse now. the parse should succeed (because the YAML above is
|
|
// legit), but if there were would be a parse error, we would get
|
|
// the default behavior which is abort on error, since we did not
|
|
// set up the error callbacks
|
|
c4::yml::extra::EventHandlerInts handler;
|
|
c4::yml::ParseEngine<c4::yml::extra::EventHandlerInts> parser(&handler);
|
|
handler.reset(yaml, arena, events, estimated_size); // note we pass the estimated size!
|
|
parser.parse_in_place_ev("filename", yaml);
|
|
|
|
// the YAML was successfully parsed, but it may happen that it
|
|
// requires more events than may fit in the buffers. so we need to
|
|
// check that it actually fits (this is mandatory):
|
|
if(!handler.fits_buffers())
|
|
{
|
|
printf("error: buffers too small: required_evt=%d actual_evt=%d\n required_arena=%zu actual_arena=%zu\n", // LCOV_EXCL_LINE
|
|
handler.required_size_events(), estimated_size, handler.required_size_arena(), c4::to_csubstr(arena).len); // LCOV_EXCL_LINE
|
|
// WATCHOUT: if you want to retry the parse, you need to set
|
|
// up the source buffer again, because it is invalidated from
|
|
// being parsed in place. refer to the doxygen documentation
|
|
// for more details.
|
|
return 1; // LCOV_EXCL_LINE
|
|
}
|
|
|
|
// done!
|
|
printf("success! YAML requires event size %d, estimated=%d (required_arena=%zu actual_arena=%zu)\n", // LCOV_EXCL_LINE
|
|
handler.required_size_events(), estimated_size, handler.required_size_arena(), c4::to_csubstr(arena).len); // LCOV_EXCL_LINE
|
|
|
|
// ensure the result is as expected
|
|
bool success = true;
|
|
|
|
// example iterating through the events array: compare and print
|
|
// the result
|
|
char flags[100];
|
|
for (int pos = 0, evt = 0; pos < handler.required_size_events(); ++pos, ++evt)
|
|
{
|
|
bool status = (events[pos] == expected_events[pos]);
|
|
// let's format the event flags to print them as string.
|
|
// we need to zero-terminate them to be able to align using printf.
|
|
memset(flags, 0, sizeof(flags)); // ensure flags are zero-terminated
|
|
size_t len = c4::yml::extra::ievt::to_chars(flags, events[pos]);
|
|
if(len + 1 >= sizeof(flags)) { printf("error: could not format flags"); return 1; } // ensure flags are zero-terminated
|
|
// print the event
|
|
printf("pos=%d\tevent[%d]:\t%20s = 0x%08x", pos, evt, flags, events[pos]);
|
|
if(events[pos] & WSTR) // the event has a string following it
|
|
{
|
|
int offset = events[pos + 1];
|
|
int length = events[pos + 2];
|
|
bool in_arena = (events[pos] & AREN);
|
|
// WATCHOUT! the string is NOT ZERO TERMINATED!
|
|
const char *ptr = in_arena ? arena : yaml;
|
|
const char *str = ptr + offset;
|
|
printf("\tstr=(%d,%d)\t'%.*s'", offset, length, length, str);
|
|
status = status && (offset == expected_events[pos + 1]);
|
|
status = status && (length == expected_events[pos + 2]);
|
|
pos += 2; // advance the two ints from the string
|
|
}
|
|
if(!status)
|
|
{
|
|
printf(" ... fail!"); // LCOV_EXCL_LINE
|
|
success = false; // LCOV_EXCL_LINE
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
return success ? 0 : 1;
|
|
}
|
|
|
|
// NOLINTEND(hicpp-signed-bitwise)
|