85#if defined(RYML_SINGLE_HEADER)
86 #define RYML_SINGLE_HDR_DEFINE_NOW
87 #include <ryml_all.hpp>
88#elif defined(RYML_SINGLE_HEADER_LIB)
89 #include <ryml_all.hpp>
101 #include <c4/format_base64.hpp>
171int main(
int argc,
const char* argv[])
227C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
228C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wcast-qual")
229C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wold-style-cast")
230C4_SUPPRESS_WARNING_GCC(
"-Wuseless-cast")
300bool report_check(
int line,
const char *predicate,
bool result);
303#if defined(__DOXYGEN__) || defined(_DOXYGEN_)
305# define CHECK(predicate) assert(predicate)
307# if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
309# define CHECK(predicate) do { if(!report_check(__LINE__, #predicate, (predicate))) { RYML_DEBUG_BREAK(); } } while(0)
311# define CHECK CheckPredicate{__FILE__, __LINE__}
312 struct CheckPredicate
316 void operator() (
bool result)
const
339 char yml_buf[] =
"{foo: 1, bar: [2, 3], john: doe}";
344 CHECK(bar[0].val() ==
"2");
345 CHECK(bar[1].val() ==
"3");
346 CHECK(bar[0].val().str == yml_buf + 15);
347 CHECK(bar[1].val().str == yml_buf + 18);
350 int bar0 = 0, bar1 = 0;
359 CHECK(bar[0].val() ==
"10");
360 CHECK(bar[1].val() ==
"11");
364 CHECK(bar[2].val() ==
"12");
367 std::string expected =
"{foo: 1,bar: [10,11,12],john: doe}";
373 std::cout << tree <<
"\n";
377 expected =
"foo: 1\n";
462 CHECK(tree[
"foo"].is_keyval());
463 CHECK(tree[
"foo"].val() ==
"1");
464 CHECK(tree[
"foo"].key() ==
"foo");
465 CHECK(tree[
"bar"].is_seq());
466 CHECK(tree[
"bar"].has_key());
467 CHECK(tree[
"bar"].key() ==
"bar");
469 CHECK(tree[
"bar"][0].val() ==
"2");
470 CHECK(tree[
"bar"][1].val() ==
"3");
471 CHECK(tree[
"john"].val() ==
"doe");
475 CHECK(tree[0].
id() == tree[
"foo"].
id());
476 CHECK(tree[1].
id() == tree[
"bar"].
id());
477 CHECK(tree[2].
id() == tree[
"john"].
id());
479 CHECK(tree[0].
id() == tree[
"foo"].
id());
480 CHECK(tree[1].
id() == tree[
"bar"].
id());
481 CHECK(tree[2].
id() == tree[
"john"].
id());
483 CHECK(bar[0].val() ==
"2");
484 CHECK(bar[1].val() ==
"3");
489 CHECK(tree[
"foo"].key() ==
"foo");
490 CHECK(tree[
"bar"].key() ==
"bar");
491 CHECK(tree[
"john"].key() ==
"john");
496 CHECK(root[
"foo"].
id() == root[0].
id());
497 CHECK(root[
"bar"].
id() == root[1].
id());
498 CHECK(root[
"john"].
id() == root[2].
id());
557 CHECK(child.key() == expected_keys[count++]);
563 CHECK(child.key() == expected_keys[count++]);
569 CHECK(tree.
key(child_id) == expected_keys[count++]);
578 CHECK(tree.
key(child_id) == expected_keys[count++]);
638 int foo = 0, bar0 = 0, bar1 = 0;
639 std::string john_str;
642 root[
"bar"][0] >> bar0;
643 root[
"bar"][1] >> bar1;
644 root[
"john"] >> john_str;
649 CHECK(john_str ==
"doe");
650 CHECK(bar_str ==
"bar");
667 wroot[
"foo"] =
"says you";
668 wroot[
"bar"][0] =
"-2";
669 wroot[
"bar"][1] =
"-3";
670 wroot[
"john"] =
"ron";
674 CHECK(root[
"foo"].val() ==
"says you");
675 CHECK(root[
"bar"][0].val() ==
"-2");
676 CHECK(root[
"bar"][1].val() ==
"-3");
677 CHECK(root[
"john"].val() ==
"ron");
692 wroot[
"foo"] <<
"says who";
693 wroot[
"bar"][0] << 20;
694 wroot[
"bar"][1] << 30;
695 wroot[
"john"] <<
"deere";
696 CHECK(root[
"foo"].val() ==
"says who");
697 CHECK(root[
"bar"][0].val() ==
"20");
698 CHECK(root[
"bar"][1].val() ==
"30");
699 CHECK(root[
"john"].val() ==
"deere");
703 std::string ok(
"in_scope");
707 CHECK(root[
"john"].val() ==
"in_scope");
709 wroot[
"float"] << 2.4f;
713 CHECK(tree.
arena() ==
"says who2030deerein_scope2.42.400000");
721 wroot[
"newkeyval"] =
"shiny and new";
724 CHECK(root[
"newkeyval"].key() ==
"newkeyval");
725 CHECK(root[
"newkeyval"].val() ==
"shiny and new");
726 CHECK(root[
"newkeyval (serialized)"].key() ==
"newkeyval (serialized)");
727 CHECK(root[
"newkeyval (serialized)"].val() ==
"shiny and new (serialized)");
733 CHECK(root[
"bar"].num_children() == 2);
734 wroot[
"bar"][2] =
"oh so nice";
735 wroot[
"bar"][3] <<
"oh so nice (serialized)";
736 CHECK(root[
"bar"].num_children() == 4);
737 CHECK(root[
"bar"][2].val() ==
"oh so nice");
738 CHECK(root[
"bar"][3].val() ==
"oh so nice (serialized)");
744 CHECK(root[
"newseq"].num_children() == 0);
745 CHECK(root[
"newseq"].is_seq());
746 CHECK(root[
"newseq (serialized)"].num_children() == 0);
747 CHECK(root[
"newseq (serialized)"].is_seq());
753 CHECK(root[
"newmap"].num_children() == 0);
754 CHECK(root[
"newmap"].is_map());
755 CHECK(root[
"newmap (serialized)"].num_children() == 0);
756 CHECK(root[
"newmap (serialized)"].is_map());
789 nothing = wroot[
"I am nothing"];
804 something =
"indeed";
806 CHECK(root[
"I am something"].val() ==
"indeed");
837 CHECK(wbar[0].readable() && wbar[0].val() ==
"20");
838 CHECK( ! wbar[100].readable());
839 CHECK( ! wbar[100].readable() || wbar[100].val() ==
"100");
841 CHECK( ! wbar[0].is_seed() && wbar[0].val() ==
"20");
842 CHECK(wbar[100].is_seed() || wbar[100].val() ==
"100");
870 return seed_node.at(
"is").at(
"an").at(
"invalid").at(
"operation");
877 return seed_node[
"is"][
"an"][
"invalid"][
"operation"];
889 "bar: [20,30,oh so nice,oh so nice (serialized)]" "\n"
890 "john: in_scope" "\n"
892 "digits: 2.400000" "\n"
893 "newkeyval: shiny and new" "\n"
894 "newkeyval (serialized): shiny and new (serialized)" "\n"
896 "newseq (serialized): []" "\n"
898 "newmap (serialized): {}" "\n"
899 "I am something: indeed" "\n"
908 std::stringstream ss;
910 std::string stream_result = ss.str();
917 CHECK(buf_result == expected_result);
918 CHECK(str_result == expected_result);
919 CHECK(stream_result == expected_result);
935 CHECK(tree[
"bar"][0].val() ==
"21");
937 CHECK(tree[
"bar"][0].val() ==
"22");
943 constnoderef = noderef;
949 noderef = tree[
"bar"][0];
950 constnoderef = consttree[
"bar"][0];
954 CHECK(constnoderef == noderef);
955 CHECK(!(constnoderef != noderef));
965 ryml::Tree tree2 = parse_in_arena(&parser,
"expected.yml", expected_result);
980 "# UTF8/16/32 can be placed directly in any scalar:" "\n"
982 "en: Planet (Gas)" "\n"
983 "fr: Planète (Gazeuse)" "\n"
984 "ru: Планета (Газ)" "\n"
988 "# UTF8 decoding only happens in double-quoted strings," "\n"
989 "# as per the YAML standard" "\n"
991 "decode this: \"\\u263A c\\x61f\\xE9\"" "\n"
992 "and this as well: \"\\u2705 \\U0001D11E\"" "\n"
993 "not decoded: '\\u263A \\xE2\\x98\\xBA'" "\n"
994 "neither this: '\\u2705 \\U0001D11E'" "\n");
996 CHECK(langs[
"en"].val() ==
"Planet (Gas)");
997 CHECK(langs[
"fr"].val() ==
"Planète (Gazeuse)");
998 CHECK(langs[
"ru"].val() ==
"Планета (Газ)");
999 CHECK(langs[
"ja"].val() ==
"惑星(ガス)");
1000 CHECK(langs[
"zh"].val() ==
"行星(气体)");
1004 CHECK(langs[
"decode this"].val() ==
"☺ café");
1005 CHECK(langs[
"and this as well"].val() ==
"✅ 𝄞");
1006 CHECK(langs[
"not decoded"].val() ==
"\\u263A \\xE2\\x98\\xBA");
1007 CHECK(langs[
"neither this"].val() ==
"\\u2705 \\U0001D11E");
1035 const char foobar_str[] =
"foobar";
1037 CHECK(s ==
"foobar");
1038 CHECK(s.size() == 6);
1039 CHECK(s.data() == foobar_str);
1040 CHECK(s.size() == s.len);
1041 CHECK(s.data() == s.str);
1046 const char foobar_str[] =
"foobar";
1048 CHECK(s ==
"foobar");
1049 CHECK(s !=
"foobar0");
1058 CHECK(s ==
"foobar");
1059 CHECK(s !=
"foobar0");
1071 const char *foobar_str =
"foobar";
1073 CHECK(s ==
"foobar");
1074 CHECK(s !=
"foobar0");
1088 std::string foobar_str =
"foobar";
1090 CHECK(s ==
"foobar");
1091 CHECK(s !=
"foobar0");
1113 char const foobar_str_ro[] =
"foobar";
1114 char foobar_str_rw[] =
"foobar";
1115 static_assert(std::is_array<
decltype(foobar_str_ro)>::value,
"this is an array");
1116 static_assert(std::is_array<
decltype(foobar_str_rw)>::value,
"this is an array");
1121 CHECK(foobar.
size() == strlen(foobar_str_ro));
1122 CHECK(foobar ==
"foobar");
1128 CHECK(foobar.
size() == strlen(foobar_str_rw));
1129 CHECK(foobar ==
"foobar");
1135 CHECK(foobar.
size() == strlen(foobar_str_rw));
1136 CHECK(foobar ==
"foobar");
1147 char const* foobar_str_ro =
"foobar";
1148 char foobar_str_rw_[] =
"foobar";
1149 char * foobar_str_rw = foobar_str_rw_;
1150 static_assert(!std::is_array<
decltype(foobar_str_ro)>::value,
"this is a decayed pointer");
1151 static_assert(!std::is_array<
decltype(foobar_str_rw)>::value,
"this is a decayed pointer");
1157 CHECK(foobar.
size() == strlen(foobar_str_ro));
1158 CHECK(foobar ==
"foobar");
1164 CHECK(foobar.
size() == strlen(foobar_str_rw));
1165 CHECK(foobar ==
"foobar");
1171 CHECK(foobar.
size() == strlen(foobar_str_rw));
1172 CHECK(foobar ==
"foobar");
1182 char buf[] =
"foobar";
1184 CHECK(foobar ==
"foobar");
1185 foobar[0] =
'F';
CHECK(foobar ==
"Foobar");
1186 foobar.
back() =
'R';
CHECK(foobar ==
"FoobaR");
1198 foobar.
fill(
'.');
CHECK(foobar ==
"......");
1210 CHECK(s.
sub(0, 12) ==
"fooFOObarBAR");
1270 CHECK(some ==
"some");
1271 CHECK(s ==
"some substring");
1274 char result[32] = {0};
1275 std::snprintf(result,
sizeof(result),
"%.*s", (
int)some.
len, some.
str);
1276 printf(
"~~~%s~~~\n", result);
1286 char result[32] = {0};
1287 std::snprintf(result,
sizeof(result),
"%s", some.
str);
1297 CHECK(some ==
"some");
1298 CHECK(s ==
"some substring");
1301 std::stringstream ss;
1303 CHECK(ss.str() ==
"some substring");
1304 CHECK(ss.str() == s);
1312 std::stringstream ss;
1314 CHECK(ss.str() ==
"some substring");
1315 CHECK(ss.str() == s);
1319 std::stringstream ss;
1321 CHECK(ss.str() ==
"some substring");
1322 CHECK(ss.str() == s);
1326 std::stringstream ss;
1328 CHECK(ss.str() ==
"some");
1329 CHECK(ss.str() == some);
1366 CHECK(
ryml::csubstr(
" \t\n\rcontents without whitespace\t \n\r").trim(
"\t \n\r") ==
"contents without whitespace");
1387 CHECK(aaa___bbb.
trim (
'c') == aaa___bbb);
1406 CHECK(aaa___bbb.
trim (
"cd") == aaa___bbb);
1411 CHECK(
ryml::csubstr(
"'this is is single quoted'" ).unquoted() ==
"this is is single quoted");
1412 CHECK(
ryml::csubstr(
"\"this is is double quoted\"").unquoted() ==
"this is is double quoted");
1730 CHECK(
ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extshort() ==
"/path/to/file.tar");
1736 using namespace ryml;
1737 csubstr parts[] = {
"aa",
"bb",
"cc",
"dd",
"ee",
"ff"};
1741 CHECK(part == parts[count++]);
1747 CHECK(part == parts[count++]);
1753 CHECK(part == parts[count++]);
1762 const bool skip_empty =
true;
1835 const char filename[] =
"ryml_example.yml";
1836 std::string yaml =
""
1850 CHECK(tree[
"foo"].val() ==
"1");
1851 CHECK(tree[
"bar"][0].val() ==
"2");
1852 CHECK(tree[
"bar"][1].val() ==
"3");
1859 CHECK(tree[
"foo"].val() ==
"1");
1860 CHECK(tree[
"bar"][0].val() ==
"2");
1861 CHECK(tree[
"bar"][1].val() ==
"3");
1882 char src[] =
"{foo: 1, bar: [2, 3]}";
1888 CHECK(root[
"foo"].is_keyval());
1890 CHECK(root[
"foo"].val() ==
"1");
1891 CHECK(root[
"bar"].is_seq());
1892 CHECK(root[
"bar"].has_key());
1894 CHECK(root[
"bar"][0].val() ==
"2");
1895 CHECK(root[
"bar"][1].val() ==
"3");
1898 int foo = 0, bar0 = 0, bar1 = 0;
1900 root[
"bar"][0] >> bar0;
1901 root[
"bar"][1] >> bar1;
1907 CHECK(root[
"foo"].val().data() == src + strlen(
"{foo: "));
1908 CHECK(root[
"foo"].val().begin() == src + strlen(
"{foo: "));
1909 CHECK(root[
"foo"].val().end() == src + strlen(
"{foo: 1"));
1910 CHECK(root[
"foo"].val().is_sub(srcview));
1911 CHECK(root[
"bar"][0].val().data() == src + strlen(
"{foo: 1, bar: ["));
1912 CHECK(root[
"bar"][0].val().begin() == src + strlen(
"{foo: 1, bar: ["));
1913 CHECK(root[
"bar"][0].val().end() == src + strlen(
"{foo: 1, bar: [2"));
1914 CHECK(root[
"bar"][0].val().is_sub(srcview));
1915 CHECK(root[
"bar"][1].val().data() == src + strlen(
"{foo: 1, bar: [2, "));
1916 CHECK(root[
"bar"][1].val().begin() == src + strlen(
"{foo: 1, bar: [2, "));
1917 CHECK(root[
"bar"][1].val().end() == src + strlen(
"{foo: 1, bar: [2, 3"));
1918 CHECK(root[
"bar"][1].val().is_sub(srcview));
1940 CHECK(root[
"foo"].is_keyval());
1942 CHECK(root[
"foo"].val() ==
"1");
1943 CHECK(root[
"bar"].is_seq());
1944 CHECK(root[
"bar"].has_key());
1946 CHECK(root[
"bar"][0].val() ==
"2");
1947 CHECK(root[
"bar"][1].val() ==
"3");
1950 int foo = 0, bar0 = 0, bar1 = 0;
1952 root[
"bar"][0] >> bar0;
1953 root[
"bar"][1] >> bar1;
1961 char src[] =
"{foo: is it really true}";
1970 CHECK(tree[
"foo"].val() ==
"is it really true");
1998 CHECK(root[
"foo"].is_keyval());
2000 CHECK(root[
"foo"].val() ==
"1");
2001 CHECK(root[
"bar"].is_seq());
2002 CHECK(root[
"bar"].has_key());
2004 CHECK(root[
"bar"][0].val() ==
"2");
2005 CHECK(root[
"bar"][1].val() ==
"3");
2014 "bar2: [22,32]" "\n"
2017 CHECK(root[
"foo2"].is_keyval());
2018 CHECK(root[
"foo2"].
key() ==
"foo2");
2019 CHECK(root[
"foo2"].val() ==
"12");
2020 CHECK(root[
"bar2"].is_seq());
2021 CHECK(root[
"bar2"].has_key());
2022 CHECK(root[
"bar2"].
key() ==
"bar2");
2023 CHECK(root[
"bar2"][0].val() ==
"22");
2024 CHECK(root[
"bar2"][1].val() ==
"32");
2033 CHECK(root[0].val() ==
"a");
2034 CHECK(root[1].val() ==
"b");
2035 CHECK(root[2].is_map());
2036 CHECK(root[2][
"x0"].val() ==
"1");
2037 CHECK(root[2][
"x1"].val() ==
"2");
2045 "- {x0: 1,x1: 2}" "\n"
2046 "- champagne: Dom Perignon" "\n"
2047 " coffee: Arabica" "\n"
2050 CHECK(root[0].val() ==
"a");
2051 CHECK(root[1].val() ==
"b");
2052 CHECK(root[2].is_map());
2053 CHECK(root[2][
"x0"].val() ==
"1");
2054 CHECK(root[2][
"x1"].val() ==
"2");
2055 CHECK(root[3].is_map());
2056 CHECK(root[3][
"champagne"].val() ==
"Dom Perignon");
2057 CHECK(root[3][
"coffee"].val() ==
"Arabica");
2070 "- {x0: 1,x1: 2}" "\n"
2071 "- champagne: Dom Perignon" "\n"
2072 " coffee: Arabica" "\n"
2075 " vinho verde: Soalheiro" "\n"
2076 " vinho tinto: Redoma 2017" "\n"
2078 " - Rochefort 10" "\n"
2080 " - Leffe Rituel" "\n"
2081 " always: lots of water" "\n"
2089 "- {x0: 1,x1: 2}" "\n"
2090 "- champagne: Dom Perignon" "\n"
2091 " coffee: Arabica" "\n"
2093 " vinho verde: Soalheiro" "\n"
2094 " vinho tinto: Redoma 2017" "\n"
2096 " - Rochefort 10" "\n"
2098 " - Leffe Rituel" "\n"
2099 " always: lots of water" "\n"
2112 "- {x0: 1,x1: 2}" "\n"
2113 "- champagne: Dom Perignon" "\n"
2114 " coffee: Arabica" "\n"
2116 " vinho verde: Soalheiro" "\n"
2117 " vinho tinto: Redoma 2017" "\n"
2119 " - Rochefort 10" "\n"
2121 " - Leffe Rituel" "\n"
2122 " - Kasteel Donker" "\n"
2123 " always: lots of water" "\n"
2151 ryml::csubstr yaml =
"[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]";
2155 yaml =
"[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]";
2189 "- Gosset Grande Reserve\n"
2190 "- Jacquesson 742\n"
2196 "- Kasteel Donker\n"
2200 "- Niepoort Redoma 2017\n"
2201 "- Vina Esmeralda\n"
2211 "- Gosset Grande Reserve\n"
2212 "- Jacquesson 742\n"
2216 "- Kasteel Donker\n"
2224 "- Niepoort Redoma 2017\n"
2225 "- Vina Esmeralda\n"
2239 "doe: a deer, a female deer" "\n"
2240 "ray: a drop of golden sun" "\n"
2243 "french-hens: 3" "\n"
2244 "calling-birds:" "\n"
2249 "xmas-fifth-day:" "\n"
2250 " calling-birds: four" "\n"
2251 " french-hens: 3" "\n"
2252 " golden-rings: 5" "\n"
2255 " location: a pear tree" "\n"
2256 " turtle-doves: two" "\n"
2263 std::vector<ryml::csubstr> keys, vals;
2266 keys.emplace_back(n.key());
2269 CHECK(keys.size() >= 6);
2270 CHECK(vals.size() >= 6);
2271 if(keys.size() >= 6 && vals.size() >= 6)
2273 CHECK(keys[0] ==
"doe");
2274 CHECK(vals[0] ==
"a deer, a female deer");
2275 CHECK(keys[1] ==
"ray");
2276 CHECK(vals[1] ==
"a drop of golden sun");
2277 CHECK(keys[2] ==
"pi");
2278 CHECK(vals[2] ==
"3.14159");
2279 CHECK(keys[3] ==
"xmas");
2280 CHECK(vals[3] ==
"true");
2281 CHECK(root[5].has_key());
2282 CHECK(root[5].is_seq());
2283 CHECK(root[5].
key() ==
"calling-birds");
2284 CHECK(!root[5].has_val());
2286 CHECK(keys[5] ==
"calling-birds");
2287 CHECK(vals[5] ==
"");
2294 ryml::csubstr calling_birds[] = {
"huey",
"dewey",
"louie",
"fred"};
2296 CHECK(n.val() == calling_birds[count++]);
2321 const char a_deer[] =
"a deer, a female deer";
2330 std::string a_drop =
"a drop of golden sun";
2333 root[
"ray"] << a_drop;
2339 CHECK(root[
"ray"].val() ==
"a drop of golden sun");
2342 root[
"pi"] << ryml::fmt::real(3.141592654, 5);
2343 root[
"xmas"] << ryml::fmt::boolalpha(
true);
2344 root[
"french-hens"] << 3;
2353 xmas5[
"calling-birds"] =
"four";
2354 xmas5[
"french-hens"] << 3;
2355 xmas5[
"golden-rings"] << 5;
2357 xmas5[
"partridges"][
"count"] << 1;
2358 xmas5[
"partridges"][
"location"] =
"a pear tree";
2359 xmas5[
"turtle-doves"] =
"two";
2360 root[
"cars"] =
"GTO";
2363 "doe: a deer, a female deer" "\n"
2364 "ray: a drop of golden sun" "\n"
2367 "french-hens: 3" "\n"
2368 "calling-birds:" "\n"
2373 "xmas-fifth-day:" "\n"
2374 " calling-birds: four" "\n"
2375 " french-hens: 3" "\n"
2376 " golden-rings: 5" "\n"
2379 " location: a pear tree" "\n"
2380 " turtle-doves: two" "\n"
2394 char buf[] =
"[a, b, c, d]";
2424 CHECK(root[0].val().is_sub(arena));
2425 CHECK(root[1].val().is_sub(arena));
2426 CHECK(root[2].val().is_sub(arena));
2427 CHECK(root[3].val().is_sub(arena));
2437 char buf[] =
"[a, b, c, d]";
2445 CHECK(root[2].val() ==
"c");
2448 CHECK(root[2].val() ==
"12345");
2454 CHECK(root[3].val() ==
"d");
2457 CHECK(root[3].val() ==
"67890");
2473 CHECK(root[2].val() ==
"c");
2475 CHECK(root[2].val() ==
"12345");
2484 CHECK(root[3].val() ==
"67890");
2488 CHECK(tree.
arena() ==
"[a, b, c, d]1234567890");
2496 CHECK(c10 ==
"10101010");
2506 CHECK(root[
"a"].val() ==
"2222");
2516 CHECK(copied == mystr);
2517 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2526 memcpy(copied.
str, mystr.
str, mystr.
len);
2527 CHECK(copied == mystr);
2528 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2577 CHECK(tree.
to_arena(
double(0.234)) ==
"0.234");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.234");
2587 const float fnan = std::numeric_limits<float >::quiet_NaN();
2588 const double dnan = std::numeric_limits<double>::quiet_NaN();
2589 const float finf = std::numeric_limits<float >::infinity();
2590 const double dinf = std::numeric_limits<double>::infinity();
2591 CHECK(tree.
to_arena( finf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf");
2592 CHECK(tree.
to_arena( dinf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf");
2593 CHECK(tree.
to_arena(-finf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf");
2594 CHECK(tree.
to_arena(-dinf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf");
2595 CHECK(tree.
to_arena( fnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan");
2596 CHECK(tree.
to_arena( dnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan.nan");
2600 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
2606 tree[
"ninf"] >> f;
CHECK(f == -finf);
2607 tree[
"ninf"] >> d;
CHECK(d == -dinf);
2608 tree[
"pinf"] >> f;
CHECK(f == finf);
2609 tree[
"pinf"] >> d;
CHECK(d == dinf);
2610 tree[
"nan" ] >> f;
CHECK(std::isnan(f));
2611 tree[
"nan" ] >> d;
CHECK(std::isnan(d));
2612 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2625 t[
"val"] >> valu8;
CHECK(valu8 == 2);
2626 t[
"val"] >> vali8;
CHECK(vali8 == 2);
2633 auto checku8 = ryml::fmt::overflow_checked(valu8);
2634 t[
"val"] >> checku8;
2637 auto checki8 = ryml::fmt::overflow_checked(vali8);
2638 t[
"val"] >> checki8;
2654 "dquoted: \"\"" "\n"
2657 "all_null: [~, null, Null, NULL]" "\n"
2658 "non_null: [nULL, non_null, non null, null it is not]" "\n"
2662 CHECK(tree[
"plain"].has_val());
2663 CHECK(tree[
"squoted"].has_val());
2664 CHECK(tree[
"dquoted"].has_val());
2665 CHECK(tree[
"literal"].has_val());
2666 CHECK(tree[
"folded"].has_val());
2667 CHECK( ! tree[
"all_null"].has_val());
2668 CHECK( ! tree[
"non_null"].has_val());
2670 CHECK( ! tree[
"plain"].is_container());
2671 CHECK( ! tree[
"squoted"].is_container());
2672 CHECK( ! tree[
"dquoted"].is_container());
2673 CHECK( ! tree[
"literal"].is_container());
2674 CHECK( ! tree[
"folded"].is_container());
2675 CHECK(tree[
"all_null"].is_container());
2676 CHECK(tree[
"non_null"].is_container());
2681 CHECK(tree[
"plain"].val().len == 0);
2682 CHECK(tree[
"squoted"].val().len == 0);
2683 CHECK(tree[
"dquoted"].val().len == 0);
2684 CHECK(tree[
"literal"].val().len == 0);
2685 CHECK(tree[
"folded"].val().len == 0);
2687 CHECK(tree[
"plain"].val().str ==
nullptr);
2688 CHECK(tree[
"squoted"].val().str !=
nullptr);
2689 CHECK(tree[
"dquoted"].val().str !=
nullptr);
2690 CHECK(tree[
"literal"].val().str !=
nullptr);
2691 CHECK(tree[
"folded"].val().str !=
nullptr);
2695 CHECK(tree[
"plain"].val() ==
nullptr);
2696 CHECK(tree[
"squoted"].val() !=
nullptr);
2697 CHECK(tree[
"dquoted"].val() !=
nullptr);
2698 CHECK(tree[
"literal"].val() !=
nullptr);
2699 CHECK(tree[
"folded"].val() !=
nullptr);
2704 CHECK(tree[
"plain"].val_is_null());
2705 CHECK( ! tree[
"squoted"].val_is_null());
2706 CHECK( ! tree[
"dquoted"].val_is_null());
2707 CHECK( ! tree[
"literal"].val_is_null());
2708 CHECK( ! tree[
"folded"].val_is_null());
2713 CHECK(child.val() !=
nullptr);
2714 CHECK(child.val_is_null());
2718 CHECK(child.val() !=
nullptr);
2719 CHECK( ! child.val_is_null());
2734 CHECK(null .len == 0);
CHECK(null .str ==
nullptr);
CHECK(null ==
nullptr);
2737 CHECK(tilde .len != 0);
CHECK(tilde .str !=
nullptr);
CHECK(tilde !=
nullptr);
2742 tree[
"empty_null"] << null;
CHECK(tree.
arena() ==
"");
2744 tree[
"empty_nonnull"] << nonnull;
CHECK(tree.
arena() ==
"");
2746 tree[
"str_null"] << strnull;
CHECK(tree.
arena() ==
"null");
2748 tree[
"str_tilde"] << tilde;
CHECK(tree.
arena() ==
"null~");
2752 "empty_nonnull: ''" "\n"
2753 "str_null: null" "\n"
2762 return s.str ==
nullptr ?
"null" : s;
2764 tree[
"empty_null"] << null_if_nullptr(null);
2765 tree[
"empty_nonnull"] << null_if_nullptr(nonnull);
2766 tree[
"str_null"] << null_if_nullptr(strnull);
2767 tree[
"str_tilde"] << null_if_nullptr(tilde);
2770 "empty_null: null" "\n"
2771 "empty_nonnull: ''" "\n"
2772 "str_null: null" "\n"
2781 tree[
"empty_null"] << null_if_predicate(null);
2782 tree[
"empty_nonnull"] << null_if_predicate(nonnull);
2783 tree[
"str_null"] << null_if_predicate(strnull);
2784 tree[
"str_tilde"] << null_if_predicate(tilde);
2787 "empty_null: null" "\n"
2788 "empty_nonnull: ''" "\n"
2789 "str_null: null" "\n"
2790 "str_tilde: null" "\n"
2798 tree[
"empty_null"] << tilde_if_predicate(null);
2799 tree[
"empty_nonnull"] << tilde_if_predicate(nonnull);
2800 tree[
"str_null"] << tilde_if_predicate(strnull);
2801 tree[
"str_tilde"] << tilde_if_predicate(tilde);
2804 "empty_null: ~" "\n"
2805 "empty_nonnull: ''" "\n"
2823 char buf_[256] = {};
2825 size_t size =
ryml::format(buf,
"a={} foo {} {} bar {}", 0.1, 10, 11, 12);
2826 CHECK(size == strlen(
"a=0.1 foo 10 11 bar 12"));
2827 CHECK(buf.
first(size) ==
"a=0.1 foo 10 11 bar 12");
2830 size =
ryml::format({} ,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12);
2831 CHECK(size ==
ryml::format(buf,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12));
2832 CHECK(size == strlen(
"a=this_is_a foo 10 11 bar 12"));
2834 char smallbuf[8] = {};
2835 size =
ryml::format(smallbuf,
"{} is too large {}",
"this",
"for the buffer");
2836 CHECK(size == strlen(
"this is too large for the buffer"));
2842 CHECK(result ==
"b=1, damn it.");
2861 CHECK(sbuf ==
"and c=2 seems about right");
2862 std::vector<char> vbuf;
2864 CHECK(sbuf ==
"and c=2 seems about right");
2867 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2874 int a = 0, b = 1, c = 2;
2876 CHECK(result ==
"0 and 1 and 2");
2877 int aa = -1, bb = -2, cc = -3;
2878 size_t num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2886 CHECK(result ==
"10 and 20 and 30");
2887 num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2897 char buf_[256] = {};
2899 size_t size =
ryml::cat(buf,
"a=", 0.1,
"foo", 10, 11,
"bar", 12);
2900 CHECK(size == strlen(
"a=0.1foo1011bar12"));
2901 CHECK(buf.
first(size) ==
"a=0.1foo1011bar12");
2906 char smallbuf[8] = {};
2907 size =
ryml::cat(smallbuf,
"this",
" is too large ",
"for the buffer");
2908 CHECK(size == strlen(
"this is too large for the buffer"));
2914 CHECK(result ==
"b=1, damn it.");
2932 ryml::catrs(&sbuf,
"and c=", 2,
" seems about right");
2933 CHECK(sbuf ==
"and c=2 seems about right");
2934 std::vector<char> vbuf;
2935 ryml::catrs(&vbuf,
"and c=", 2,
" seems about right");
2936 CHECK(sbuf ==
"and c=2 seems about right");
2939 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2946 int a = 0, b = 1, c = 2;
2948 CHECK(result ==
"0 1 2");
2949 int aa = -1, bb = -2, cc = -3;
2950 char sep1 =
'a', sep2 =
'b';
2951 size_t num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2960 CHECK(result ==
"10 20 30");
2961 num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2972 char buf_[256] = {};
2975 size_t size =
ryml::catsep(buf,
' ',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2976 CHECK(buf.
first(size) ==
"a= 0 b= 1 c= 2 45 67");
2979 size =
ryml::catsep(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2980 CHECK(buf.
first(size) ==
"a=0 and b=1 and c=2 and 45 and 67");
2982 size =
ryml::catsep(buf,
" ... ",
"a=0",
"b=1",
"c=2", 45, 67);
2983 CHECK(buf.
first(size) ==
"a=0 ... b=1 ... c=2 ... 45 ... 67");
2985 size =
ryml::catsep(buf,
'/',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2986 CHECK(buf.
first(size) ==
"a=/0/b=/1/c=/2/45/67");
2988 size =
ryml::catsep(buf, 888,
"a=0",
"b=1",
"c=2", 45, 67);
2989 CHECK(buf.
first(size) ==
"a=0888b=1888c=28884588867");
2995 char smallbuf[8] = {};
2997 CHECK(size == strlen(
"a=0888b=1888c=28884588867"));
3003 CHECK(result ==
"a=0 and b=1 and c=2 and 45 and 67");
3022 CHECK(sbuf ==
"a=0 and b=1 and c=2 and 45 and 67");
3023 std::vector<char> vbuf;
3029 CHECK(sbuf ==
"a=0 and b=1 and c=2 and 45 and 67 --- a=0 well b=11 well c=12 well 145 well 167");
3034 char buf_[256] = {};
3036 int a = 0, b = 1, c = 2;
3038 CHECK(result ==
"0 1 2");
3039 int aa = -1, bb = -2, cc = -3;
3047 CHECK(result ==
"10--20--30");
3057 using namespace ryml;
3058 char buf_[256] = {};
3077 CHECK(
"3735928559" ==
cat_sub(buf, UINT32_C(0xdeadbeef)));
3201 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wcast-align")
3202 const uint32_t payload[] = {10, 20, 30, 40, UINT32_C(0xdeadbeef)};
3204 csubstr expected =
csubstr((
const char *)payload,
sizeof(payload));
3209 for(
const uint32_t value : payload)
3212 expected =
csubstr((
const char *)&value,
sizeof(value));
3214 CHECK(actual.
size() ==
sizeof(uint32_t));
3219 CHECK(actual.
size() ==
sizeof(uint32_t));
3224 uint32_t result = 0;
3229 CHECK(result == value);
3231 C4_SUPPRESS_WARNING_GCC_CLANG_POP
3251 text_and_base64 cases[] = {
3252 {{
"Hello, World!"}, {
"SGVsbG8sIFdvcmxkIQ=="}},
3253 {{
"Brevity is the soul of wit."}, {
"QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu"}},
3254 {{
"All that glitters is not gold."}, {
"QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu"}},
3257 for(text_and_base64 c : cases)
3258 tree[c.text] << ryml::fmt::base64(c.text);
3260 for(text_and_base64 c : cases)
3263 for(text_and_base64 c : cases)
3265 CHECK(tree[c.text].
val() == c.base64);
3266 CHECK(tree[c.base64].
val() == c.text);
3270 "Hello, World!: SGVsbG8sIFdvcmxkIQ==" "\n"
3271 "Brevity is the soul of wit.: QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu" "\n"
3272 "All that glitters is not gold.: QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu" "\n"
3274 "SGVsbG8sIFdvcmxkIQ==: Hello, World!" "\n"
3275 "QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu: Brevity is the soul of wit." "\n"
3276 "QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu: All that glitters is not gold." "\n"
3278 char buf1_[128], buf2_[128];
3282 for(
const text_and_base64 c : cases)
3287 tree[c.text] >> ryml::fmt::base64(buf1, &len);
3296 CHECK(c.text.len == len);
3299 tree[c.base64] >>
ryml::key(ryml::fmt::base64(buf2, &len));
3305 tree[c.text] >> ryml::fmt::base64(result);
3306 CHECK(result == c.text);
3308 tree[c.base64] >>
ryml::key(ryml::fmt::base64(result));
3309 CHECK(result == c.text);
3313 const uint64_t valin = UINT64_C(0xdeadbeef);
3314 tree[
"deadbeef"] << c4::fmt::base64(valin);
3315 uint64_t valout = 0;
3317 tree[
"deadbeef"] >> ryml::fmt::base64(valout, &len);
3318 CHECK(len ==
sizeof(valout));
3319 CHECK(valout == UINT64_C(0xdeadbeef));
3322 tree[
"deadbeef"] >> ryml::fmt::base64(valout);
3323 CHECK(valout == UINT64_C(0xdeadbeef));
3327 const double valin = 123456.7891011;
3328 tree[
"float"] << c4::fmt::base64(valin);
3331 tree[
"float"] >> ryml::fmt::base64(valout, &len);
3332 CHECK(len ==
sizeof(valout));
3333 CHECK(memcmp(&valout, &valin,
sizeof(valout)) == 0);
3336 tree[
"float"] >> ryml::fmt::base64(valout);
3337 CHECK(memcmp(&valout, &valin,
sizeof(valout)) == 0);
3341 const uint32_t data_in[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xdeadbeef};
3342 uint32_t data_out[11] = {};
3343 tree[
"int_data"] << ryml::fmt::base64(data_in, 11);
3344 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) != 0);
3346 tree[
"int_data"] >> ryml::fmt::base64(data_out, 11, &len);
3347 CHECK(len ==
sizeof(data_out));
3348 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) == 0);
3350 memset(data_out, 0,
sizeof(data_out));
3351 tree[
"int_data"] >> ryml::fmt::base64(data_out);
3352 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) == 0);
3606 "v3: (100,101,102)" "\n"
3607 "v4: (1000,1001,1002,1003)" "\n"
3635 "v3: (30,31,32)" "\n"
3636 "v4: (40,41,42,43)" "\n"
3688template<
class K,
class V>
3713template<
class K,
class V>
3741template<
class K,
class V>
3746 for(
auto const ch : n)
3749 map->
map_member.emplace(std::make_pair(std::move(k), std::move(v)));
3760 n[
"seq"] >> val->
seq;
3761 n[
"map"] >> val->
map;
3780 {{101, 102, 103, 104, 105, 106, 107}},
3781 {{{1001, 2001}, {1002, 2002}, {1003, 2003}}},
3812 "v3: (30,31,32)" "\n"
3813 "v4: (40,41,42,43)" "\n"
3838 std::string yml_std_string =
""
3839 "- v2: (20,21)" "\n"
3840 " v3: (30,31,32)" "\n"
3841 " v4: (40,41,42,43)" "\n"
3854 "- v2: (120,121)" "\n"
3855 " v3: (130,131,132)" "\n"
3856 " v4: (140,141,142,143)" "\n"
3866 " 11001: 12001" "\n"
3867 " 11002: 12002" "\n"
3868 " 11003: 12003" "\n"
3869 "- v2: (220,221)" "\n"
3870 " v3: (230,231,232)" "\n"
3871 " v4: (240,241,242,243)" "\n"
3881 " 21001: 22001" "\n"
3882 " 21002: 22002" "\n"
3883 " 21003: 22003" "\n"
3889 std::vector<my_type> vmt;
3891 CHECK(vmt.size() == 3);
3903 std::vector<double> reference{1.23234412342131234, 2.12323123143434237, 3.67847983572591234};
3907 const double precision_safe = 1.e-14;
3908 const size_t num_digits_safe = 14;
3909 const size_t num_digits_original = 17;
3910 auto get_num_digits = [](
ryml::csubstr number){
return number.len - 2u; };
3916 std::vector<double> output;
3918 CHECK(output.size() == reference.size());
3919 for(
size_t i = 0; i < reference.size(); ++i)
3922 CHECK(fabs(output[i] - reference[i]) < precision_safe);
3931 serialized.
rootref() << reference;
3932 std::cout << serialized;
3934 #if (!C4CORE_HAVE_STD_TOCHARS)
3939 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
3940 C4_UNUSED(num_digits_safe);
3944 "- 1.2323441234213124" "\n"
3945 "- 2.1232312314343424" "\n"
3946 "- 3.6784798357259123" "\n"
3947 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
3951 CHECK(get_num_digits(child.val()) >= num_digits_safe);
3954 CHECK(fabs(out - reference[pos++]) < precision_safe);
3985 auto check_precision = [&](
ryml::Tree const& serialized){
3986 std::cout << serialized;
3989 "- 1.23234412342131239" "\n"
3990 "- 2.12323123143434245" "\n"
3991 "- 3.67847983572591231" "\n"
3992 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
3996 CHECK(get_num_digits(child.val()) == num_digits_original);
3999 CHECK(fabs(out - reference[pos++]) < precision_safe);
4008 for(
const double v : reference)
4010 check_precision(serialized);
4019 for(
const double v : reference)
4024 (void)snprintf(tmp,
sizeof(tmp),
"%.18g", v);
4030 check_precision(serialized);
4050 "- champagne: Dom Perignon" "\n"
4051 " coffee: Arabica" "\n"
4053 " vinho verde: Soalheiro" "\n"
4054 " vinho tinto: Redoma 2017" "\n"
4056 " - Rochefort 10" "\n"
4058 " - Leffe Rituel" "\n"
4077 size_t num_needed_chars = output.
len;
4078 std::vector<char> buf(num_needed_chars);
4081 CHECK(output == ymla);
4089 num_needed_chars = output.
len;
4090 buf.resize(num_needed_chars);
4093 CHECK(output == ymlb);
4098 CHECK(output == ymlb);
4109 " vinho verde: Soalheiro" "\n"
4110 " vinho tinto: Redoma 2017" "\n"
4123 size_t num_needed_chars = output.
len;
4125 buf.resize(num_needed_chars);
4128 CHECK(output == ymla);
4136 num_needed_chars = output.
len;
4137 buf.resize(num_needed_chars);
4140 CHECK(output == ymlb);
4145 CHECK(output == ymlb);
4156 " vinho verde: Soalheiro" "\n"
4157 " vinho tinto: Redoma 2017" "\n"
4173 "- champagne: Dom Perignon" "\n"
4174 " coffee: Arabica" "\n"
4176 " vinho verde: Soalheiro" "\n"
4177 " vinho tinto: Redoma 2017" "\n"
4179 " - Rochefort 10" "\n"
4181 " - Leffe Rituel" "\n"
4193 std::stringstream ss;
4201 std::stringstream ss;
4213 " \"champagne\": \"Dom Perignon\"," "\n"
4214 " \"coffee\": \"Arabica\"," "\n"
4216 " \"vinho verde\": \"Soalheiro\"," "\n"
4217 " \"vinho tinto\": \"Redoma 2017\"" "\n"
4220 " \"Rochefort 10\"," "\n"
4222 " \"Leffe Rituel\"" "\n"
4235 std::stringstream ss;
4240 " vinho verde: Soalheiro" "\n"
4241 " vinho tinto: Redoma 2017" "\n"
4247 std::stringstream ss;
4252 " \"vinho verde\": \"Soalheiro\"," "\n"
4253 " \"vinho tinto\": \"Redoma 2017\"" "\n"
4270 "- champagne: Dom Perignon" "\n"
4271 " coffee: Arabica" "\n"
4273 " vinho verde: Soalheiro" "\n"
4274 " vinho tinto: Redoma 2017" "\n"
4276 " - Rochefort 10" "\n"
4278 " - Leffe Rituel" "\n"
4304 "- champagne: Dom Perignon" "\n"
4305 " coffee: Arabica" "\n"
4307 " vinho verde: Soalheiro" "\n"
4308 " vinho tinto: Redoma 2017" "\n"
4310 " - Rochefort 10" "\n"
4312 " - Leffe Rituel" "\n"
4314 " - many other" "\n"
4315 " - wonderful beers" "\n"
4323 " - Rochefort 10" "\n"
4325 " - Leffe Rituel" "\n"
4327 " - many other" "\n"
4328 " - wonderful beers" "\n"
4334 "- wonderful beers" "\n"
4350 " block key: block val" "\n"
4352 " - block val 1" "\n"
4353 " - block val 2" "\n"
4355 "flow map, singleline: {flow key: flow val}" "\n"
4356 "flow seq, singleline: [flow val,flow val]" "\n"
4357 "flow map, multiline: {" "\n"
4358 " flow key: flow val" "\n"
4360 "flow seq, multiline: [" "\n"
4368 CHECK(tree[
"block map"].is_key_plain());
4369 CHECK(tree[
"block seq"].is_key_plain());
4370 CHECK(tree[
"flow map, singleline"].is_key_plain());
4371 CHECK(tree[
"flow seq, singleline"].is_key_plain());
4372 CHECK(tree[
"flow map, multiline"].is_key_plain());
4373 CHECK(tree[
"flow seq, multiline"].is_key_plain());
4374 CHECK(tree[
"block map"].is_block());
4375 CHECK(tree[
"block seq"].is_block());
4377 CHECK(tree[
"flow map, singleline"].is_flow_sl());
4378 CHECK(tree[
"flow seq, singleline"].is_flow_sl());
4379 CHECK(tree[
"flow map, multiline"].is_flow_ml());
4380 CHECK(tree[
"flow seq, multiline"].is_flow_ml());
4382 CHECK(tree[
"flow map, singleline"].is_flow());
4383 CHECK(tree[
"flow seq, singleline"].is_flow());
4384 CHECK(tree[
"flow map, multiline"].is_flow());
4385 CHECK(tree[
"flow seq, multiline"].is_flow());
4391 CHECK(tostr(tree) == yaml);
4402 " block key: block val\n"
4409 "'block map': {block key: block val}\n"
4415 CHECK(tostr(n) ==
""
4424 CHECK(tostr(n) ==
""
4425 "\"block seq\": [\n"
4434 CHECK(tostr(n) ==
"flow map, singleline: {flow key: flow val}\n");
4437 CHECK(tostr(n) ==
""
4438 "flow map, singleline:\n"
4446 CHECK(tostr(n) ==
""
4447 "flow map, multiline: {\n"
4448 " flow key: flow val\n"
4452 CHECK(tostr(n) ==
""
4453 "flow map, multiline:\n"
4454 " flow key: flow val\n"
4460 CHECK(tostr(n) ==
"flow seq, singleline: [flow val,flow val]\n");
4465 CHECK(tostr(n) ==
""
4467 " flow seq, singleline\n"
4476 CHECK(tostr(n) ==
""
4477 "flow seq, multiline: [\n"
4483 CHECK(tostr(n) ==
"flow seq, multiline: [flow val,flow val]\n");
4486 CHECK(tostr(tree) != yaml);
4487 CHECK(tostr(tree) ==
4488 "'block map': {block key: block val}" "\n"
4489 "\"block seq\": [" "\n"
4490 " block val 1," "\n"
4491 " block val 2," "\n"
4494 "flow map, singleline:" "\n"
4495 " flow key: |-" "\n"
4498 " flow seq, singleline" "\n"
4500 " - 'flow val'" "\n"
4501 " - \"flow val\"" "\n"
4502 "flow map, multiline:" "\n"
4503 " flow key: flow val" "\n"
4504 "flow seq, multiline: [flow val,flow val]" "\n"
4509 CHECK(tostr(tree) ==
4511 " block key: block val" "\n"
4513 " - block val 1" "\n"
4514 " - block val 2" "\n"
4516 "flow map, singleline:" "\n"
4517 " flow key: |-" "\n"
4520 " flow seq, singleline" "\n"
4522 " - 'flow val'" "\n"
4523 " - \"flow val\"" "\n"
4524 "flow map, multiline:" "\n"
4525 " flow key: flow val" "\n"
4526 "flow seq, multiline: [flow val,flow val]" "\n"
4535 CHECK(tostr(tree) ==
4537 " block key: block val" "\n"
4539 " - block val 1" "\n"
4540 " - block val 2" "\n"
4542 "flow map, singleline:" "\n"
4543 " flow key: flow val" "\n"
4544 "flow seq, singleline:" "\n"
4547 "flow map, multiline:" "\n"
4548 " flow key: flow val" "\n"
4549 "flow seq, multiline:" "\n"
4560 CHECK(tostr(tree) ==
4562 " block key: block val" "\n"
4564 " - block val 1" "\n"
4565 " - block val 2" "\n"
4567 "flow map, singleline:" "\n"
4568 " flow key: flow val" "\n"
4569 "flow seq, singleline:" "\n"
4572 "flow map, multiline:" "\n"
4573 " flow key: flow val" "\n"
4574 "flow seq, multiline:" "\n"
4599 CHECK(tostr(tree) ==
""
4601 " 'block key': \"block val\"" "\n"
4602 "'block seq': [\"block val 1\",\"block val 2\",\"quoted\"]" "\n"
4603 "'flow map, singleline':" "\n"
4604 " 'flow key': \"flow val\"" "\n"
4605 "'flow seq, singleline': [\"flow val\",\"flow val\"]" "\n"
4606 "'flow map, multiline':" "\n"
4607 " 'flow key': \"flow val\"" "\n"
4608 "'flow seq, multiline': [\"flow val\",\"flow val\"]" "\n"
4615 CHECK(tostr(tree) ==
""
4617 " 'block key': \"block val\"" "\n"
4618 "'block seq': [\"block val 1\",\"block val 2\",\"quoted\"]" "\n"
4619 "'flow map, singleline':" "\n"
4620 " 'flow key': \"flow val\"" "\n"
4621 "'flow seq, singleline':" "\n"
4622 " - \"flow val\"" "\n"
4623 " - \"flow val\"" "\n"
4624 "'flow map, multiline':" "\n"
4625 " 'flow key': \"flow val\"" "\n"
4626 "'flow seq, multiline': [\"flow val\",\"flow val\"]" "\n"
4645 ryml::csubstr yaml =
"{map: {seq: [0, 1, 2, 3, [40, 41]]}}";
4649 CHECK(tostr(tree, defaults) ==
"{map: {seq: [0,1,2,3,[40,41]]}}");
4656 CHECK(tostr(tree, defaults) ==
4674 CHECK(tostr(tree, noindent) ==
4693 CHECK(tostr(tree, noindent) ==
""
4709 CHECK(tostr(tree, noindent) ==
4767 CHECK(tree[
"map"].is_flow_ml());
4776 CHECK(tree[
"map"].is_flow_sl());
4779 R
"({map: {seq: [0,1,2,3,[40,41]]}})");
4786 CHECK(tree[
"map"].is_flow_ml());
4802 " \"doe\": \"a deer, a female deer\"," "\n"
4803 " \"ray\": \"a drop of golden sun\"," "\n"
4804 " \"me\": \"a name, I call myself\"," "\n"
4805 " \"far\": \"a long long way to go\"" "\n"
4819 std::stringstream ss;
4821 CHECK(ss.str() == json);
4838 std::cout << ryml::emitrs_yaml<std::string>(json_tree);
4845 "\"doe\": \"a deer, a female deer\"" "\n"
4846 "\"ray\": \"a drop of golden sun\"" "\n"
4847 "\"me\": \"a name, I call myself\"" "\n"
4848 "\"far\": \"a long long way to go\"" "\n"
4856 "doe: a deer, a female deer" "\n"
4857 "ray: a drop of golden sun" "\n"
4858 "me: a name, I call myself" "\n"
4859 "far: a long long way to go" "\n"
4868 "doe: 'a deer, a female deer'" "\n"
4869 "ray: 'a drop of golden sun'" "\n"
4870 "me: 'a name, I call myself'" "\n"
4871 "far: 'a long long way to go'" "\n"
4901 std::string unresolved =
""
4903 " name: Everyone has same name" "\n"
4910 "bill_to: &id001" "\n"
4912 " 123 Tornado Alley" "\n"
4914 " city: East Centerville" "\n"
4916 "ship_to: *id001" "\n"
4917 "&keyref key: &valref val" "\n"
4918 "*valref : *keyref" "\n"
4920 std::string resolved =
""
4922 " name: Everyone has same name" "\n"
4924 " name: Everyone has same name" "\n"
4927 " name: Everyone has same name" "\n"
4931 " 123 Tornado Alley" "\n"
4933 " city: East Centerville" "\n"
4937 " 123 Tornado Alley" "\n"
4939 " city: East Centerville" "\n"
4947 CHECK( ! tree[
"base"].has_key_anchor());
4948 CHECK( tree[
"base"].has_val_anchor());
4949 CHECK( tree[
"base"].val_anchor() ==
"base");
4950 CHECK( tree[
"key"].key_anchor() ==
"keyref");
4951 CHECK( tree[
"key"].val_anchor() ==
"valref");
4952 CHECK( tree[
"*valref"].is_key_ref());
4953 CHECK( tree[
"*valref"].is_val_ref());
4954 CHECK( tree[
"*valref"].key_ref() ==
"valref");
4955 CHECK( tree[
"*valref"].val_ref() ==
"keyref");
4962 CHECK( ! tree[
"base"].has_key_anchor());
4963 CHECK( ! tree[
"base"].has_val_anchor());
4964 CHECK( ! tree[
"base"].has_val_anchor());
4965 CHECK( ! tree[
"key"].has_key_anchor());
4966 CHECK( ! tree[
"key"].has_val_anchor());
4967 CHECK( ! tree[
"val"].is_key_ref());
4968 CHECK( ! tree[
"val"].is_val_ref());
4970 CHECK(tree[
"ship_to"][
"city"].val() ==
"East Centerville");
4971 CHECK(tree[
"ship_to"][
"state"].val() ==
"KS");
4989 t[
"nref"] =
"*vanchor";
4991 "&kanchor kanchor: 2" "\n"
4992 "vanchor: &vanchor 3" "\n"
4993 "kref: *kanchor" "\n"
4994 "vref: *vanchor" "\n"
4997 "nref: '*vanchor'" "\n"
5003 "kref: kanchor" "\n"
5006 "nref: '*vanchor'" "\n"
5013 "orig: &orig {foo: bar, baz: bat}" "\n"
5021 t[
"notref"][
"<<"] =
"*orig";
5023 "orig: &orig {foo: bar,baz: bat}" "\n"
5024 "copy: {<<: *orig}" "\n"
5025 "notcopy: {test: *orig,<<: *orig}" "\n"
5026 "notref: {<<: '*orig'}" "\n"
5030 "orig: {foo: bar,baz: bat}" "\n"
5031 "copy: {foo: bar,baz: bat}" "\n"
5032 "notcopy: {test: {foo: bar,baz: bat},foo: bar,baz: bat}" "\n"
5033 "notref: {<<: '*orig'}" "\n"
5040 "orig1: &orig1 {foo: bar}" "\n"
5041 "orig2: &orig2 {baz: bat}" "\n"
5042 "orig3: &orig3 {and: more}" "\n"
5051 "orig1: &orig1 {foo: bar}" "\n"
5052 "orig2: &orig2 {baz: bat}" "\n"
5053 "orig3: &orig3 {and: more}" "\n"
5054 "copy: {<<: [*orig1,*orig2,*orig3]}" "\n"
5058 "orig1: {foo: bar}" "\n"
5059 "orig2: {baz: bat}" "\n"
5060 "orig3: {and: more}" "\n"
5061 "copy: {foo: bar,baz: bat,and: more}" "\n");
5070 const std::string yaml =
""
5079 "--- !!str a b" "\n"
5080 "--- !!str 'a: b'" "\n"
5097 CHECK(doc.is_doc());
5099 CHECK(root[0].has_val_tag());
5100 CHECK(root[0].val_tag() ==
"!!map");
5101 CHECK(root[1].val_tag() ==
"!map");
5102 CHECK(root[2].val_tag() ==
"!!seq");
5103 CHECK(root[3].val_tag() ==
"!!str");
5104 CHECK(root[4].val_tag() ==
"!!str");
5105 CHECK(root[5][
"a"].has_key_tag());
5106 CHECK(root[5][
"a"].key_tag() ==
"!!str");
5107 CHECK(root[6].val_tag() ==
"!!set");
5108 CHECK(root[7].val_tag() ==
"!!set");
5109 CHECK(root[8].val_tag() ==
"!!seq");
5110 CHECK(root[8][0].val_tag() ==
"!!int");
5111 CHECK(root[8][1].val_tag() ==
"!!str");
5169 "--- !!str a b" "\n"
5170 "--- !!str 'a: b'" "\n"
5185 "--- !<tag:yaml.org,2002:map>" "\n"
5190 "--- !<tag:yaml.org,2002:seq>" "\n"
5193 "--- !<tag:yaml.org,2002:str> a b" "\n"
5194 "--- !<tag:yaml.org,2002:str> 'a: b'" "\n"
5196 "!<tag:yaml.org,2002:str> a: b" "\n"
5197 "--- !<tag:yaml.org,2002:set>" "\n"
5200 "--- !<tag:yaml.org,2002:set>" "\n"
5202 "--- !<tag:yaml.org,2002:seq>" "\n"
5203 "- !<tag:yaml.org,2002:int> 0" "\n"
5204 "- !<tag:yaml.org,2002:str> 1" "\n"
5213 const std::string yaml =
""
5214 "%TAG !m! !my-" "\n"
5215 "--- # Bulb here" "\n"
5216 "!m!light fluorescent" "\n"
5218 "%TAG !m! !meta-" "\n"
5219 "--- # Color here" "\n"
5220 "!m!light green" "\n"
5225 "%TAG !m! !my-" "\n"
5226 "--- !m!light fluorescent" "\n"
5228 "%TAG !m! !meta-" "\n"
5229 "--- !m!light green" "\n"
5236 "%TAG !m! !my-" "\n"
5237 "--- !<!my-light> fluorescent" "\n"
5239 "%TAG !m! !meta-" "\n"
5240 "--- !<!meta-light> green" "\n"
5247 "%TAG !m! !my-" "\n"
5248 "--- !<!my-light> fluorescent" "\n"
5250 "%TAG !m! !meta-" "\n"
5251 "--- !<!meta-light> green" "\n"
5262 std::string
yml =
""
5287 CHECK(doc.is_doc());
5306 CHECK(stream[0].is_doc());
5307 CHECK(stream[0].is_map());
5308 CHECK(stream[0][
"a"].val() ==
"0");
5309 CHECK(stream[0][
"b"].val() ==
"1");
5318 CHECK(stream[1].is_doc());
5319 CHECK(stream[1].is_map());
5320 CHECK(stream[1][
"c"].val() ==
"2");
5321 CHECK(stream[1][
"d"].val() ==
"3");
5330 CHECK(stream[2].is_doc());
5331 CHECK(stream[2].is_seq());
5332 CHECK(stream[2][0].val() ==
"4");
5333 CHECK(stream[2][1].val() ==
"5");
5334 CHECK(stream[2][2].val() ==
"6");
5335 CHECK(stream[2][3].val() ==
"7");
5354 const std::string expected_json[] = {
5431 ryml::Tree tree = ryml::parse_in_arena(
"errorhandler.yml",
"[a: b\n}");
5442 auto cause_basic_error = []{
5451#ifdef _RYML_WITH_EXCEPTIONS
5455 cause_basic_error();
5477 auto cause_parse_error = [&]{
5501 msg_ctx.append(s.
str, s.
len);
5503 CHECK(
ryml::to_csubstr(msg_ctx).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5505 "file.yml:3: col=4 (12B): err:" "\n"
5511 "err: see region:" "\n"
5546 CHECK(errh.
saved_msg_full ==
"file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
5559#ifdef _RYML_WITH_EXCEPTIONS
5563 cause_parse_error();
5575 CHECK(msg ==
"invalid character: '['");
5580 auto dumpfn = [&full](
ryml::csubstr s) { full.append(s.str, s.len); };
5584 CHECK(
ryml::to_csubstr(full).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5586 "file.yml:3: col=4 (12B): err:" "\n"
5592 "err: see region:" "\n"
5605 cause_parse_error();
5631 tree[
"float"] >> intval;
5660 tree[
"float"] >> intval;
5672#ifdef _RYML_WITH_EXCEPTIONS
5684 tree[
"float"] >> intval;
5705 tree[
"float"] >> intval;
5742 "float: 123.456" "\n"
5746 auto cause_visit_error = [&]{
5748 tree[
"float"] >> intval;
5780 msg.append(s.
str, s.
len);
5781 }, ymlloc, ymlsrc,
"err", 3);
5783 "file.yml:3: col=0 (24B): err:" "\n"
5785 "err: float: 123.456" "\n"
5789 "err: see region:" "\n"
5791 "err: foo: bar" "\n"
5794 "err: float: 123.456" "\n"
5835 uintptr_t uptr = (uintptr_t)ptr;
5836 const uintptr_t align =
alignof(max_align_t);
5839 uintptr_t prev = uptr - (uptr % align);
5840 uintptr_t next = prev + align;
5841 uintptr_t corr = next - uptr;
5842 ptr = (
void*)(((
char*)ptr) + corr);
5846 "out of memory! requested=%zu+%zu available=%zu\n",
5872 static void s_free(
void *mem,
size_t len,
void *this_)
5944 parse_in_arena(&parser,
"", R
"([a, b, c, d, {foo: bar, money: pennys}])", &tree);
5987 std::cerr <<
"out of memory! requested=" <<
alloc_size <<
" vs " <<
memory_pool.size() <<
" available" << std::endl;
6073 CHECK(tree["doe"].val() ==
"a deer, a female deer");
6089 "aa: contents," "\n"
6090 "foo: [one, [two, three]]" "\n"
6134 loc = tree[
"foo"].
location(parser);
6139 loc = tree[
"foo"][0].
location(parser);
6144 loc = tree[
"foo"][1].
location(parser);
6148 loc = tree[
"foo"][1][0].
location(parser);
6152 loc = tree[
"foo"][1][1].
location(parser);
6174 "a new: buffer" "\n"
6175 "to: be parsed" "\n"
6176 "map with key:" "\n"
6177 " first: value" "\n"
6178 " second: value" "\n"
6179 "seq with key:" "\n"
6180 " - first value" "\n"
6181 " - second value" "\n"
6183 " - nested first value" "\n"
6184 " - nested second value" "\n"
6186 " nested first: value" "\n"
6187 " nested second: value" "\n"
6201 loc = tree2[
"a new"].
location(parser);
6206 loc = tree2[
"to"].
location(parser);
6212 loc = tree2[
"map with key"].
location(parser);
6216 loc = tree2[
"map with key"][
"first"].
location(parser);
6220 loc = tree2[
"map with key"][
"second"].
location(parser);
6225 loc = tree2[
"seq with key"].
location(parser);
6229 loc = tree2[
"seq with key"][0].
location(parser);
6233 loc = tree2[
"seq with key"][1].
location(parser);
6238 loc = tree2[
"seq with key"][2].
location(parser);
6242 loc = tree2[
"seq with key"][2][0].
location(parser);
6247 loc = tree2[
"seq with key"][3].
location(parser);
6251 loc = tree2[
"seq with key"][3][0].
location(parser);
6267static int num_checks = 0;
6268static int num_failed_checks = 0;
6269static bool quiet_mode =
false;
6274 auto arg_matches = [](
const char *arg,
const char *shortform,
const char *longform) {
6275 return (0 == strcmp(arg, shortform) || 0 == strcmp(arg, longform));
6277 for(
int i = 1; i < argc; ++i)
6278 if(arg_matches(argv[i],
"-q",
"--quiet"))
6285 const char *msg = predicate ?
"OK! " :
"OK!";
6288 ++num_failed_checks;
6289 msg = predicate ?
"FAIL: " :
"FAIL";
6291 if(!result || !quiet_mode)
6293 std::cout << __FILE__ <<
':' << line <<
": " << msg << (predicate ? predicate :
"") << std::endl;
6301 std::cout <<
"Completed " << num_checks <<
" checks." << std::endl;
6302 if(num_failed_checks)
6303 std::cout <<
"ERROR: " << num_failed_checks <<
'/' << num_checks <<
" checks failed." << std::endl;
6305 std::cout <<
"SUCCESS!" << std::endl;
6306 return num_failed_checks;
6321 fwrite(s.
str, 1, s.
len, stderr);
6327 fputc(
'\n', stderr);
6342 .set_free([](
void* mem,
size_t,
void *){
6378#ifdef RYML_NO_DEFAULT_CALLBACKS
6387#ifndef C4_EXCEPTIONS
6418 bool got_error =
false;
6419 #ifdef C4_EXCEPTIONS
6422 std::forward<Fn>(fn)();
6424 catch(std::exception
const&)
6431 std::forward<Fn>(fn)();
6444[[noreturn]]
void stopexec(std::string
const& s)
6446 #ifdef C4_EXCEPTIONS
6447 throw std::runtime_error(s);
6572C4_SUPPRESS_WARNING_GCC_CLANG_POP
Holds a pointer to an existing tree, and a node id.
id_type id() const noexcept
bool invalid() const noexcept
Tree const * tree() const noexcept
bool readable() const noexcept
because a ConstNodeRef cannot be used to write to the tree, readable() has the same meaning as !...
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
void set_key_style(NodeType_e style)
void set_style_conditionally(NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
void clear_style(bool recurse=false)
void set_val_style(NodeType_e style)
id_type id() const noexcept
bool invalid() const noexcept
true if the object is not referring to any existing or seed node.
void set_container_style(NodeType_e style)
bool readable() const noexcept
true if the object is not invalid and not in seed state.
size_t set_val_serialized(T const &v)
bool is_seed() const noexcept
true if the object is not invalid and in seed state.
void set_val_ref(csubstr val_ref)
void reserve_stack(id_type capacity)
Reserve a certain capacity for the parsing stack.
csubstr location_contents(Location const &loc) const
Get the string starting at a particular location, to the end of the parsed source buffer.
ParserOptions const & options() const
Get the options used to build this parser object.
Callbacks const & callbacks() const
Get the current callbacks in the parser.
void reserve_locations(size_t num_source_lines)
Reserve a certain capacity for the array used to track node locations in the source buffer.
void clear()
clear the tree and zero every node
csubstr const & key(id_type node) const
id_type first_child(id_type node) const
bool is_stream(id_type node) const
void set_val_ref(id_type node, csubstr ref)
id_type root_id() const
Get the id of the root node. The tree must not be empty.
NodeRef rootref()
Get the root as a NodeRef.
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as "!!str" -> "<tag:yaml.org,2002:str>", "!foo" -> "<!...
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
ensure the tree's internal string arena is at least the given capacity
bool is_map(id_type node) const
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
csubstr const & val(id_type node) const
bool is_root(id_type node) const
substr alloc_arena(size_t sz)
grow the tree's string arena by the given size and return a substr of the added portion
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
void clear_style(id_type node, bool recurse=false)
id_type next_sibling(id_type node) const
ConstNodeRef crootref() const
Get the root as a ConstNodeRef.
id_type id(NodeData const *n) const
get the index of a node belonging to this tree. n can be nullptr, in which case NONE is returned
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
csubstr to_arena(T const &a)
serialize the given variable to the tree's arena, growing it as needed to accomodate the serializatio...
void set_val_anchor(id_type node, csubstr anchor)
NodeRef docref(id_type i)
get the i-th document of the stream
bool is_doc(id_type node) const
void set_container_style(id_type node, NodeType_e style)
Callbacks const & callbacks() const
size_t arena_capacity() const
get the current capacity of the tree's internal arena
id_type doc(id_type i) const
gets the i document node index.
void set_val(id_type node, csubstr val)
void normalize_tags_long()
void resolve(ReferenceResolver *rr, bool clear_anchors=true)
Resolve references (aliases <- anchors), by forwarding to ReferenceResolver::resolve(); refer to Refe...
bool is_seq(id_type node) const
id_type find_child(id_type node, csubstr const &key) const
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
id_type first_sibling(id_type node) const
substr copy_to_arena(csubstr s)
copy the given string to the tree's arena, growing the arena by the required size.
id_type num_children(id_type node) const
O(num_children).
csubstr arena() const
get the current arena
id_type child(id_type node, id_type pos) const
void set_key_anchor(id_type node, csubstr anchor)
Definitions of error utilities used by ryml.
right_< T > right(T val, size_t width, char padchar=' ')
tag function to mark an argument to be aligned right
left_< T > left(T val, size_t width, char padchar=' ')
tag type to mark an argument to be aligned left.
boolalpha_ boolalpha(T const &val=false)
tag function to mark a variable to be written as an alphabetic boolean, ie as either true or false
void set_callbacks(Callbacks const &c)
set the global callbacks for the library; after a call to this function, these callbacks will be used...
Callbacks const & get_callbacks()
get the global callbacks
csubstr catrs_append(CharOwningContainer *cont, Args const &...args)
cat+resize+append: like c4::cat(), but receives a container, and appends to it instead of overwriting...
size_t cat(substr buf, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer.
void catrs(CharOwningContainer *cont, Args const &...args)
cat+resize: like c4::cat(), but receives a container, and resizes it as needed to contain the result.
substr cat_sub(substr buf, Args const &...args)
like c4::cat() but return a substr instead of a size
csubstr catseprs_append(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize+append: like c4::catsep(), but receives a container, and appends the arguments,...
void catseprs(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize: like c4::catsep(), but receives a container, and resizes it as needed to contain the r...
size_t catsep(substr buf, Sep const &sep, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer, using a separator between...
substr catsep_sub(substr buf, Args &&...args)
like c4::catsep() but return a substr instead of a size
@ FTOA_FLEX
print the real number in flexible format (like g)
@ FTOA_SCIENT
print the real number in scientific format (like e)
@ FTOA_FLOAT
print the real number in floating point format (like f)
@ FTOA_HEXA
print the real number in hexadecimal format (like a)
bool indent_flow_ml() const noexcept
substr emitrs_json(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit JSON to the given std::string/std::vector-like container, resizing it as needed...
substr emitrs_yaml(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit YAML to the given std::string/std::vector-like container, resizing it as needed...
size_t emit_yaml(Tree const &t, id_type id, EmitOptions const &opts, FILE *f)
(1) emit YAML to the given file, starting at the given node.
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const &errdata)
Given an error message and associated visit error data, format it fully as a visit error message.
void location_format_with_context(DumpFn &&dumpfn, Location const &location, csubstr source_buffer, csubstr call, size_t num_lines_before, size_t num_lines_after, size_t first_col_highlight, size_t last_col_highlight, size_t maxlen)
Generic formatting of a location, printing the source code buffer region around the location.
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const &errdata)
Given an error message and associated basic error data, format it fully as a basic error message.
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const &errdata)
Given an error message and associated parse error data, format it fully as a parse error message.
void file_get_contents(const char *filename, FILE *fp, size_t filesz, void *buf, size_t bufsz)
load a file of specified size from disk into an existing contiguous buffer.
void file_put_contents(void const *buf, size_t sz, const char *filename, const char *access="wb")
save a contiguous buffer into a file
integral_< intptr_t > hex(std::nullptr_t)
format null as an hexadecimal value
integral_< intptr_t > oct(std::nullptr_t)
format null as an octal value
integral_< intptr_t > bin(std::nullptr_t)
format null as a binary 0-1 value
bool scalar_is_null(csubstr s) noexcept
YAML-sense query of nullity.
@ KEY_DQUO
mark key scalar as double quoted "
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
@ FLOW_ML
mark container with multi-line flow style (seqs as '[ val1, val2 ], maps as '{ key: val,...
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
@ VAL_SQUO
mark val scalar as single quoted '
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
@ VAL_DQUO
mark val scalar as double quoted "
@ KEY_SQUO
mark key scalar as single quoted '
@ VAL_LITERAL
mark val scalar as multiline, block literal |
@ KEY_FOLDED
mark key scalar as multiline, block folded >
auto overflows(csubstr str) noexcept -> typename std::enable_if< std::is_unsigned< T >::value, bool >::type
Test if the following string would overflow when converted to associated integral types; this functio...
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id)
(1) parse JSON into an existing tree node. The filename will be used in any error messages arising du...
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id)
(1) parse YAML into an existing tree node.
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree.
void sample_anchors_and_aliases()
demonstrates usage with anchors and alias references.
void sample_emit_to_file()
demonstrates how to emit to a FILE*
void sample_formatting()
ryml provides facilities for formatting/deformatting (imported from c4core into the ryml namespace).
void sample_quick_overview()
a brief tour over most features
void sample_style_flow_ml_indent()
[experimental] control the indentation of emitted FLOW_ML containers
void sample_per_tree_allocator()
void sample_lightning_overview()
a lightning tour over most features see sample_quick_overview
void sample_user_container_types()
shows how to serialize/deserialize container types.
void sample_empty_null_values()
Shows how to deal with empty/null values.
void sample_global_allocator()
demonstrates how to set the global allocator for ryml
void sample_base64()
demonstrates how to read and write base64-encoded blobs.
void sample_error_visit()
Visit errors happen when an error is triggered while reading from a node.
void sample_static_trees()
shows how to work around the static initialization order fiasco when using a static-duration ryml tre...
void sample_parse_file()
demonstrate how to load a YAML file from disk to parse with ryml.
void sample_style_flow_ml_filter()
[experimental] set the parser to pick FLOW_SL even if the container being parsed is FLOW_ML
void sample_json()
shows how to parse and emit JSON.
void sample_error_parse()
void sample_parse_in_arena()
demonstrate parsing of a read-only YAML source buffer
void sample_emit_nested_node()
just like parsing into a nested node, you can also emit from a nested node.
void sample_style()
[experimental] query/set/modify node style to control formatting of emitted YAML code.
void sample_location_tracking()
demonstrates how to obtain the (zero-based) location of a node from a recently parsed tree
void sample_parse_reuse_parser()
Demonstrates reuse of an existing parser.
void sample_iterate_trees()
shows how to programatically iterate through trees
void sample_create_trees()
shows how to programatically create trees
void sample_parse_reuse_tree_and_parser()
for ultimate speed when parsing multiple times, reuse both the tree and parser
void sample_emit_to_container()
demonstrates how to emit to a linear container of char
void sample_parse_in_place()
demonstrate in-place parsing of a mutable YAML source buffer.
void sample_fundamental_types()
ryml provides facilities for serializing and deserializing the C++ fundamental types,...
void sample_std_types()
demonstrates usage with the std implementations provided by ryml in the ryml_std.hpp header
void sample_float_precision()
control precision of serialized floats
void sample_anchors_and_aliases_create()
demonstrates how to use the API to programatically create anchors and aliases
void sample_user_scalar_types()
to add scalar types (ie leaf types converting to/from string), define the functions above for those t...
void sample_error_visit_location()
It is possible to obtain the YAML location from a visit error: when the tree is obtained from parsing...
void sample_error_basic()
void sample_tag_directives()
void sample_error_handler()
demonstrates how to set a custom error handler for ryml
void sample_emit_to_stream()
demonstrates how to emit to a stream-like structure
void sample_tree_arena()
demonstrates explicit and implicit interaction with the tree's string arena.
void sample_parse_reuse_tree()
demonstrate reuse/modification of tree when parsing
void sample_substr()
demonstrate usage of ryml::substr and ryml::csubstr
const_raw_wrapper raw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
const_raw_wrapper craw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
real_< T > real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT)
void write(ryml::NodeRef *n, my_seq_type< T > const &seq)
bool read(ryml::ConstNodeRef const &n, my_seq_type< T > *seq)
bool from_chars(ryml::csubstr buf, vec2< T > *v)
static void s_error_basic(ryml::csubstr msg, ryml::ErrorDataBasic const &errdata, void *this_)
trampoline function to call the object's method
bool report_check(int line, const char *predicate, bool result)
static void s_error_parse(ryml::csubstr msg, ryml::ErrorDataParse const &errdata, void *this_)
trampoline function to call the object's method
bool check_assertion_occurs(Fn &&fn)
checking that an assertion occurs while calling fn.
void on_error_visit(ryml::csubstr msg, ryml::ErrorDataVisit const &errdata)
this is where the callback implementation goes.
static std::string s_jmp_msg
void ensure_callbacks()
set up default callbacks when ryml does not provide them (ie when RYML_NO_DEFAULT_CALLBACKS is define...
static void s_error_visit(ryml::csubstr msg, ryml::ErrorDataVisit const &errdata, void *this_)
trampoline function to call the object's method
void on_error_parse(ryml::csubstr msg, ryml::ErrorDataParse const &errdata)
this is where the callback implementation goes.
bool check_error_occurs(Fn &&fn)
checking that an error occurs while calling fn
ryml::Callbacks default_callbacks()
a bare-bones implementation of the callbacks
void check_disabled() const
test that this handler is currently not set
#define CHECK(predicate)
a quick'n'dirty assertion to verify a predicate
ryml::Callbacks callbacks()
a helper to create the Callbacks object for the custom error handler
void on_error_basic(ryml::csubstr msg, ryml::ErrorDataBasic const &errdata)
this is where the callback implementation goes.
static std::jmp_buf s_jmp_env
void check_enabled() const
test that this handler is currently set
void handle_args(int argc, const char *argv[])
size_t to_chars(ryml::substr buf, vec2< T > v)
substr to_substr(char(&s)[N]) noexcept
csubstr to_csubstr(const char(&s)[N]) noexcept
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
csubstr from_tag_long(YamlTag_e tag)
csubstr normalize_tag_long(csubstr tag)
csubstr normalize_tag(csubstr tag)
csubstr from_tag(YamlTag_e tag)
YamlTag_e to_tag(csubstr tag)
size_t uncat(csubstr buf, Arg &a, Args &...more)
deserialize the arguments from the given buffer.
size_t uncatsep(csubstr buf, csubstr sep, Arg &a, Args &...more)
deserialize the arguments from the given buffer, using a separator.
integral_padded_< T > zpad(T val, size_t num_digits)
pad the argument with zeroes on the left, with decimal radix
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
int main(int, const char *[])
an example error handler, required for some of the quickstart examples.
ryml::Location saved_basic_loc
ryml::Callbacks original_callbacks
std::string saved_msg_full
ryml::id_type saved_visit_id
std::string saved_msg_short
ryml::Tree const * saved_visit_tree
ryml::Location saved_parse_loc
std::string saved_msg_full_with_context
void free(void *mem, size_t len)
~GlobalAllocatorExample()
std::vector< char > memory_pool
static void s_free(void *mem, size_t len, void *this_)
void * allocate(size_t len)
ryml::Callbacks callbacks()
static void * s_allocate(size_t len, void *, void *this_)
an example for a per-tree memory allocator
std::vector< char > memory_pool
ryml::Callbacks callbacks() const
void * allocate(size_t len)
void free(void *mem, size_t len)
Shows how to create a scoped error handler.
~ScopedErrorHandlerExample()
ScopedErrorHandlerExample()
bool begins_with_any(ro_substr chars) const noexcept
true if the first character of the string is any of the given chars
basic_substring trim(const C c) const
trim the character c left and right
size_t count(const C c, size_t pos=0) const
count the number of occurrences of c
auto reverse_sub(size_t ifirst, size_t num) -> typename std::enable_if< !std::is_const< U >::value, void >::type
revert a subpart in place
basic_substring range(size_t first, size_t last=npos) const noexcept
return [first,last[.
size_t first_not_of(const C c) const
auto tolower() -> typename std::enable_if< !std::is_const< U >::value, void >::type
convert the string to lower-case
bool begins_with(const C c) const noexcept
true if the first character of the string is c
basic_substring triml(const C c) const
trim left
size_t last_of(const C c, size_t start=npos) const
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...
auto fill(C val) -> typename std::enable_if< !std::is_const< U >::value, void >::type
fill the entire contents with the given val
size_t len
the length of the substring
basic_substring last(size_t num) const noexcept
return the last num elements: [len-num,len[
bool ends_with(const C c) const noexcept
true if the last character of the string is c
size_t first_of(const C c, size_t start=0) const
basic_substring stripl(ro_substr pattern) const
remove a pattern from the left
size_t find(const C c, size_t start_pos=0) const
auto replace(C value, C repl, size_t pos=0) -> typename std::enable_if< ! std::is_const< U >::value, size_t >::type
replace every occurrence of character value with the character repl
basic_substring stripr(ro_substr pattern) const
remove a pattern from the right
size_t size() const noexcept
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 left_of(size_t pos) const noexcept
return [0, pos[ .
basic_substring sub(size_t first) const noexcept
return [first,len[
bool ends_with_any(ro_substr chars) const noexcept
true if the last character of the string is any of the given chars
bool empty() const noexcept
basic_substring trimr(const C c) const
trim the character c from the right
auto reverse_range(size_t ifirst, size_t ilast) -> typename std::enable_if< !std::is_const< U >::value, void >::type
revert a range in place
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
size_t last_not_of(const C c) const
auto toupper() -> typename std::enable_if< ! std::is_const< U >::value, void >::type
convert the string to upper-case
C * str
a restricted pointer to the first character of the substring
basic_substring right_of(size_t pos) const noexcept
return [pos+1, len[
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
basic_substring select(const C c, size_t pos=0) const
get the substr consisting of the first occurrence of c after pos, or an empty substr if none occurs
auto reverse() -> typename std::enable_if< !std::is_const< U >::value, void >::type
reverse in place
A c-style callbacks class to customize behavior on errors or allocation.
pfn_error_basic m_error_basic
a pointer to a basic error handler function
pfn_error_parse m_error_parse
a pointer to a parse error handler function
Callbacks & set_error_visit(pfn_error_visit error_visit=nullptr)
Set or reset the error_visit callback.
Callbacks & set_free(pfn_free free=nullptr)
Set or reset the free callback.
void * m_user_data
data to be forwarded in every call to a callback
pfn_allocate m_allocate
a pointer to an allocate handler function
Callbacks & set_error_parse(pfn_error_parse error_parse=nullptr)
Set or reset the error_parse callback.
Callbacks & set_allocate(pfn_allocate allocate=nullptr)
Set or reset the allocate callback.
Callbacks & set_error_basic(pfn_error_basic error_basic=nullptr)
Set or reset the error_basic callback.
pfn_error_visit m_error_visit
a pointer to a visit error handler function
pfn_free m_free
a pointer to a free handler function
Callbacks & set_user_data(void *user_data)
Set the user data.
A lightweight object containing options to be used when emitting.
Location location
location where the error was detected (may be from YAML or C++ source code)
Location cpploc
location in the C++ source file where the error was detected.
Location ymlloc
location in the YAML source buffer where the error was detected.
Location cpploc
location in the C++ source file where the error was detected.
Tree const * tree
tree where the error was detected
id_type node
node where the error was detected
The event handler to create a ryml Tree.
Callbacks const & callbacks() const
Exception thrown by the default basic error implementation.
const char * what() const noexcept override
ErrorDataBasic errdata_basic
error data
Exception thrown by the default parse error implementation.
ErrorDataParse errdata_parse
Exception thrown by the default visit error implementation.
ErrorDataVisit errdata_visit
holds a source or yaml file position, for example when an error is detected; See also location_format...
size_t offset
number of bytes from the beginning of the source buffer
csubstr name
name of the file
Options to give to the parser to control its behavior.
ParserOptions & detect_flow_ml(bool enabled) noexcept
enable/disable detection of FLOW_ML container style.
ParserOptions & locations(bool enabled) noexcept
enable/disable source location tracking
ParserOptions & resolve_tags(bool enabled) noexcept
enable/disable resolution of YAML tags during parsing.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
mark a tree or node to be emitted as yaml when using operator<<, with options.
auto first_child() RYML_NOEXCEPT -> Impl
Forward to Tree::first_child().
auto children() RYML_NOEXCEPT -> children_view
get an iterable view over children.
bool is_val() const RYML_NOEXCEPT
Forward to Tree::is_val().
bool is_root() const RYML_NOEXCEPT
Forward to Tree::is_root().
auto last_child() RYML_NOEXCEPT -> Impl
Forward to Tree::last_child().
bool is_stream() const RYML_NOEXCEPT
Forward to Tree::is_stream().
auto parent() RYML_NOEXCEPT -> Impl
Forward to Tree::parent().
bool has_child(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_child().
auto next_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::next_sibling().
auto last_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::last_sibling().
bool is_map() const RYML_NOEXCEPT
Forward to Tree::is_map().
id_type num_siblings() const RYML_NOEXCEPT
O(num_children).
bool has_key() const RYML_NOEXCEPT
Forward to Tree::has_key().
csubstr key() const RYML_NOEXCEPT
Forward to Tree::key().
auto first_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::first_sibling().
csubstr val() const RYML_NOEXCEPT
Forward to Tree::val().
bool is_doc() const RYML_NOEXCEPT
Forward to Tree::is_doc().
id_type num_children() const RYML_NOEXCEPT
O(num_children).
auto child(id_type pos) RYML_NOEXCEPT -> Impl
Forward to Tree::child().
bool is_block() const RYML_NOEXCEPT
Forward to Tree::is_block().
Location location(Parser const &parser) const
bool is_seq() const RYML_NOEXCEPT
Forward to Tree::is_seq().
bool has_val() const RYML_NOEXCEPT
Forward to Tree::has_val().
auto prev_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::prev_sibling().
example scalar type, serialized only
example scalar type, serialized only
example scalar type, serialized only
example user container type: map-like
std::map< K, V > map_member
example user container type: seq-like
std::vector< T > seq_member
example user container type with nested container members.
my_map_type< int, int > map
example scalar type, deserialized only
example scalar type, deserialized only
example scalar type, deserialized only
example scalar type, serialized and deserialized
example scalar type, serialized and deserialized
example scalar type, serialized and deserialized