76 #if defined(RYML_SINGLE_HEADER)
77 #define RYML_SINGLE_HDR_DEFINE_NOW
78 #include <ryml_all.hpp>
79 #elif defined(RYML_SINGLE_HEADER_LIB)
80 #include <ryml_all.hpp>
209 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
210 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wcast-qual")
211 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
212 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
231 template<
class Fn>
bool check_error_occurs(Fn &&fn);
232 template<
class Fn>
bool check_assertion_occurs(Fn &&fn);
233 void check_enabled()
const;
234 void check_disabled()
const;
243 [[noreturn]]
static void s_error_basic(ryml::csubstr msg,
ryml::ErrorDataBasic const& errdata,
void *this_);
244 [[noreturn]]
static void s_error_parse(ryml::csubstr msg,
ryml::ErrorDataParse const& errdata,
void *this_);
245 [[noreturn]]
static void s_error_visit(ryml::csubstr msg,
ryml::ErrorDataVisit const& errdata,
void *this_);
283 template<
class CharContainer> CharContainer
file_get_contents(
const char *filename);
284 template<
class CharContainer>
size_t file_get_contents(
const char *filename, CharContainer *v);
285 template<
class CharContainer>
void file_put_contents(
const char *filename, CharContainer
const& v,
const char* access=
"wb");
286 void file_put_contents(
const char *filename,
const char *buf,
size_t sz,
const char* access);
289 bool report_check(
int line,
const char *predicate,
bool result);
292 #if defined(__DOXYGEN__) || defined(_DOXYGEN_)
294 # define CHECK(predicate) assert(predicate)
296 # if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
298 # define CHECK(predicate) do { if(!report_check(__LINE__, #predicate, (predicate))) { RYML_DEBUG_BREAK(); } } while(0)
301 # define CHECK CheckPredicate{__FILE__, __LINE__}
302 struct CheckPredicate
306 void operator() (
bool result)
const
329 char yml_buf[] =
"{foo: 1, bar: [2, 3], john: doe}";
334 CHECK(bar[0].val() ==
"2");
335 CHECK(bar[1].val() ==
"3");
336 CHECK(bar[0].val().str == yml_buf + 15);
337 CHECK(bar[1].val().str == yml_buf + 18);
340 int bar0 = 0, bar1 = 0;
349 CHECK(bar[0].val() ==
"10");
350 CHECK(bar[1].val() ==
"11");
354 CHECK(bar[2].val() ==
"12");
358 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"({foo: 1,bar: [10,11,12],john: doe})");
365 CHECK(ryml::emitrs_yaml<std::string>(foo) ==
"foo: 1\n");
445 CHECK(tree[
"foo"].is_keyval());
446 CHECK(tree[
"foo"].val() ==
"1");
448 CHECK(tree[
"bar"].is_seq());
449 CHECK(tree[
"bar"].has_key());
452 CHECK(tree[
"bar"][0].val() ==
"2");
453 CHECK(tree[
"bar"][1].val() ==
"3");
454 CHECK(tree[
"john"].val() ==
"doe");
458 CHECK(tree[0].
id() == tree[
"foo"].
id());
459 CHECK(tree[1].
id() == tree[
"bar"].
id());
460 CHECK(tree[2].
id() == tree[
"john"].
id());
462 CHECK(tree[0].
id() == tree[
"foo"].
id());
463 CHECK(tree[1].
id() == tree[
"bar"].
id());
464 CHECK(tree[2].
id() == tree[
"john"].
id());
466 CHECK(bar[0].val() ==
"2");
467 CHECK(bar[1].val() ==
"3");
474 CHECK(tree[
"john"].
key() ==
"john");
479 CHECK(root[
"foo"].
id() == root[0].
id());
480 CHECK(root[
"bar"].
id() == root[1].
id());
481 CHECK(root[
"john"].
id() == root[2].
id());
535 ryml::csubstr expected_keys[] = {
"foo",
"bar",
"john"};
540 CHECK(child.key() == expected_keys[count++]);
546 CHECK(child.key() == expected_keys[count++]);
552 CHECK(tree.
key(child_id) == expected_keys[count++]);
561 CHECK(tree.
key(child_id) == expected_keys[count++]);
621 int foo = 0, bar0 = 0, bar1 = 0;
622 std::string john_str;
625 root[
"bar"][0] >> bar0;
626 root[
"bar"][1] >> bar1;
627 root[
"john"] >> john_str;
632 CHECK(john_str ==
"doe");
633 CHECK(bar_str ==
"bar");
650 wroot[
"foo"] =
"says you";
651 wroot[
"bar"][0] =
"-2";
652 wroot[
"bar"][1] =
"-3";
653 wroot[
"john"] =
"ron";
657 CHECK(root[
"foo"].val() ==
"says you");
658 CHECK(root[
"bar"][0].val() ==
"-2");
659 CHECK(root[
"bar"][1].val() ==
"-3");
660 CHECK(root[
"john"].val() ==
"ron");
675 wroot[
"foo"] <<
"says who";
676 wroot[
"bar"][0] << 20;
677 wroot[
"bar"][1] << 30;
678 wroot[
"john"] <<
"deere";
679 CHECK(root[
"foo"].val() ==
"says who");
680 CHECK(root[
"bar"][0].val() ==
"20");
681 CHECK(root[
"bar"][1].val() ==
"30");
682 CHECK(root[
"john"].val() ==
"deere");
686 std::string ok(
"in_scope");
690 CHECK(root[
"john"].val() ==
"in_scope");
692 wroot[
"float"] << 2.4f;
696 CHECK(tree.
arena() ==
"says who2030deerein_scope2.42.400000");
704 wroot[
"newkeyval"] =
"shiny and new";
707 CHECK(root[
"newkeyval"].
key() ==
"newkeyval");
708 CHECK(root[
"newkeyval"].val() ==
"shiny and new");
709 CHECK(root[
"newkeyval (serialized)"].
key() ==
"newkeyval (serialized)");
710 CHECK(root[
"newkeyval (serialized)"].val() ==
"shiny and new (serialized)");
716 CHECK(root[
"bar"].num_children() == 2);
717 wroot[
"bar"][2] =
"oh so nice";
718 wroot[
"bar"][3] <<
"oh so nice (serialized)";
719 CHECK(root[
"bar"].num_children() == 4);
720 CHECK(root[
"bar"][2].val() ==
"oh so nice");
721 CHECK(root[
"bar"][3].val() ==
"oh so nice (serialized)");
727 CHECK(root[
"newseq"].num_children() == 0);
728 CHECK(root[
"newseq"].is_seq());
729 CHECK(root[
"newseq (serialized)"].num_children() == 0);
730 CHECK(root[
"newseq (serialized)"].is_seq());
736 CHECK(root[
"newmap"].num_children() == 0);
737 CHECK(root[
"newmap"].is_map());
738 CHECK(root[
"newmap (serialized)"].num_children() == 0);
739 CHECK(root[
"newmap (serialized)"].is_map());
767 nothing = wroot[
"I am nothing"];
782 something =
"indeed";
784 CHECK(root[
"I am something"].val() ==
"indeed");
815 CHECK(wbar[0].readable() && wbar[0].val() ==
"20");
816 CHECK( ! wbar[100].readable());
817 CHECK( ! wbar[100].readable() || wbar[100].val() ==
"100");
819 CHECK( ! wbar[0].is_seed() && wbar[0].val() ==
"20");
820 CHECK(wbar[100].is_seed() || wbar[100].val() ==
"100");
848 return seed_node.at(
"is").at(
"an").at(
"invalid").at(
"operation");
855 return seed_node[
"is"][
"an"][
"invalid"][
"operation"];
865 ryml::csubstr expected_result = R
"(foo: says who
866 bar: [20,30,oh so nice,oh so nice (serialized)]
870 newkeyval: shiny and new
871 newkeyval (serialized): shiny and new (serialized)
873 newseq (serialized): []
875 newmap (serialized): {}
876 I am something: indeed
882 std::stringstream ss;
884 std::string stream_result = ss.str();
886 std::string str_result = ryml::emitrs_yaml<std::string>(tree);
891 CHECK(buf_result == expected_result);
892 CHECK(str_result == expected_result);
893 CHECK(stream_result == expected_result);
909 CHECK(tree[
"bar"][0].val() ==
"21");
911 CHECK(tree[
"bar"][0].val() ==
"22");
917 constnoderef = noderef;
923 noderef = tree[
"bar"][0];
924 constnoderef = consttree[
"bar"][0];
928 CHECK(constnoderef == noderef);
929 CHECK(!(constnoderef != noderef));
954 fr: Planète (Gazeuse)
958 # UTF8 decoding only happens in double-quoted strings,
959 # as per the YAML standard
960 decode this: "\u263A c\x61f\xE9"
961 and this as well: "\u2705 \U0001D11E"
962 not decoded: '\u263A \xE2\x98\xBA'
963 neither this: '\u2705 \U0001D11E'
966 CHECK(langs[
"en"].val() ==
"Planet (Gas)");
967 CHECK(langs[
"fr"].val() ==
"Planète (Gazeuse)");
968 CHECK(langs[
"ru"].val() ==
"Планета (Газ)");
969 CHECK(langs[
"ja"].val() ==
"惑星(ガス)");
970 CHECK(langs[
"zh"].val() ==
"行星(气体)");
974 CHECK(langs[
"decode this"].val() ==
"☺ café");
975 CHECK(langs[
"and this as well"].val() ==
"✅ 𝄞");
976 CHECK(langs[
"not decoded"].val() ==
"\\u263A \\xE2\\x98\\xBA");
977 CHECK(langs[
"neither this"].val() ==
"\\u2705 \\U0001D11E");
1005 const char foobar_str[] =
"foobar";
1006 auto s = ryml::csubstr(foobar_str, strlen(foobar_str));
1007 CHECK(s ==
"foobar");
1008 CHECK(s.size() == 6);
1009 CHECK(s.data() == foobar_str);
1010 CHECK(s.size() == s.len);
1011 CHECK(s.data() == s.str);
1016 const char foobar_str[] =
"foobar";
1017 ryml::csubstr s = foobar_str;
1018 CHECK(s ==
"foobar");
1019 CHECK(s !=
"foobar0");
1020 CHECK(s.size() == 6);
1021 CHECK(s.data() == foobar_str);
1022 CHECK(s.size() == s.len);
1023 CHECK(s.data() == s.str);
1027 ryml::csubstr s =
"foobar";
1028 CHECK(s ==
"foobar");
1029 CHECK(s !=
"foobar0");
1030 CHECK(s.size() == 6);
1031 CHECK(s.size() == s.len);
1032 CHECK(s.data() == s.str);
1041 const char *foobar_str =
"foobar";
1043 CHECK(s ==
"foobar");
1044 CHECK(s !=
"foobar0");
1045 CHECK(s.size() == 6);
1046 CHECK(s.size() == s.len);
1047 CHECK(s.data() == s.str);
1058 std::string foobar_str =
"foobar";
1060 CHECK(s ==
"foobar");
1061 CHECK(s !=
"foobar0");
1062 CHECK(s.size() == 6);
1063 CHECK(s.size() == s.len);
1064 CHECK(s.data() == s.str);
1070 ryml::substr foo = buf;
1071 CHECK(foo.len == 3);
1072 CHECK(foo.data() == buf);
1073 ryml::csubstr cfoo = foo;
1074 CHECK(cfoo.data() == buf);
1083 char const foobar_str_ro[] =
"foobar";
1084 char foobar_str_rw[] =
"foobar";
1085 static_assert(std::is_array<decltype(foobar_str_ro)>::value,
"this is an array");
1086 static_assert(std::is_array<decltype(foobar_str_rw)>::value,
"this is an array");
1089 ryml::csubstr foobar = foobar_str_ro;
1090 CHECK(foobar.data() == foobar_str_ro);
1091 CHECK(foobar.size() == strlen(foobar_str_ro));
1092 CHECK(foobar ==
"foobar");
1096 ryml::csubstr foobar = foobar_str_rw;
1097 CHECK(foobar.data() == foobar_str_rw);
1098 CHECK(foobar.size() == strlen(foobar_str_rw));
1099 CHECK(foobar ==
"foobar");
1103 ryml::substr foobar = foobar_str_rw;
1104 CHECK(foobar.data() == foobar_str_rw);
1105 CHECK(foobar.size() == strlen(foobar_str_rw));
1106 CHECK(foobar ==
"foobar");
1117 char const* foobar_str_ro =
"foobar";
1118 char foobar_str_rw_[] =
"foobar";
1119 char * foobar_str_rw = foobar_str_rw_;
1120 static_assert(!std::is_array<decltype(foobar_str_ro)>::value,
"this is a decayed pointer");
1121 static_assert(!std::is_array<decltype(foobar_str_rw)>::value,
"this is a decayed pointer");
1126 CHECK(foobar.data() == foobar_str_ro);
1127 CHECK(foobar.size() == strlen(foobar_str_ro));
1128 CHECK(foobar ==
"foobar");
1133 CHECK(foobar.data() == foobar_str_rw);
1134 CHECK(foobar.size() == strlen(foobar_str_rw));
1135 CHECK(foobar ==
"foobar");
1140 CHECK(foobar.data() == foobar_str_rw);
1141 CHECK(foobar.size() == strlen(foobar_str_rw));
1142 CHECK(foobar ==
"foobar");
1152 char buf[] =
"foobar";
1153 ryml::substr foobar = buf;
1154 CHECK(foobar ==
"foobar");
1155 foobar[0] =
'F';
CHECK(foobar ==
"Foobar");
1156 foobar.back() =
'R';
CHECK(foobar ==
"FoobaR");
1157 foobar.reverse();
CHECK(foobar ==
"RabooF");
1158 foobar.reverse();
CHECK(foobar ==
"FoobaR");
1159 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FabooR");
1160 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FoobaR");
1161 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoaboR");
1162 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoobaR");
1163 foobar.replace(
'o',
'0');
CHECK(foobar ==
"F00baR");
1164 foobar.replace(
'a',
'_');
CHECK(foobar ==
"F00b_R");
1165 foobar.replace(
"_0b",
'a');
CHECK(foobar ==
"FaaaaR");
1166 foobar.toupper();
CHECK(foobar ==
"FAAAAR");
1167 foobar.tolower();
CHECK(foobar ==
"faaaar");
1168 foobar.fill(
'.');
CHECK(foobar ==
"......");
1176 ryml::csubstr s =
"fooFOObarBAR";
1177 CHECK(s.len == 12u);
1179 CHECK(s.sub(0) ==
"fooFOObarBAR");
1180 CHECK(s.sub(0, 12) ==
"fooFOObarBAR");
1181 CHECK(s.sub(0, 3) ==
"foo" );
1182 CHECK(s.sub(3) ==
"FOObarBAR");
1183 CHECK(s.sub(3, 3) ==
"FOO" );
1184 CHECK(s.sub(6) ==
"barBAR");
1185 CHECK(s.sub(6, 3) ==
"bar" );
1186 CHECK(s.sub(9) ==
"BAR");
1187 CHECK(s.sub(9, 3) ==
"BAR");
1189 CHECK(s.first(0) ==
"" );
1190 CHECK(s.first(1) ==
"f" );
1191 CHECK(s.first(2) !=
"f" );
1192 CHECK(s.first(2) ==
"fo" );
1193 CHECK(s.first(3) ==
"foo");
1195 CHECK(s.last(0) ==
"");
1196 CHECK(s.last(1) ==
"R");
1197 CHECK(s.last(2) ==
"AR");
1198 CHECK(s.last(3) ==
"BAR");
1200 CHECK(s.range(0, 12) ==
"fooFOObarBAR");
1201 CHECK(s.range(1, 12) ==
"ooFOObarBAR");
1202 CHECK(s.range(1, 11) ==
"ooFOObarBA" );
1203 CHECK(s.range(2, 10) ==
"oFOObarB" );
1204 CHECK(s.range(3, 9) ==
"FOObar" );
1206 CHECK(s.offs(0, 0) ==
"fooFOObarBAR");
1207 CHECK(s.offs(1, 0) ==
"ooFOObarBAR");
1208 CHECK(s.offs(1, 1) ==
"ooFOObarBA" );
1209 CHECK(s.offs(2, 1) ==
"oFOObarBA" );
1210 CHECK(s.offs(2, 2) ==
"oFOObarB" );
1211 CHECK(s.offs(3, 3) ==
"FOObar" );
1213 CHECK(s.right_of(0,
true) ==
"fooFOObarBAR");
1214 CHECK(s.right_of(0,
false) ==
"ooFOObarBAR");
1215 CHECK(s.right_of(1,
true) ==
"ooFOObarBAR");
1216 CHECK(s.right_of(1,
false) ==
"oFOObarBAR");
1217 CHECK(s.right_of(2,
true) ==
"oFOObarBAR");
1218 CHECK(s.right_of(2,
false) ==
"FOObarBAR");
1219 CHECK(s.right_of(3,
true) ==
"FOObarBAR");
1220 CHECK(s.right_of(3,
false) ==
"OObarBAR");
1222 CHECK(s.left_of(12,
false) ==
"fooFOObarBAR");
1223 CHECK(s.left_of(11,
true) ==
"fooFOObarBAR");
1224 CHECK(s.left_of(11,
false) ==
"fooFOObarBA" );
1225 CHECK(s.left_of(10,
true) ==
"fooFOObarBA" );
1226 CHECK(s.left_of(10,
false) ==
"fooFOObarB" );
1227 CHECK(s.left_of( 9,
true) ==
"fooFOObarB" );
1228 CHECK(s.left_of( 9,
false) ==
"fooFOObar" );
1230 ryml::csubstr FOO = s.sub(3, 3);
1231 CHECK(s.is_super(FOO));
1232 CHECK(s.left_of(FOO) ==
"foo");
1233 CHECK(s.right_of(FOO) ==
"barBAR");
1238 ryml::csubstr s =
"some substring";
1239 ryml::csubstr some = s.first(4);
1240 CHECK(some ==
"some");
1241 CHECK(s ==
"some substring");
1244 char result[32] = {0};
1245 std::snprintf(result,
sizeof(result),
"%.*s", (
int)some.len, some.str);
1246 printf(
"~~~%s~~~\n", result);
1256 char result[32] = {0};
1257 std::snprintf(result,
sizeof(result),
"%s", some.str);
1265 ryml::csubstr s =
"some substring";
1266 ryml::csubstr some = s.first(4);
1267 CHECK(some ==
"some");
1268 CHECK(s ==
"some substring");
1271 std::stringstream ss;
1273 CHECK(ss.str() ==
"some substring");
1274 CHECK(ss.str() == s);
1282 std::stringstream ss;
1284 CHECK(ss.str() ==
"some substring");
1285 CHECK(ss.str() == s);
1289 std::stringstream ss;
1291 CHECK(ss.str() ==
"some substring");
1292 CHECK(ss.str() == s);
1296 std::stringstream ss;
1298 CHECK(ss.str() ==
"some");
1299 CHECK(ss.str() == some);
1305 ryml::csubstr foobar =
"foobar";
1306 ryml::csubstr foo = foobar.first(3);
1307 CHECK(foo.is_sub(foobar));
1308 CHECK(foo.is_sub(foo));
1309 CHECK(!foo.is_super(foobar));
1310 CHECK(!foobar.is_sub(foo));
1312 CHECK(foo.is_super(foo));
1313 CHECK(foo.is_sub(foo));
1314 CHECK(foobar.is_sub(foobar));
1315 CHECK(foobar.is_super(foobar));
1320 ryml::csubstr foobar =
"foobar";
1321 ryml::csubstr foo = foobar.first(3);
1322 ryml::csubstr oba = foobar.offs(2, 1);
1323 ryml::csubstr abc =
"abc";
1324 CHECK(foobar.overlaps(foo));
1325 CHECK(foobar.overlaps(oba));
1326 CHECK(foo.overlaps(foobar));
1327 CHECK(foo.overlaps(oba));
1328 CHECK(!foo.overlaps(abc));
1329 CHECK(!abc.overlaps(foo));
1336 CHECK(ryml::csubstr(
" \t\n\rcontents without whitespace\t \n\r").trim(
"\t \n\r") ==
"contents without whitespace");
1337 ryml::csubstr aaabbb =
"aaabbb";
1338 ryml::csubstr aaa___bbb =
"aaa___bbb";
1340 CHECK(aaabbb.triml(
'a') == aaabbb.last(3));
1341 CHECK(aaabbb.trimr(
'a') == aaabbb);
1342 CHECK(aaabbb.trim (
'a') == aaabbb.last(3));
1343 CHECK(aaabbb.triml(
'b') == aaabbb);
1344 CHECK(aaabbb.trimr(
'b') == aaabbb.first(3));
1345 CHECK(aaabbb.trim (
'b') == aaabbb.first(3));
1346 CHECK(aaabbb.triml(
'c') == aaabbb);
1347 CHECK(aaabbb.trimr(
'c') == aaabbb);
1348 CHECK(aaabbb.trim (
'c') == aaabbb);
1349 CHECK(aaa___bbb.triml(
'a') == aaa___bbb.last(6));
1350 CHECK(aaa___bbb.trimr(
'a') == aaa___bbb);
1351 CHECK(aaa___bbb.trim (
'a') == aaa___bbb.last(6));
1352 CHECK(aaa___bbb.triml(
'b') == aaa___bbb);
1353 CHECK(aaa___bbb.trimr(
'b') == aaa___bbb.first(6));
1354 CHECK(aaa___bbb.trim (
'b') == aaa___bbb.first(6));
1355 CHECK(aaa___bbb.triml(
'c') == aaa___bbb);
1356 CHECK(aaa___bbb.trimr(
'c') == aaa___bbb);
1357 CHECK(aaa___bbb.trim (
'c') == aaa___bbb);
1359 CHECK(aaabbb.triml(
"ab") ==
"");
1360 CHECK(aaabbb.trimr(
"ab") ==
"");
1361 CHECK(aaabbb.trim (
"ab") ==
"");
1362 CHECK(aaabbb.triml(
"ba") ==
"");
1363 CHECK(aaabbb.trimr(
"ba") ==
"");
1364 CHECK(aaabbb.trim (
"ba") ==
"");
1365 CHECK(aaabbb.triml(
"cd") == aaabbb);
1366 CHECK(aaabbb.trimr(
"cd") == aaabbb);
1367 CHECK(aaabbb.trim (
"cd") == aaabbb);
1368 CHECK(aaa___bbb.triml(
"ab") == aaa___bbb.last(6));
1369 CHECK(aaa___bbb.triml(
"ba") == aaa___bbb.last(6));
1370 CHECK(aaa___bbb.triml(
"cd") == aaa___bbb);
1371 CHECK(aaa___bbb.trimr(
"ab") == aaa___bbb.first(6));
1372 CHECK(aaa___bbb.trimr(
"ba") == aaa___bbb.first(6));
1373 CHECK(aaa___bbb.trimr(
"cd") == aaa___bbb);
1374 CHECK(aaa___bbb.trim (
"ab") == aaa___bbb.range(3, 6));
1375 CHECK(aaa___bbb.trim (
"ba") == aaa___bbb.range(3, 6));
1376 CHECK(aaa___bbb.trim (
"cd") == aaa___bbb);
1381 CHECK(ryml::csubstr(R
"('this is is single quoted')").unquoted() == "this is is single quoted");
1382 CHECK(ryml::csubstr(R
"("this is is double quoted")").unquoted() == "this is is double quoted");
1388 ryml::csubstr abc___cba =
"abc___cba";
1389 ryml::csubstr abc___abc =
"abc___abc";
1390 CHECK(abc___cba.stripl(
"abc") == abc___cba.last(6));
1391 CHECK(abc___cba.stripr(
"abc") == abc___cba);
1392 CHECK(abc___cba.stripl(
"ab") == abc___cba.last(7));
1393 CHECK(abc___cba.stripr(
"ab") == abc___cba);
1394 CHECK(abc___cba.stripl(
"a") == abc___cba.last(8));
1395 CHECK(abc___cba.stripr(
"a") == abc___cba.first(8));
1396 CHECK(abc___abc.stripl(
"abc") == abc___abc.last(6));
1397 CHECK(abc___abc.stripr(
"abc") == abc___abc.first(6));
1398 CHECK(abc___abc.stripl(
"ab") == abc___abc.last(7));
1399 CHECK(abc___abc.stripr(
"ab") == abc___abc);
1400 CHECK(abc___abc.stripl(
"a") == abc___abc.last(8));
1401 CHECK(abc___abc.stripr(
"a") == abc___abc);
1407 ryml::csubstr s =
"foobar123";
1409 CHECK(s.begins_with(
'f'));
1410 CHECK(s.ends_with(
'3'));
1411 CHECK(!s.ends_with(
'2'));
1412 CHECK(!s.ends_with(
'o'));
1414 CHECK(s.begins_with(
"foobar"));
1415 CHECK(s.begins_with(
"foo"));
1416 CHECK(s.begins_with_any(
"foo"));
1417 CHECK(!s.begins_with(
"oof"));
1418 CHECK(s.begins_with_any(
"oof"));
1419 CHECK(s.ends_with(
"23"));
1420 CHECK(s.ends_with(
"123"));
1421 CHECK(s.ends_with_any(
"123"));
1422 CHECK(!s.ends_with(
"321"));
1423 CHECK(s.ends_with_any(
"231"));
1428 ryml::csubstr s =
"0123456789";
1429 CHECK(s.select(
'0') == s.sub(0, 1));
1430 CHECK(s.select(
'1') == s.sub(1, 1));
1431 CHECK(s.select(
'2') == s.sub(2, 1));
1432 CHECK(s.select(
'8') == s.sub(8, 1));
1433 CHECK(s.select(
'9') == s.sub(9, 1));
1434 CHECK(s.select(
"0123") == s.range(0, 4));
1435 CHECK(s.select(
"012" ) == s.range(0, 3));
1436 CHECK(s.select(
"01" ) == s.range(0, 2));
1437 CHECK(s.select(
"0" ) == s.range(0, 1));
1438 CHECK(s.select(
"123") == s.range(1, 4));
1439 CHECK(s.select(
"23") == s.range(2, 4));
1440 CHECK(s.select(
"3") == s.range(3, 4));
1445 ryml::csubstr s012345 =
"012345";
1448 CHECK(s012345.find(
'0' ) == 0u);
1450 CHECK(s012345.find(
'1' ) == 1u);
1452 CHECK(s012345.find(
'2' ) == 2u);
1454 CHECK(s012345.find(
'3' ) == 3u);
1458 CHECK(s012345.find(
"01" ) == 0u);
1460 CHECK(s012345.find(
"12" ) == 1u);
1462 CHECK(s012345.find(
"23" ) == 2u);
1468 ryml::csubstr buf =
"00110022003300440055";
1469 CHECK(buf.count(
'1' ) == 2u);
1470 CHECK(buf.count(
'1', 0u) == 2u);
1471 CHECK(buf.count(
'1', 1u) == 2u);
1472 CHECK(buf.count(
'1', 2u) == 2u);
1473 CHECK(buf.count(
'1', 3u) == 1u);
1474 CHECK(buf.count(
'1', 4u) == 0u);
1475 CHECK(buf.count(
'1', 5u) == 0u);
1476 CHECK(buf.count(
'0' ) == 10u);
1477 CHECK(buf.count(
'0', 0u) == 10u);
1478 CHECK(buf.count(
'0', 1u) == 9u);
1479 CHECK(buf.count(
'0', 2u) == 8u);
1480 CHECK(buf.count(
'0', 3u) == 8u);
1481 CHECK(buf.count(
'0', 4u) == 8u);
1482 CHECK(buf.count(
'0', 5u) == 7u);
1483 CHECK(buf.count(
'0', 6u) == 6u);
1484 CHECK(buf.count(
'0', 7u) == 6u);
1485 CHECK(buf.count(
'0', 8u) == 6u);
1486 CHECK(buf.count(
'0', 9u) == 5u);
1487 CHECK(buf.count(
'0', 10u) == 4u);
1488 CHECK(buf.count(
'0', 11u) == 4u);
1489 CHECK(buf.count(
'0', 12u) == 4u);
1490 CHECK(buf.count(
'0', 13u) == 3u);
1491 CHECK(buf.count(
'0', 14u) == 2u);
1492 CHECK(buf.count(
'0', 15u) == 2u);
1493 CHECK(buf.count(
'0', 16u) == 2u);
1494 CHECK(buf.count(
'0', 17u) == 1u);
1495 CHECK(buf.count(
'0', 18u) == 0u);
1496 CHECK(buf.count(
'0', 19u) == 0u);
1497 CHECK(buf.count(
'0', 20u) == 0u);
1502 ryml::csubstr s012345 =
"012345";
1505 CHECK(s012345.first_of(
'0') == 0u);
1506 CHECK(s012345.first_of(
"0") == 0u);
1507 CHECK(s012345.first_of(
"01") == 0u);
1508 CHECK(s012345.first_of(
"10") == 0u);
1509 CHECK(s012345.first_of(
"012") == 0u);
1510 CHECK(s012345.first_of(
"210") == 0u);
1511 CHECK(s012345.first_of(
"0123") == 0u);
1512 CHECK(s012345.first_of(
"3210") == 0u);
1513 CHECK(s012345.first_of(
"01234") == 0u);
1514 CHECK(s012345.first_of(
"43210") == 0u);
1515 CHECK(s012345.first_of(
"012345") == 0u);
1516 CHECK(s012345.first_of(
"543210") == 0u);
1517 CHECK(s012345.first_of(
'5') == 5u);
1518 CHECK(s012345.first_of(
"5") == 5u);
1519 CHECK(s012345.first_of(
"45") == 4u);
1520 CHECK(s012345.first_of(
"54") == 4u);
1521 CHECK(s012345.first_of(
"345") == 3u);
1522 CHECK(s012345.first_of(
"543") == 3u);
1523 CHECK(s012345.first_of(
"2345") == 2u);
1524 CHECK(s012345.first_of(
"5432") == 2u);
1525 CHECK(s012345.first_of(
"12345") == 1u);
1526 CHECK(s012345.first_of(
"54321") == 1u);
1527 CHECK(s012345.first_of(
"012345") == 0u);
1528 CHECK(s012345.first_of(
"543210") == 0u);
1535 CHECK(s012345.last_of(
'0') == 0u);
1536 CHECK(s012345.last_of(
"0") == 0u);
1537 CHECK(s012345.last_of(
"01") == 1u);
1538 CHECK(s012345.last_of(
"10") == 1u);
1539 CHECK(s012345.last_of(
"012") == 2u);
1540 CHECK(s012345.last_of(
"210") == 2u);
1541 CHECK(s012345.last_of(
"0123") == 3u);
1542 CHECK(s012345.last_of(
"3210") == 3u);
1543 CHECK(s012345.last_of(
"01234") == 4u);
1544 CHECK(s012345.last_of(
"43210") == 4u);
1545 CHECK(s012345.last_of(
"012345") == 5u);
1546 CHECK(s012345.last_of(
"543210") == 5u);
1547 CHECK(s012345.last_of(
'5') == 5u);
1548 CHECK(s012345.last_of(
"5") == 5u);
1549 CHECK(s012345.last_of(
"45") == 5u);
1550 CHECK(s012345.last_of(
"54") == 5u);
1551 CHECK(s012345.last_of(
"345") == 5u);
1552 CHECK(s012345.last_of(
"543") == 5u);
1553 CHECK(s012345.last_of(
"2345") == 5u);
1554 CHECK(s012345.last_of(
"5432") == 5u);
1555 CHECK(s012345.last_of(
"12345") == 5u);
1556 CHECK(s012345.last_of(
"54321") == 5u);
1557 CHECK(s012345.last_of(
"012345") == 5u);
1558 CHECK(s012345.last_of(
"543210") == 5u);
1559 CHECK(s012345.last_of(
'0', 6u) == 0u);
1560 CHECK(s012345.last_of(
'5', 6u) == 5u);
1561 CHECK(s012345.last_of(
"012345", 6u) == 5u);
1566 ryml::csubstr s012345 =
"012345";
1567 CHECK(s012345.first_not_of(
'a') == 0u);
1568 CHECK(s012345.first_not_of(
"ab") == 0u);
1569 CHECK(s012345.first_not_of(
'0') == 1u);
1570 CHECK(s012345.first_not_of(
"0") == 1u);
1571 CHECK(s012345.first_not_of(
"01") == 2u);
1572 CHECK(s012345.first_not_of(
"10") == 2u);
1573 CHECK(s012345.first_not_of(
"012") == 3u);
1574 CHECK(s012345.first_not_of(
"210") == 3u);
1575 CHECK(s012345.first_not_of(
"0123") == 4u);
1576 CHECK(s012345.first_not_of(
"3210") == 4u);
1577 CHECK(s012345.first_not_of(
"01234") == 5u);
1578 CHECK(s012345.first_not_of(
"43210") == 5u);
1581 CHECK(s012345.first_not_of(
'5') == 0u);
1582 CHECK(s012345.first_not_of(
"5") == 0u);
1583 CHECK(s012345.first_not_of(
"45") == 0u);
1584 CHECK(s012345.first_not_of(
"54") == 0u);
1585 CHECK(s012345.first_not_of(
"345") == 0u);
1586 CHECK(s012345.first_not_of(
"543") == 0u);
1587 CHECK(s012345.first_not_of(
"2345") == 0u);
1588 CHECK(s012345.first_not_of(
"5432") == 0u);
1589 CHECK(s012345.first_not_of(
"12345") == 0u);
1590 CHECK(s012345.first_not_of(
"54321") == 0u);
1593 CHECK(s012345.last_not_of(
'a') == 5u);
1594 CHECK(s012345.last_not_of(
"ab") == 5u);
1595 CHECK(s012345.last_not_of(
'5') == 4u);
1596 CHECK(s012345.last_not_of(
"5") == 4u);
1597 CHECK(s012345.last_not_of(
"45") == 3u);
1598 CHECK(s012345.last_not_of(
"54") == 3u);
1599 CHECK(s012345.last_not_of(
"345") == 2u);
1600 CHECK(s012345.last_not_of(
"543") == 2u);
1601 CHECK(s012345.last_not_of(
"2345") == 1u);
1602 CHECK(s012345.last_not_of(
"5432") == 1u);
1603 CHECK(s012345.last_not_of(
"12345") == 0u);
1604 CHECK(s012345.last_not_of(
"54321") == 0u);
1607 CHECK(s012345.last_not_of(
'0') == 5u);
1608 CHECK(s012345.last_not_of(
"0") == 5u);
1609 CHECK(s012345.last_not_of(
"01") == 5u);
1610 CHECK(s012345.last_not_of(
"10") == 5u);
1611 CHECK(s012345.last_not_of(
"012") == 5u);
1612 CHECK(s012345.last_not_of(
"210") == 5u);
1613 CHECK(s012345.last_not_of(
"0123") == 5u);
1614 CHECK(s012345.last_not_of(
"3210") == 5u);
1615 CHECK(s012345.last_not_of(
"01234") == 5u);
1616 CHECK(s012345.last_not_of(
"43210") == 5u);
1623 CHECK(ryml::csubstr(
"foo bar").first_non_empty_span() ==
"foo");
1624 CHECK(ryml::csubstr(
" foo bar").first_non_empty_span() ==
"foo");
1625 CHECK(ryml::csubstr(
"\n \r \t foo bar").first_non_empty_span() ==
"foo");
1626 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1627 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1628 CHECK(ryml::csubstr(
",\n \r \t foo\n\r\t bar").first_non_empty_span() ==
",");
1632 CHECK(ryml::csubstr(
"1234 asdkjh").first_uint_span() ==
"1234");
1633 CHECK(ryml::csubstr(
"1234\rasdkjh").first_uint_span() ==
"1234");
1634 CHECK(ryml::csubstr(
"1234\tasdkjh").first_uint_span() ==
"1234");
1635 CHECK(ryml::csubstr(
"1234\nasdkjh").first_uint_span() ==
"1234");
1636 CHECK(ryml::csubstr(
"1234]asdkjh").first_uint_span() ==
"1234");
1637 CHECK(ryml::csubstr(
"1234)asdkjh").first_uint_span() ==
"1234");
1638 CHECK(ryml::csubstr(
"1234gasdkjh").first_uint_span() ==
"");
1642 CHECK(ryml::csubstr(
"-1234 asdkjh").first_int_span() ==
"-1234");
1643 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_int_span() ==
"-1234");
1644 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_int_span() ==
"-1234");
1645 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_int_span() ==
"-1234");
1646 CHECK(ryml::csubstr(
"-1234]asdkjh").first_int_span() ==
"-1234");
1647 CHECK(ryml::csubstr(
"-1234)asdkjh").first_int_span() ==
"-1234");
1648 CHECK(ryml::csubstr(
"-1234gasdkjh").first_int_span() ==
"");
1652 CHECK(ryml::csubstr(
"-1234 asdkjh").first_real_span() ==
"-1234");
1653 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_real_span() ==
"-1234");
1654 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_real_span() ==
"-1234");
1655 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_real_span() ==
"-1234");
1656 CHECK(ryml::csubstr(
"-1234]asdkjh").first_real_span() ==
"-1234");
1657 CHECK(ryml::csubstr(
"-1234)asdkjh").first_real_span() ==
"-1234");
1658 CHECK(ryml::csubstr(
"-1234gasdkjh").first_real_span() ==
"");
1659 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1660 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1661 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1662 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1663 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1664 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1665 CHECK(ryml::csubstr(
"-1.234 asdkjh").first_real_span() ==
"-1.234");
1666 CHECK(ryml::csubstr(
"-1.234e+5 asdkjh").first_real_span() ==
"-1.234e+5");
1667 CHECK(ryml::csubstr(
"-1.234e-5 asdkjh").first_real_span() ==
"-1.234e-5");
1669 CHECK(ryml::csubstr(
"0x1.e8480p+19 asdkjh").first_real_span() ==
"0x1.e8480p+19");
1670 CHECK(ryml::csubstr(
"0x1.e8480p-19 asdkjh").first_real_span() ==
"0x1.e8480p-19");
1671 CHECK(ryml::csubstr(
"-0x1.e8480p+19 asdkjh").first_real_span() ==
"-0x1.e8480p+19");
1672 CHECK(ryml::csubstr(
"-0x1.e8480p-19 asdkjh").first_real_span() ==
"-0x1.e8480p-19");
1673 CHECK(ryml::csubstr(
"+0x1.e8480p+19 asdkjh").first_real_span() ==
"+0x1.e8480p+19");
1674 CHECK(ryml::csubstr(
"+0x1.e8480p-19 asdkjh").first_real_span() ==
"+0x1.e8480p-19");
1676 CHECK(ryml::csubstr(
"0b101.011p+19 asdkjh").first_real_span() ==
"0b101.011p+19");
1677 CHECK(ryml::csubstr(
"0b101.011p-19 asdkjh").first_real_span() ==
"0b101.011p-19");
1678 CHECK(ryml::csubstr(
"-0b101.011p+19 asdkjh").first_real_span() ==
"-0b101.011p+19");
1679 CHECK(ryml::csubstr(
"-0b101.011p-19 asdkjh").first_real_span() ==
"-0b101.011p-19");
1680 CHECK(ryml::csubstr(
"+0b101.011p+19 asdkjh").first_real_span() ==
"+0b101.011p+19");
1681 CHECK(ryml::csubstr(
"+0b101.011p-19 asdkjh").first_real_span() ==
"+0b101.011p-19");
1683 CHECK(ryml::csubstr(
"0o173.045p+19 asdkjh").first_real_span() ==
"0o173.045p+19");
1684 CHECK(ryml::csubstr(
"0o173.045p-19 asdkjh").first_real_span() ==
"0o173.045p-19");
1685 CHECK(ryml::csubstr(
"-0o173.045p+19 asdkjh").first_real_span() ==
"-0o173.045p+19");
1686 CHECK(ryml::csubstr(
"-0o173.045p-19 asdkjh").first_real_span() ==
"-0o173.045p-19");
1687 CHECK(ryml::csubstr(
"+0o173.045p+19 asdkjh").first_real_span() ==
"+0o173.045p+19");
1688 CHECK(ryml::csubstr(
"+0o173.045p-19 asdkjh").first_real_span() ==
"+0o173.045p-19");
1694 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").basename() ==
"file.tar.gz");
1695 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").dirname() ==
"/path/to/");
1696 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").basename(
'\\') ==
"file.tar.gz");
1697 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").dirname(
'\\') ==
"C:\\path\\to\\");
1698 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extshort() ==
"gz");
1699 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extlong() ==
"tar.gz");
1700 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extshort() ==
"/path/to/file.tar");
1701 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extlong() ==
"/path/to/file");
1706 using namespace ryml;
1707 csubstr parts[] = {
"aa",
"bb",
"cc",
"dd",
"ee",
"ff"};
1710 for(csubstr part : csubstr(
"aa/bb/cc/dd/ee/ff").split(
'/'))
1711 CHECK(part == parts[count++]);
1716 for(csubstr part : csubstr(
"aa.bb.cc.dd.ee.ff").split(
'.'))
1717 CHECK(part == parts[count++]);
1722 for(csubstr part : csubstr(
"aa-bb-cc-dd-ee-ff").split(
'-'))
1723 CHECK(part == parts[count++]);
1732 const bool skip_empty =
true;
1734 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/' ) ==
"0" );
1735 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/' ) ==
"" );
1736 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/' ) ==
"" );
1737 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/', skip_empty) ==
"0" );
1738 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/', skip_empty) ==
"/0" );
1739 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/', skip_empty) ==
"//0" );
1741 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/' ) ==
"0/1" );
1742 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/' ) ==
"/0/1" );
1743 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/' ) ==
"//0/1" );
1744 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/' ) ==
"0/1/2");
1745 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/' ) ==
"/0/1/2");
1746 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/' ) ==
"//0/1/2");
1747 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/' ) ==
"0/1/2/");
1748 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/' ) ==
"/0/1/2/");
1749 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/' ) ==
"//0/1/2/");
1750 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1751 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1752 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1753 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1754 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1755 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1756 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1757 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1758 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1760 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/' ) ==
"2" );
1761 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/' ) ==
"" );
1762 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/' ) ==
"" );
1763 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/', skip_empty) ==
"2" );
1764 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/', skip_empty) ==
"2/" );
1765 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/', skip_empty) ==
"2//" );
1767 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/' ) ==
"1/2");
1768 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/' ) ==
"1/2/" );
1769 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/' ) ==
"1/2//" );
1770 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/' ) ==
"0/1/2");
1771 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/' ) ==
"0/1/2/" );
1772 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/' ) ==
"0/1/2//" );
1773 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/' ) ==
"/0/1/2");
1774 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/' ) ==
"/0/1/2/" );
1775 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/' ) ==
"/0/1/2//" );
1776 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1777 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1778 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1779 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1780 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1781 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1782 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1783 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1784 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1807 const char filename[] =
"ryml_example.yml";
1821 std::string contents = file_get_contents<std::string>(filename);
1823 CHECK(tree[
"foo"].val() ==
"1");
1824 CHECK(tree[
"bar"][0].val() ==
"2");
1825 CHECK(tree[
"bar"][1].val() ==
"3");
1830 std::vector<char> contents = file_get_contents<std::vector<char>>(filename);
1832 CHECK(tree[
"foo"].val() ==
"1");
1833 CHECK(tree[
"bar"][0].val() ==
"2");
1834 CHECK(tree[
"bar"][1].val() ==
"3");
1855 char src[] =
"{foo: 1, bar: [2, 3]}";
1856 ryml::substr srcview = src;
1861 CHECK(root[
"foo"].is_keyval());
1863 CHECK(root[
"foo"].val() ==
"1");
1864 CHECK(root[
"bar"].is_seq());
1865 CHECK(root[
"bar"].has_key());
1867 CHECK(root[
"bar"][0].val() ==
"2");
1868 CHECK(root[
"bar"][1].val() ==
"3");
1871 int foo = 0, bar0 = 0, bar1 = 0;
1873 root[
"bar"][0] >> bar0;
1874 root[
"bar"][1] >> bar1;
1880 CHECK(root[
"foo"].val().data() == src + strlen(
"{foo: "));
1881 CHECK(root[
"foo"].val().begin() == src + strlen(
"{foo: "));
1882 CHECK(root[
"foo"].val().end() == src + strlen(
"{foo: 1"));
1883 CHECK(root[
"foo"].val().is_sub(srcview));
1884 CHECK(root[
"bar"][0].val().data() == src + strlen(
"{foo: 1, bar: ["));
1885 CHECK(root[
"bar"][0].val().begin() == src + strlen(
"{foo: 1, bar: ["));
1886 CHECK(root[
"bar"][0].val().end() == src + strlen(
"{foo: 1, bar: [2"));
1887 CHECK(root[
"bar"][0].val().is_sub(srcview));
1888 CHECK(root[
"bar"][1].val().data() == src + strlen(
"{foo: 1, bar: [2, "));
1889 CHECK(root[
"bar"][1].val().begin() == src + strlen(
"{foo: 1, bar: [2, "));
1890 CHECK(root[
"bar"][1].val().end() == src + strlen(
"{foo: 1, bar: [2, 3"));
1891 CHECK(root[
"bar"][1].val().is_sub(srcview));
1895 ryml::csubstr csrcview = srcview;
1913 CHECK(root[
"foo"].is_keyval());
1915 CHECK(root[
"foo"].val() ==
"1");
1916 CHECK(root[
"bar"].is_seq());
1917 CHECK(root[
"bar"].has_key());
1919 CHECK(root[
"bar"][0].val() ==
"2");
1920 CHECK(root[
"bar"][1].val() ==
"3");
1923 int foo = 0, bar0 = 0, bar1 = 0;
1925 root[
"bar"][0] >> bar0;
1926 root[
"bar"][1] >> bar1;
1934 char src[] =
"{foo: is it really true}";
1935 ryml::substr srcview = src;
1941 ryml::csubstr csrcview = srcview;
1943 CHECK(tree[
"foo"].val() ==
"is it really true");
1962 ryml::csubstr yaml = R
"(foo: 1
1970 CHECK(root["foo"].is_keyval());
1972 CHECK(root[
"foo"].val() ==
"1");
1973 CHECK(root[
"bar"].is_seq());
1974 CHECK(root[
"bar"].has_key());
1976 CHECK(root[
"bar"][0].val() ==
"2");
1977 CHECK(root[
"bar"][1].val() ==
"3");
1978 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(foo: 1
1984 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(foo: 1
1990 CHECK(root["foo2"].is_keyval());
1991 CHECK(root[
"foo2"].
key() ==
"foo2");
1992 CHECK(root[
"foo2"].val() ==
"12");
1993 CHECK(root[
"bar2"].is_seq());
1994 CHECK(root[
"bar2"].has_key());
1995 CHECK(root[
"bar2"].
key() ==
"bar2");
1996 CHECK(root[
"bar2"][0].val() ==
"22");
1997 CHECK(root[
"bar2"][1].val() ==
"32");
2003 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
"- a\n- b\n- {x0: 1,x1: 2}\n");
2005 CHECK(root[0].val() ==
"a");
2006 CHECK(root[1].val() ==
"b");
2007 CHECK(root[2].is_map());
2008 CHECK(root[2][
"x0"].val() ==
"1");
2009 CHECK(root[2][
"x1"].val() ==
"2");
2014 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2017 - champagne: Dom Perignon
2021 CHECK(root[0].val() == "a");
2022 CHECK(root[1].val() ==
"b");
2023 CHECK(root[2].is_map());
2024 CHECK(root[2][
"x0"].val() ==
"1");
2025 CHECK(root[2][
"x1"].val() ==
"2");
2026 CHECK(root[3].is_map());
2027 CHECK(root[3][
"champagne"].val() ==
"Dom Perignon");
2028 CHECK(root[3][
"coffee"].val() ==
"Arabica");
2038 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2041 - champagne: Dom Perignon
2044 vinho verde: Soalheiro
2045 vinho tinto: Redoma 2017
2050 always: lots of water
2055 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2058 - champagne: Dom Perignon
2061 vinho verde: Soalheiro
2062 vinho tinto: Redoma 2017
2067 always: lots of water
2076 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2079 - champagne: Dom Perignon
2082 vinho verde: Soalheiro
2083 vinho tinto: Redoma 2017
2089 always: lots of water
2117 ryml::Tree champagnes =
parse_in_arena(&parser,
"champagnes.yml",
"[Dom Perignon, Gosset Grande Reserve, Jacquesson 742]");
2118 CHECK(ryml::emitrs_yaml<std::string>(champagnes) ==
"[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]");
2121 CHECK(ryml::emitrs_yaml<std::string>(beers) ==
"[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]");
2151 ryml::csubstr champagnes =
"- Dom Perignon\n- Gosset Grande Reserve\n- Jacquesson 742";
2152 ryml::csubstr beers =
"- Rochefort 10\n- Busch\n- Leffe Rituel\n- Kasteel Donker";
2153 ryml::csubstr wines =
"- Soalheiro\n- Niepoort Redoma 2017\n- Vina Esmeralda";
2156 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Dom Perignon
2157 - Gosset Grande Reserve
2163 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Dom Perignon
2164 - Gosset Grande Reserve
2175 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Soalheiro
2176 - Niepoort Redoma 2017
2191 ray: "a drop of golden sun"
2206 location: a pear tree
2214 std::vector<ryml::csubstr> keys, vals;
2217 keys.emplace_back(n.key());
2218 vals.emplace_back(n.has_val() ? n.val() : ryml::csubstr{});
2220 CHECK(keys[0] ==
"doe");
2221 CHECK(vals[0] ==
"a deer, a female deer");
2222 CHECK(keys[1] ==
"ray");
2223 CHECK(vals[1] ==
"a drop of golden sun");
2224 CHECK(keys[2] ==
"pi");
2225 CHECK(vals[2] ==
"3.14159");
2226 CHECK(keys[3] ==
"xmas");
2227 CHECK(vals[3] ==
"true");
2228 CHECK(root[5].has_key());
2229 CHECK(root[5].is_seq());
2230 CHECK(root[5].
key() ==
"calling-birds");
2231 CHECK(!root[5].has_val());
2233 CHECK(keys[5] ==
"calling-birds");
2234 CHECK(vals[5] ==
"");
2240 ryml::csubstr calling_birds[] = {
"huey",
"dewey",
"louie",
"fred"};
2242 CHECK(n.val() == calling_birds[count++]);
2267 const char a_deer[] =
"a deer, a female deer";
2276 std::string a_drop =
"a drop of golden sun";
2279 root[
"ray"] << a_drop;
2285 CHECK(root[
"ray"].val() ==
"a drop of golden sun");
2290 root[
"french-hens"] << 3;
2299 xmas5[
"calling-birds"] =
"four";
2300 xmas5[
"french-hens"] << 3;
2301 xmas5[
"golden-rings"] << 5;
2303 xmas5[
"partridges"][
"count"] << 1;
2304 xmas5[
"partridges"][
"location"] =
"a pear tree";
2305 xmas5[
"turtle-doves"] =
"two";
2306 root[
"cars"] =
"GTO";
2308 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(doe: 'a deer, a female deer'
2309 ray: a drop of golden sun
2324 location: a pear tree
2339 char buf[] =
"[a, b, c, d]";
2340 ryml::substr yml = buf;
2346 CHECK(root[0].val().is_sub(yml));
2347 CHECK(root[1].val().is_sub(yml));
2348 CHECK(root[2].val().is_sub(yml));
2349 CHECK(root[3].val().is_sub(yml));
2350 CHECK(yml.is_super(root[0].
val()));
2351 CHECK(yml.is_super(root[1].
val()));
2352 CHECK(yml.is_super(root[2].
val()));
2353 CHECK(yml.is_super(root[3].
val()));
2360 ryml::csubstr yml =
"[a, b, c, d]";
2368 ryml::csubstr arena = tree.
arena();
2369 CHECK(root[0].val().is_sub(arena));
2370 CHECK(root[1].val().is_sub(arena));
2371 CHECK(root[2].val().is_sub(arena));
2372 CHECK(root[3].val().is_sub(arena));
2373 CHECK(arena.is_super(root[0].
val()));
2374 CHECK(arena.is_super(root[1].
val()));
2375 CHECK(arena.is_super(root[2].
val()));
2376 CHECK(arena.is_super(root[3].
val()));
2382 char buf[] =
"[a, b, c, d]";
2383 ryml::substr yml = buf;
2390 CHECK(root[2].val() ==
"c");
2391 CHECK(root[2].val().is_sub(yml));
2393 CHECK(root[2].val() ==
"12345");
2399 CHECK(root[3].val() ==
"d");
2400 CHECK(root[3].val().is_sub(yml));
2402 CHECK(root[3].val() ==
"67890");
2410 ryml::csubstr yml =
"[a, b, c, d]";
2418 CHECK(root[2].val() ==
"c");
2420 CHECK(root[2].val() ==
"12345");
2429 CHECK(root[3].val() ==
"67890");
2433 CHECK(tree.
arena() ==
"[a, b, c, d]1234567890");
2440 ryml::csubstr c10 = tree.
to_arena(10101010);
2441 CHECK(c10 ==
"10101010");
2451 CHECK(root[
"a"].val() ==
"2222");
2458 ryml::csubstr mystr =
"Gosset Grande Reserve";
2460 CHECK(!copied.overlaps(mystr));
2461 CHECK(copied == mystr);
2462 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2468 ryml::csubstr mystr =
"Gosset Grande Reserve";
2469 ryml::substr copied = tree.
alloc_arena(mystr.size());
2470 CHECK(!copied.overlaps(mystr));
2471 memcpy(copied.str, mystr.str, mystr.len);
2472 CHECK(copied == mystr);
2473 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2479 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2482 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2484 CHECK(tree.
arena().first(12) ==
"{a: b}123456");
2522 CHECK(tree.
to_arena(
double(0.234)) ==
"0.234");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.234");
2532 const float fnan = std::numeric_limits<float >::quiet_NaN();
2533 const double dnan = std::numeric_limits<double>::quiet_NaN();
2534 const float finf = std::numeric_limits<float >::infinity();
2535 const double dinf = std::numeric_limits<double>::infinity();
2536 CHECK(tree.
to_arena( finf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf");
2537 CHECK(tree.
to_arena( dinf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf");
2538 CHECK(tree.
to_arena(-finf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf");
2539 CHECK(tree.
to_arena(-dinf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf");
2540 CHECK(tree.
to_arena( fnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan");
2541 CHECK(tree.
to_arena( dnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan.nan");
2545 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
2551 tree[
"ninf"] >> f;
CHECK(f == -finf);
2552 tree[
"ninf"] >> d;
CHECK(d == -dinf);
2553 tree[
"pinf"] >> f;
CHECK(f == finf);
2554 tree[
"pinf"] >> d;
CHECK(d == dinf);
2555 tree[
"nan" ] >> f;
CHECK(std::isnan(f));
2556 tree[
"nan" ] >> d;
CHECK(std::isnan(d));
2557 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2570 t[
"val"] >> valu8;
CHECK(valu8 == 2);
2571 t[
"val"] >> vali8;
CHECK(vali8 == 2);
2573 CHECK(ryml::overflows<uint8_t>(t[
"val"].val()));
2574 CHECK(ryml::overflows<int8_t>(t[
"val"].val()));
2575 CHECK( ! ryml::overflows<int16_t>(t[
"val"].val()));
2578 auto checku8 = ryml::fmt::overflow_checked(valu8);
2579 t[
"val"] >> checku8;
2582 auto checki8 = ryml::fmt::overflow_checked(vali8);
2583 t[
"val"] >> checki8;
2602 all_null: [~, null, Null, NULL]
2603 non_null: [nULL, non_null, non null, null it is not]
2607 CHECK(tree[
"plain"].has_val());
2608 CHECK(tree[
"squoted"].has_val());
2609 CHECK(tree[
"dquoted"].has_val());
2610 CHECK(tree[
"literal"].has_val());
2611 CHECK(tree[
"folded"].has_val());
2612 CHECK( ! tree[
"all_null"].has_val());
2613 CHECK( ! tree[
"non_null"].has_val());
2615 CHECK( ! tree[
"plain"].is_container());
2616 CHECK( ! tree[
"squoted"].is_container());
2617 CHECK( ! tree[
"dquoted"].is_container());
2618 CHECK( ! tree[
"literal"].is_container());
2619 CHECK( ! tree[
"folded"].is_container());
2620 CHECK(tree[
"all_null"].is_container());
2621 CHECK(tree[
"non_null"].is_container());
2626 CHECK(tree[
"plain"].val().len == 0);
2627 CHECK(tree[
"squoted"].val().len == 0);
2628 CHECK(tree[
"dquoted"].val().len == 0);
2629 CHECK(tree[
"literal"].val().len == 0);
2630 CHECK(tree[
"folded"].val().len == 0);
2632 CHECK(tree[
"plain"].val().str ==
nullptr);
2633 CHECK(tree[
"squoted"].val().str !=
nullptr);
2634 CHECK(tree[
"dquoted"].val().str !=
nullptr);
2635 CHECK(tree[
"literal"].val().str !=
nullptr);
2636 CHECK(tree[
"folded"].val().str !=
nullptr);
2640 CHECK(tree[
"plain"].val() ==
nullptr);
2641 CHECK(tree[
"squoted"].val() !=
nullptr);
2642 CHECK(tree[
"dquoted"].val() !=
nullptr);
2643 CHECK(tree[
"literal"].val() !=
nullptr);
2644 CHECK(tree[
"folded"].val() !=
nullptr);
2649 CHECK(tree[
"plain"].val_is_null());
2650 CHECK( ! tree[
"squoted"].val_is_null());
2651 CHECK( ! tree[
"dquoted"].val_is_null());
2652 CHECK( ! tree[
"literal"].val_is_null());
2653 CHECK( ! tree[
"folded"].val_is_null());
2658 CHECK(child.val() !=
nullptr);
2659 CHECK(child.val_is_null());
2663 CHECK(child.val() !=
nullptr);
2664 CHECK( ! child.val_is_null());
2675 ryml::csubstr
null = {};
2676 ryml::csubstr nonnull =
"";
2677 ryml::csubstr strnull =
"null";
2678 ryml::csubstr tilde =
"~";
2679 CHECK(
null .len == 0);
CHECK(
null .str ==
nullptr);
CHECK(
null ==
nullptr);
2680 CHECK(nonnull.len == 0);
CHECK(nonnull.str !=
nullptr);
CHECK(nonnull !=
nullptr);
2681 CHECK(strnull.len != 0);
CHECK(strnull.str !=
nullptr);
CHECK(strnull !=
nullptr);
2682 CHECK(tilde .len != 0);
CHECK(tilde .str !=
nullptr);
CHECK(tilde !=
nullptr);
2687 tree[
"empty_null"] <<
null;
CHECK(tree.
arena() ==
"");
2689 tree[
"empty_nonnull"] << nonnull;
CHECK(tree.
arena() ==
"");
2691 tree[
"str_null"] << strnull;
CHECK(tree.
arena() ==
"null");
2693 tree[
"str_tilde"] << tilde;
CHECK(tree.
arena() ==
"null~");
2695 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null:
2705 auto null_if_nullptr = [](ryml::csubstr s) {
2706 return s.str ==
nullptr ?
"null" : s;
2708 tree[
"empty_null"] << null_if_nullptr(
null);
2709 tree[
"empty_nonnull"] << null_if_nullptr(nonnull);
2710 tree[
"str_null"] << null_if_nullptr(strnull);
2711 tree[
"str_tilde"] << null_if_nullptr(tilde);
2713 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: null
2721 auto null_if_predicate = [](ryml::csubstr s) {
2724 tree[
"empty_null"] << null_if_predicate(
null);
2725 tree[
"empty_nonnull"] << null_if_predicate(nonnull);
2726 tree[
"str_null"] << null_if_predicate(strnull);
2727 tree[
"str_tilde"] << null_if_predicate(tilde);
2729 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: null
2737 auto tilde_if_predicate = [](ryml::csubstr s) {
2740 tree[
"empty_null"] << tilde_if_predicate(
null);
2741 tree[
"empty_nonnull"] << tilde_if_predicate(nonnull);
2742 tree[
"str_null"] << tilde_if_predicate(strnull);
2743 tree[
"str_tilde"] << tilde_if_predicate(tilde);
2745 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: ~
2764 char buf_[256] = {};
2765 ryml::substr buf = buf_;
2766 size_t size =
ryml::format(buf,
"a={} foo {} {} bar {}", 0.1, 10, 11, 12);
2767 CHECK(size == strlen(
"a=0.1 foo 10 11 bar 12"));
2768 CHECK(buf.first(size) ==
"a=0.1 foo 10 11 bar 12");
2771 size =
ryml::format({} ,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12);
2772 CHECK(size ==
ryml::format(buf,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12));
2773 CHECK(size == strlen(
"a=this_is_a foo 10 11 bar 12"));
2775 char smallbuf[8] = {};
2776 size =
ryml::format(smallbuf,
"{} is too large {}",
"this",
"for the buffer");
2777 CHECK(size == strlen(
"this is too large for the buffer"));
2779 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2783 CHECK(result ==
"b=1, damn it.");
2784 CHECK(result.is_sub(buf));
2802 CHECK(sbuf ==
"and c=2 seems about right");
2803 std::vector<char> vbuf;
2805 CHECK(sbuf ==
"and c=2 seems about right");
2808 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2815 int a = 0, b = 1, c = 2;
2816 ryml::csubstr result =
ryml::format_sub(buf_,
"{} and {} and {}", a, b, c);
2817 CHECK(result ==
"0 and 1 and 2");
2818 int aa = -1, bb = -2, cc = -3;
2819 size_t num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2821 CHECK(num_characters == result.size());
2827 CHECK(result ==
"10 and 20 and 30");
2828 num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2830 CHECK(num_characters == result.size());
2838 char buf_[256] = {};
2839 ryml::substr buf = buf_;
2840 size_t size =
ryml::cat(buf,
"a=", 0.1,
"foo", 10, 11,
"bar", 12);
2841 CHECK(size == strlen(
"a=0.1foo1011bar12"));
2842 CHECK(buf.first(size) ==
"a=0.1foo1011bar12");
2847 char smallbuf[8] = {};
2848 size =
ryml::cat(smallbuf,
"this",
" is too large ",
"for the buffer");
2849 CHECK(size == strlen(
"this is too large for the buffer"));
2851 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2854 ryml::csubstr result =
ryml::cat_sub(buf,
"b=", 1,
", damn it.");
2855 CHECK(result ==
"b=1, damn it.");
2856 CHECK(result.is_sub(buf));
2873 ryml::catrs(&sbuf,
"and c=", 2,
" seems about right");
2874 CHECK(sbuf ==
"and c=2 seems about right");
2875 std::vector<char> vbuf;
2876 ryml::catrs(&vbuf,
"and c=", 2,
" seems about right");
2877 CHECK(sbuf ==
"and c=2 seems about right");
2880 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2887 int a = 0, b = 1, c = 2;
2888 ryml::csubstr result =
ryml::cat_sub(buf_, a,
' ', b,
' ', c);
2889 CHECK(result ==
"0 1 2");
2890 int aa = -1, bb = -2, cc = -3;
2891 char sep1 =
'a', sep2 =
'b';
2892 size_t num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2893 CHECK(num_characters == result.size());
2901 CHECK(result ==
"10 20 30");
2902 num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2903 CHECK(num_characters == result.size());
2913 char buf_[256] = {};
2914 ryml::substr buf = buf_;
2916 size_t size =
ryml::catsep(buf,
' ',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2917 CHECK(buf.first(size) ==
"a= 0 b= 1 c= 2 45 67");
2920 size =
ryml::catsep(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2921 CHECK(buf.first(size) ==
"a=0 and b=1 and c=2 and 45 and 67");
2923 size =
ryml::catsep(buf,
" ... ",
"a=0",
"b=1",
"c=2", 45, 67);
2924 CHECK(buf.first(size) ==
"a=0 ... b=1 ... c=2 ... 45 ... 67");
2926 size =
ryml::catsep(buf,
'/',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2927 CHECK(buf.first(size) ==
"a=/0/b=/1/c=/2/45/67");
2929 size =
ryml::catsep(buf, 888,
"a=0",
"b=1",
"c=2", 45, 67);
2930 CHECK(buf.first(size) ==
"a=0888b=1888c=28884588867");
2936 char smallbuf[8] = {};
2938 CHECK(size == strlen(
"a=0888b=1888c=28884588867"));
2940 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"a=0888b\0");
2943 ryml::csubstr result =
ryml::catsep_sub(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2944 CHECK(result ==
"a=0 and b=1 and c=2 and 45 and 67");
2945 CHECK(result.is_sub(buf));
2963 CHECK(sbuf ==
"a=0 and b=1 and c=2 and 45 and 67");
2964 std::vector<char> vbuf;
2970 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");
2975 char buf_[256] = {};
2977 int a = 0, b = 1, c = 2;
2979 CHECK(result ==
"0 1 2");
2980 int aa = -1, bb = -2, cc = -3;
2983 CHECK(num_characters == result.size());
2991 CHECK(result ==
"10 20 30");
2993 CHECK(num_characters == result.size());
3002 using namespace ryml;
3003 char buf_[256] = {};
3022 CHECK(
"3735928559" ==
cat_sub(buf, UINT32_C(0xdeadbeef)));
3146 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wcast-align")
3147 const uint32_t payload[] = {10, 20, 30, 40, UINT32_C(0xdeadbeef)};
3149 csubstr expected = csubstr((
const char *)payload,
sizeof(payload));
3151 CHECK(!actual.overlaps(expected));
3152 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3154 for(
const uint32_t value : payload)
3157 expected = csubstr((
const char *)&value,
sizeof(value));
3159 CHECK(actual.size() ==
sizeof(uint32_t));
3160 CHECK(!actual.overlaps(expected));
3161 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3164 CHECK(actual.size() ==
sizeof(uint32_t));
3165 CHECK(!actual.overlaps(expected));
3166 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3171 CHECK(&result == (uint32_t*)reader.buf);
3172 CHECK(reader.len ==
sizeof(uint32_t));
3173 uncat(actual, reader);
3176 result = *(uint32_t*)reader.buf;
3177 CHECK(result == value);
3179 C4_SUPPRESS_WARNING_GCC_CLANG_POP
3198 struct text_and_base64 { ryml::csubstr text,
base64; };
3199 text_and_base64 cases[] = {
3200 {{
"Love all, trust a few, do wrong to none."}, {
"TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg=="}},
3201 {{
"The fool doth think he is wise, but the wise man knows himself to be a fool."}, {
"VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg=="}},
3202 {{
"Brevity is the soul of wit."}, {
"QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu"}},
3203 {{
"All that glitters is not gold."}, {
"QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu"}},
3206 for(text_and_base64 c : cases)
3209 CHECK(tree[c.text].
val() == c.base64);
3212 for(text_and_base64 c : cases)
3215 CHECK(tree[c.base64].
val() == c.text);
3217 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"('Love all, trust a few, do wrong to none.': TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg==
3218 'The fool doth think he is wise, but the wise man knows himself to be a fool.': VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg==
3219 Brevity is the soul of wit.: QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu
3220 All that glitters is not gold.: QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu
3221 TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg==: 'Love all, trust a few, do wrong to none.'
3222 VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg==: 'The fool doth think he is wise, but the wise man knows himself to be a fool.'
3223 QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu: Brevity is the soul of wit.
3224 QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu: All that glitters is not gold.
3226 char buf1_[128], buf2_[128];
3227 ryml::substr buf1 = buf1_;
3228 ryml::substr buf2 = buf2_;
3229 std::string result = {};
3231 for(
const text_and_base64 c : cases)
3236 CHECK(len <= buf1.len);
3237 CHECK(len <= buf2.len);
3238 CHECK(c.text.len == len);
3239 CHECK(buf1.first(len) == c.text);
3240 CHECK(buf2.first(len) == c.text);
3245 if(len > result.size())
3251 CHECK(result == c.text);
3255 ryml::blob strblob(&result[0], result.size());
3256 CHECK(strblob.buf == result.data());
3257 CHECK(strblob.len == result.size());
3259 if(len > result.size())
3262 strblob = {&result[0], result.
size()};
3263 CHECK(strblob.buf == result.data());
3264 CHECK(strblob.len == result.size());
3268 CHECK(result == c.text);
3273 ryml::csubstr encoded = tree[c.text].
val();
3274 CHECK(encoded == c.base64);
3275 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3276 if(len > result.size())
3279 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3282 CHECK(result == c.text);
3285 for(
const text_and_base64 c : cases)
3290 CHECK(len <= buf1.len);
3291 CHECK(len <= buf2.len);
3292 CHECK(c.text.len == len);
3293 CHECK(buf1.first(len) == c.text);
3294 CHECK(buf2.first(len) == c.text);
3298 if(len > result.size())
3304 CHECK(result == c.text);
3308 ryml::blob strblob = {&result[0], result.size()};
3309 CHECK(strblob.buf == result.data());
3310 CHECK(strblob.len == result.size());
3312 if(len > result.size())
3315 strblob = {&result[0], result.
size()};
3316 CHECK(strblob.buf == result.data());
3317 CHECK(strblob.len == result.size());
3321 CHECK(result == c.text);
3326 ryml::csubstr encoded = tree[c.base64].
key();
3327 CHECK(encoded == c.base64);
3328 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3329 if(len > result.size())
3332 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3335 CHECK(result == c.text);
3339 const uint64_t valin = UINT64_C(0xdeadbeef);
3340 uint64_t valout = 0;
3343 CHECK(len <=
sizeof(valout));
3344 CHECK(valout == UINT64_C(0xdeadbeef));
3348 const uint32_t data_in[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xdeadbeef};
3349 uint32_t data_out[11] = {};
3350 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) != 0);
3353 CHECK(len <=
sizeof(data_out));
3354 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) == 0);
3589 CHECK(v2in.x == v2out.x);
3590 CHECK(v2in.y == v2out.y);
3595 CHECK(v3in.x == v3out.x);
3596 CHECK(v3in.y == v3out.y);
3597 CHECK(v3in.z == v3out.z);
3602 CHECK(v4in.x == v4out.x);
3603 CHECK(v4in.y == v4out.y);
3604 CHECK(v4in.z == v4out.z);
3605 CHECK(v4in.w == v4out.w);
3606 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(10,11)'
3608 v4: '(1000,1001,1002,1003)'
3618 CHECK(eov2in.x == pov2out.x);
3619 CHECK(eov2in.y == pov2out.y);
3624 CHECK(eov3in.x == pov3out.x);
3625 CHECK(eov3in.y == pov3out.y);
3626 CHECK(eov3in.z == pov3out.z);
3631 CHECK(eov4in.x == pov4out.x);
3632 CHECK(eov4in.y == pov4out.y);
3633 CHECK(eov4in.z == pov4out.z);
3634 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(20,21)'
3688 template<
class K,
class V>
3713 template<
class K,
class V>
3741 template<
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}}},
3797 CHECK(mt_in.seq.seq_member.size() > 0);
3799 for(
size_t i = 0; i < mt_in.seq.seq_member.size(); ++i)
3803 CHECK(mt_in.map.map_member.size() > 0);
3805 for(
auto const& kv : mt_in.map.map_member)
3810 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(20,21)'
3837 std::string yml_std_string = R
"(- v2: '(20,21)'
3854 v4: '(140,141,142,143)'
3869 v4: '(240,241,242,243)'
3887 std::vector<my_type> vmt;
3889 CHECK(vmt.size() == 3);
3892 CHECK(ryml::emitrs_yaml<std::string>(tree_out) == yml_std_string);
3901 std::vector<double> reference{1.23234412342131234, 2.12323123143434237, 3.67847983572591234};
3905 const double precision_safe = 1.e-14;
3906 const size_t num_digits_safe = 14;
3907 const size_t num_digits_original = 17;
3908 auto get_num_digits = [](ryml::csubstr number){
return number.sub(2).len; };
3914 std::vector<double> output;
3916 CHECK(output.size() == reference.size());
3917 for(
size_t i = 0; i < reference.size(); ++i)
3920 CHECK(fabs(output[i] - reference[i]) < precision_safe);
3929 serialized.
rootref() << reference;
3930 std::cout << serialized;
3932 #if (!C4CORE_HAVE_STD_TOCHARS)
3933 CHECK(ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.23234
3936 )" || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3937 C4_UNUSED(num_digits_safe);
3939 CHECK((ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.2323441234213124
3940 - 2.1232312314343424
3941 - 3.6784798357259123
3942 )") || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3946 CHECK(get_num_digits(child.val()) >= num_digits_safe);
3949 CHECK(fabs(out - reference[pos++]) < precision_safe);
3980 auto check_precision = [&](
ryml::Tree const& serialized){
3981 std::cout << serialized;
3983 CHECK((ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.23234412342131239
3984 - 2.12323123143434245
3985 - 3.67847983572591231
3986 )") || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3990 CHECK(get_num_digits(child.val()) == num_digits_original);
3993 CHECK(fabs(out - reference[pos++]) < precision_safe);
4002 for(
const double v : reference)
4004 check_precision(serialized);
4013 for(
const double v : reference)
4018 (void)snprintf(tmp,
sizeof(tmp),
"%.18g", v);
4024 check_precision(serialized);
4036 ryml::csubstr ymla =
"- 1\n- 2\n";
4037 ryml::csubstr ymlb = R
"(- a
4041 - champagne: Dom Perignon
4044 vinho verde: Soalheiro
4045 vinho tinto: Redoma 2017
4064 CHECK(output.str ==
nullptr);
4065 CHECK(output.len > 0);
4066 size_t num_needed_chars = output.len;
4067 std::vector<char> buf(num_needed_chars);
4070 CHECK(output == ymla);
4075 CHECK(output.str ==
nullptr);
4076 CHECK(output.len > 0);
4077 CHECK(output.len == ymlb.len);
4078 num_needed_chars = output.len;
4079 buf.resize(num_needed_chars);
4082 CHECK(output == ymlb);
4087 CHECK(output == ymlb);
4091 std::vector<char> another = ryml::emitrs_yaml<std::vector<char>>(treeb);
4095 another = ryml::emitrs_yaml<std::vector<char>>(treeb[3][2]);
4097 vinho verde: Soalheiro
4098 vinho tinto: Redoma 2017
4109 CHECK(output.str ==
nullptr);
4110 CHECK(output.len > 0);
4111 size_t num_needed_chars = output.len;
4113 buf.resize(num_needed_chars);
4116 CHECK(output == ymla);
4121 CHECK(output.str ==
nullptr);
4122 CHECK(output.len > 0);
4123 CHECK(output.len == ymlb.len);
4124 num_needed_chars = output.len;
4125 buf.resize(num_needed_chars);
4128 CHECK(output == ymlb);
4133 CHECK(output == ymlb);
4137 std::string another = ryml::emitrs_yaml<std::string>(treeb);
4141 another = ryml::emitrs_yaml<std::string>(treeb[3][2]);
4143 vinho verde: Soalheiro
4144 vinho tinto: Redoma 2017
4155 ryml::csubstr ymlb = R
"(- a
4159 - champagne: Dom Perignon
4162 vinho verde: Soalheiro
4163 vinho tinto: Redoma 2017
4179 std::stringstream ss;
4187 std::stringstream ss;
4198 "champagne": "Dom Perignon",
4199 "coffee": "Arabica",
4201 "vinho verde": "Soalheiro",
4202 "vinho tinto": "Redoma 2017"
4220 std::stringstream ss;
4224 vinho verde: Soalheiro
4225 vinho tinto: Redoma 2017
4231 std::stringstream ss;
4235 "vinho verde": "Soalheiro",
4236 "vinho tinto": "Redoma 2017"
4248 ryml::csubstr yml = R
"(- a
4252 - champagne: Dom Perignon
4255 vinho verde: Soalheiro
4256 vinho tinto: Redoma 2017
4272 CHECK(len == yml.len);
4285 - champagne: Dom Perignon
4288 vinho verde: Soalheiro
4289 vinho tinto: Redoma 2017
4302 CHECK(ryml::emitrs_yaml<std::string>(tree[3]["beer"]) == R
"(beer:
4310 CHECK(ryml::emitrs_yaml<std::string>(tree[3]["beer"][0]) ==
"Rochefort 10");
4311 CHECK(ryml::emitrs_yaml<std::string>(tree[3][
"beer"][3]) == R
"(- and so
4327 ryml::csubstr yaml = R
"(block map:
4328 block key: block val
4333 flow map, singleline: {flow key: flow val}
4334 flow seq, singleline: [flow val,flow val]
4335 flow map, multiline: {
4338 flow seq, multiline: [
4346 CHECK(tree[
"block map"].is_key_plain());
4347 CHECK(tree[
"block seq"].is_key_plain());
4348 CHECK(tree[
"flow map, singleline"].is_key_plain());
4349 CHECK(tree[
"flow seq, singleline"].is_key_plain());
4350 CHECK(tree[
"flow map, multiline"].is_key_plain());
4351 CHECK(tree[
"flow seq, multiline"].is_key_plain());
4352 CHECK(tree[
"block map"].is_block());
4353 CHECK(tree[
"block seq"].is_block());
4355 CHECK(tree[
"flow map, singleline"].is_flow_sl());
4356 CHECK(tree[
"flow seq, singleline"].is_flow_sl());
4357 CHECK(tree[
"flow map, multiline"].is_flow_ml());
4358 CHECK(tree[
"flow seq, multiline"].is_flow_ml());
4360 CHECK(tree[
"flow map, singleline"].is_flow());
4361 CHECK(tree[
"flow seq, singleline"].is_flow());
4362 CHECK(tree[
"flow map, multiline"].is_flow());
4363 CHECK(tree[
"flow seq, multiline"].is_flow());
4369 CHECK(tostr(tree) == yaml);
4378 CHECK(tostr(n) ==
"block map:\n block key: block val\n");
4383 CHECK(tostr(n) ==
"'block map': {block key: block val}\n");
4388 CHECK(tostr(n) ==
"block seq:\n - block val 1\n - block val 2\n - 'quoted'\n");
4392 CHECK(tostr(n) ==
"\"block seq\": [\n block val 1,\n block val 2,\n quoted\n ]\n");
4397 CHECK(tostr(n) ==
"flow map, singleline: {flow key: flow val}\n");
4400 CHECK(tostr(n) ==
"flow map, singleline:\n flow key: |-\n flow val\n");
4405 CHECK(tostr(n) ==
"flow map, multiline: {\n flow key: flow val\n }\n");
4407 CHECK(tostr(n) ==
"flow map, multiline:\n flow key: flow val\n");
4412 CHECK(tostr(n) ==
"flow seq, singleline: [flow val,flow val]\n");
4417 CHECK(tostr(n) ==
"? >-\n flow seq, singleline\n:\n - 'flow val'\n - \"flow val\"\n");
4422 CHECK(tostr(n) ==
"flow seq, multiline: [\n flow val,\n flow val\n ]\n");
4424 CHECK(tostr(n) ==
"flow seq, multiline: [flow val,flow val]\n");
4427 CHECK(tostr(tree) != yaml);
4428 CHECK(tostr(tree) ==
4429 R
"('block map': {block key: block val}
4435 flow map, singleline:
4439 flow seq, singleline
4443 flow map, multiline:
4445 flow seq, multiline: [flow val,flow val]
4450 CHECK(tostr(tree) ==
4452 block key: block val
4457 flow map, singleline:
4461 flow seq, singleline
4465 flow map, multiline:
4467 flow seq, multiline: [flow val,flow val]
4476 CHECK(tostr(tree) ==
4478 block key: block val
4483 'flow map, singleline':
4485 'flow seq, singleline':
4488 'flow map, multiline':
4490 'flow seq, multiline':
4501 CHECK(tostr(tree) ==
4503 block key: block val
4508 'flow map, singleline':
4510 'flow seq, singleline':
4513 'flow map, multiline':
4515 'flow seq, multiline':
4540 CHECK(tostr(tree) ==
4542 'block key': "block val"
4543 'block seq': ["block val 1","block val 2","quoted"]
4544 'flow map, singleline':
4545 'flow key': "flow val"
4546 'flow seq, singleline': ["flow val","flow val"]
4547 'flow map, multiline':
4548 'flow key': "flow val"
4549 'flow seq, multiline': ["flow val","flow val"]
4556 CHECK(tostr(tree) ==
4558 'block key': "block val"
4559 'block seq': ["block val 1","block val 2","quoted"]
4560 'flow map, singleline':
4561 'flow key': "flow val"
4562 'flow seq, singleline':
4565 'flow map, multiline':
4566 'flow key': "flow val"
4567 'flow seq, multiline': ["flow val","flow val"]
4584 return ryml::emitrs_yaml<std::string>(n, opts);
4586 ryml::csubstr yaml =
"{map: {seq: [0, 1, 2, 3, [40, 41]]}}";
4590 CHECK(tostr(tree, defaults) ==
"{map: {seq: [0,1,2,3,[40,41]]}}");
4597 CHECK(tostr(tree, defaults) ==
4615 CHECK(tostr(tree, noindent) ==
4634 CHECK(tostr(tree, noindent) ==
4650 CHECK(tostr(tree, noindent) ==
4672 ryml::csubstr yaml = R
"({
4687 ryml::csubstr yaml_not_indented = R"({
4706 CHECK(tree[
"map"].is_flow_ml());
4708 CHECK(ryml::emitrs_yaml<std::string>(tree) == yaml);
4715 CHECK(tree[
"map"].is_flow_sl());
4717 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
4718 R
"({map: {seq: [0,1,2,3,[40,41]]}})");
4725 CHECK(tree[
"map"].is_flow_ml());
4726 CHECK(ryml::emitrs_yaml<std::string>(tree, noindent) == yaml_not_indented);
4739 ryml::csubstr json = R
"({
4740 "doe": "a deer, a female deer",
4741 "ray": "a drop of golden sun",
4742 "me": "a name, I call myself",
4743 "far": "a long long way to go"
4754 CHECK(ryml::emitrs_json<std::string>(tree) == json);
4755 CHECK(ryml::emitrs_json<std::string>(json_tree) == json);
4757 std::stringstream ss;
4759 CHECK(ss.str() == json);
4776 std::cout << ryml::emitrs_yaml<std::string>(json_tree);
4777 CHECK(ryml::emitrs_yaml<std::string>(json_tree) == json);
4782 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4783 R
"("doe": "a deer, a female deer"
4784 "ray": "a drop of golden sun"
4785 "me": "a name, I call myself"
4786 "far": "a long long way to go"
4793 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4794 R
"(doe: 'a deer, a female deer'
4795 ray: a drop of golden sun
4796 me: 'a name, I call myself'
4797 far: a long long way to go
4805 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4806 R
"(doe: 'a deer, a female deer'
4807 ray: 'a drop of golden sun'
4808 me: 'a name, I call myself'
4809 far: 'a long long way to go'
4839 std::string unresolved = R
"(base: &base
4840 name: Everyone has same name
4851 city: East Centerville
4854 &keyref key: &valref val
4857 std::string resolved = R"(base:
4858 name: Everyone has same name
4860 name: Everyone has same name
4863 name: Everyone has same name
4869 city: East Centerville
4875 city: East Centerville
4883 CHECK( ! tree[
"base"].has_key_anchor());
4884 CHECK( tree[
"base"].has_val_anchor());
4885 CHECK( tree[
"base"].val_anchor() ==
"base");
4886 CHECK( tree[
"key"].key_anchor() ==
"keyref");
4887 CHECK( tree[
"key"].val_anchor() ==
"valref");
4888 CHECK( tree[
"*valref"].is_key_ref());
4889 CHECK( tree[
"*valref"].is_val_ref());
4890 CHECK( tree[
"*valref"].key_ref() ==
"valref");
4891 CHECK( tree[
"*valref"].val_ref() ==
"keyref");
4898 CHECK( ! tree[
"base"].has_key_anchor());
4899 CHECK( ! tree[
"base"].has_val_anchor());
4900 CHECK( ! tree[
"base"].has_val_anchor());
4901 CHECK( ! tree[
"key"].has_key_anchor());
4902 CHECK( ! tree[
"key"].has_val_anchor());
4903 CHECK( ! tree[
"val"].is_key_ref());
4904 CHECK( ! tree[
"val"].is_val_ref());
4906 CHECK(tree[
"ship_to"][
"city"].val() ==
"East Centerville");
4907 CHECK(tree[
"ship_to"][
"state"].val() ==
"KS");
4925 t[
"nref"] =
"*vanchor";
4926 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(&kanchor kanchor: 2
4933 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(kanchor: 2
4944 orig: &orig {foo: bar, baz: bat}
4952 t[
"notref"][
"<<"] =
"*orig";
4953 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(orig: &orig {foo: bar,baz: bat}
4955 notcopy: {test: *orig,<<: *orig}
4956 notref: {<<: '*orig'}
4959 CHECK(ryml::emitrs_yaml<std::string>(t) == R"(orig: {foo: bar,baz: bat}
4960 copy: {foo: bar,baz: bat}
4961 notcopy: {test: {foo: bar,baz: bat},foo: bar,baz: bat}
4962 notref: {<<: '*orig'}
4969 orig2: &orig2 {baz: bat}
4970 orig3: &orig3 {and: more}
4978 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(orig1: &orig1 {foo: bar}
4979 orig2: &orig2 {baz: bat}
4980 orig3: &orig3 {and: more}
4981 copy: {<<: [*orig1,*orig2,*orig3]}
4984 CHECK(ryml::emitrs_yaml<std::string>(t) == R"(orig1: {foo: bar}
4987 copy: {foo: bar,baz: bat,and: more}
4997 const std::string yaml = R
"(--- !!map
5023 CHECK(doc.is_doc());
5025 CHECK(root[0].has_val_tag());
5026 CHECK(root[0].val_tag() ==
"!!map");
5027 CHECK(root[1].val_tag() ==
"!map");
5028 CHECK(root[2].val_tag() ==
"!!seq");
5029 CHECK(root[3].val_tag() ==
"!!str");
5030 CHECK(root[4].val_tag() ==
"!!str");
5031 CHECK(root[5][
"a"].has_key_tag());
5032 CHECK(root[5][
"a"].key_tag() ==
"!!str");
5033 CHECK(root[6].val_tag() ==
"!!set");
5034 CHECK(root[7].val_tag() ==
"!!set");
5035 CHECK(root[8].val_tag() ==
"!!seq");
5036 CHECK(root[8][0].val_tag() ==
"!!int");
5037 CHECK(root[8][1].val_tag() ==
"!!str");
5086 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree) == R
"(--- !!map
5109 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree_long) == R
"(--- !<tag:yaml.org,2002:map>
5114 --- !<tag:yaml.org,2002:seq>
5117 --- !<tag:yaml.org,2002:str> a b
5118 --- !<tag:yaml.org,2002:str> 'a: b'
5120 !<tag:yaml.org,2002:str> a: b
5121 --- !<tag:yaml.org,2002:set>
5124 --- !<tag:yaml.org,2002:set>
5126 --- !<tag:yaml.org,2002:seq>
5127 - !<tag:yaml.org,2002:int> 0
5128 - !<tag:yaml.org,2002:str> 1
5137 const std::string yaml = R
"(
5140 !m!light fluorescent
5147 CHECK(ryml::emitrs_yaml<std::string>(tree) == R"(%TAG !m! !my-
5148 --- !m!light fluorescent
5156 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(%TAG !m! !my-
5157 --- !<!my-light> fluorescent
5160 --- !<!meta-light> green
5171 std::string yml = R
"(---
5184 CHECK(ryml::emitrs_yaml<std::string>(tree) == yml);
5195 CHECK(doc.is_doc());
5212 CHECK(stream[0].is_doc());
5213 CHECK(stream[0].is_map());
5214 CHECK(stream[0][
"a"].val() ==
"0");
5215 CHECK(stream[0][
"b"].val() ==
"1");
5224 CHECK(stream[1].is_doc());
5225 CHECK(stream[1].is_map());
5226 CHECK(stream[1][
"c"].val() ==
"2");
5227 CHECK(stream[1][
"d"].val() ==
"3");
5236 CHECK(stream[2].is_doc());
5237 CHECK(stream[2].is_seq());
5238 CHECK(stream[2][0].val() ==
"4");
5239 CHECK(stream[2][1].val() ==
"5");
5240 CHECK(stream[2][2].val() ==
"6");
5241 CHECK(stream[2][3].val() ==
"7");
5260 const std::string expected_json[] = {
5261 "{\n \"a\": 0,\n \"b\": 1\n}\n",
5262 "{\n \"c\": 2,\n \"d\": 3\n}\n",
5263 "[\n 4,\n 5,\n 6,\n 7\n]\n",
5272 CHECK(ryml::emitrs_json<std::string>(doc) == expected_json[count++]);
5282 CHECK(ryml::emitrs_json<std::string>(tree, doc_id) == expected_json[count++]);
5321 ryml::Tree tree = ryml::parse_in_arena(
"errorhandler.yml",
"[a: b\n}");
5332 auto cause_basic_error = []{
5340 #ifdef _RYML_WITH_EXCEPTIONS
5344 cause_basic_error();
5351 CHECK(!msg.empty());
5359 ryml::csubstr ymlsrc = R
"({
5363 ryml::csubstr ymlfile = "file.yml";
5364 auto cause_parse_error = [&]{
5388 msg_ctx.append(s.str, s.len);
5390 CHECK(
ryml::to_csubstr(msg_ctx).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5432 CHECK(errh.
saved_msg_full ==
"file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
5445 #ifdef _RYML_WITH_EXCEPTIONS
5449 cause_parse_error();
5466 auto dumpfn = [&full](ryml::csubstr s) { full.append(s.str, s.len); };
5470 CHECK(
ryml::to_csubstr(full).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5490 cause_parse_error();
5497 CHECK(!msg.empty());
5508 ryml::csubstr ymlfile =
"file.yml";
5509 ryml::csubstr ymlsrc =
"float: 123.456";
5516 tree[
"float"] >> intval;
5545 tree[
"float"] >> intval;
5557 #ifdef _RYML_WITH_EXCEPTIONS
5569 tree[
"float"] >> intval;
5578 CHECK(!msg.empty());
5590 tree[
"float"] >> intval;
5597 CHECK(!msg.empty());
5622 ryml::csubstr ymlfile =
"file.yml";
5623 ryml::csubstr ymlsrc = R
"(foo: bar
5630 auto cause_visit_error = [&]{
5632 tree[
"float"] >> intval;
5664 msg.append(s.str, s.len);
5665 }, ymlloc, ymlsrc,
"err", 3);
5708 std::vector<char>
memory_pool = std::vector<char>(10u * 1024u);
5718 uintptr_t uptr = (uintptr_t)ptr;
5719 const uintptr_t align =
alignof(max_align_t);
5722 uintptr_t prev = uptr - (uptr % align);
5723 uintptr_t next = prev + align;
5724 uintptr_t corr = next - uptr;
5725 ptr = (
void*)(((
char*)ptr) + corr);
5729 "out of memory! requested=%zu+%zu available=%zu\n",
5734 void free(
void *mem,
size_t len)
5751 static void*
s_allocate(
size_t len,
void* ,
void *this_)
5755 static void s_free(
void *mem,
size_t len,
void *this_)
5816 parser.reserve_stack(10);
5822 parser.reserve_stack(20);
5827 parse_in_arena(&parser,
"", R
"([a, b, c, d, {foo: bar, money: pennys}])", &tree);
5846 std::vector<char>
memory_pool = std::vector<char>(10u * 1024u);
5870 std::cerr <<
"out of memory! requested=" <<
alloc_size <<
" vs " <<
memory_pool.size() <<
" available" << std::endl;
5876 void free(
void *mem,
size_t len)
5921 ryml::csubstr yml1 =
"{a: b}";
5922 ryml::csubstr yml2 =
"{c: d, e: f, g: [h, i, 0, 1, 2, 3]}";
5956 CHECK(tree["doe"].val() ==
"a deer, a female deer");
5970 ryml::csubstr yaml = R
"({
5972 foo: [one, [two, three]]
5981 CHECK(parser.options().locations());
5994 parser.reserve_locations(50u);
6003 CHECK(parser.location_contents(loc).begins_with(
"{"));
6010 CHECK(parser.location_contents(loc).begins_with(
"aa"));
6015 loc = tree[
"foo"].
location(parser);
6016 CHECK(parser.location_contents(loc).begins_with(
"foo"));
6020 loc = tree[
"foo"][0].
location(parser);
6021 CHECK(parser.location_contents(loc).begins_with(
"one"));
6025 loc = tree[
"foo"][1].
location(parser);
6026 CHECK(parser.location_contents(loc).begins_with(
"["));
6029 loc = tree[
"foo"][1][0].
location(parser);
6030 CHECK(parser.location_contents(loc).begins_with(
"two"));
6033 loc = tree[
"foo"][1][1].
location(parser);
6034 CHECK(parser.location_contents(loc).begins_with(
"three"));
6048 CHECK(parser.location_contents(loc).begins_with(
"this is a docval"));
6063 - nested first value
6064 - nested second value
6067 nested second: value
6076 CHECK(parser.location_contents(loc).begins_with(
"a new"));
6081 loc = tree2[
"a new"].
location(parser);
6082 CHECK(parser.location_contents(loc).begins_with(
"a new"));
6086 loc = tree2[
"to"].
location(parser);
6087 CHECK(parser.location_contents(loc).begins_with(
"to"));
6092 loc = tree2[
"map with key"].
location(parser);
6093 CHECK(parser.location_contents(loc).begins_with(
"map with key"));
6096 loc = tree2[
"map with key"][
"first"].
location(parser);
6097 CHECK(parser.location_contents(loc).begins_with(
"first"));
6100 loc = tree2[
"map with key"][
"second"].
location(parser);
6101 CHECK(parser.location_contents(loc).begins_with(
"second"));
6105 loc = tree2[
"seq with key"].
location(parser);
6106 CHECK(parser.location_contents(loc).begins_with(
"seq with key"));
6109 loc = tree2[
"seq with key"][0].
location(parser);
6110 CHECK(parser.location_contents(loc).begins_with(
"first value"));
6113 loc = tree2[
"seq with key"][1].
location(parser);
6114 CHECK(parser.location_contents(loc).begins_with(
"second value"));
6118 loc = tree2[
"seq with key"][2].
location(parser);
6119 CHECK(parser.location_contents(loc).begins_with(
"- nested first value"));
6122 loc = tree2[
"seq with key"][2][0].
location(parser);
6123 CHECK(parser.location_contents(loc).begins_with(
"nested first value"));
6128 CHECK(parser.location_contents(loc).begins_with(
"nested first: "));
6131 loc = tree2[
"seq with key"][3][0].
location(parser);
6132 CHECK(parser.location_contents(loc).begins_with(
"nested first: "));
6147 static int num_checks = 0;
6148 static int num_failed_checks = 0;
6152 bool report_check(
int line,
const char *predicate,
bool result)
6155 const char *msg = predicate ?
"OK! " :
"OK!";
6158 ++num_failed_checks;
6159 msg = predicate ?
"FAIL: " :
"FAIL";
6161 std::cout << __FILE__ <<
':' << line <<
": " << msg << (predicate ? predicate :
"") << std::endl;
6168 std::cout <<
"Completed " << num_checks <<
" checks." << std::endl;
6169 if(num_failed_checks)
6170 std::cout <<
"ERROR: " << num_failed_checks <<
'/' << num_checks <<
" checks failed." << std::endl;
6172 std::cout <<
"SUCCESS!" << std::endl;
6173 return num_failed_checks;
6185 void errdump(ryml::csubstr s)
6188 fwrite(s.str, 1, s.len, stderr);
6194 fputc(
'\n', stderr);
6209 .set_free([](
void* mem,
size_t,
void *){
6245 #ifdef RYML_NO_DEFAULT_CALLBACKS
6254 #ifndef C4_EXCEPTIONS
6285 bool got_error =
false;
6286 #ifdef C4_EXCEPTIONS
6289 std::forward<Fn>(fn)();
6291 catch(std::exception
const&)
6298 std::forward<Fn>(fn)();
6311 [[noreturn]]
void stopexec(std::string
const& s)
6313 #ifdef C4_EXCEPTIONS
6314 throw std::runtime_error(s);
6438 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4996)
6439 C4_SUPPRESS_WARNING_CLANG_WITH_PUSH("-Wdeprecated-declarations")
6441 template<class CharContainer>
6444 std::FILE *fp = std::fopen(filename,
"rb");
6445 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6446 std::fseek(fp, 0, SEEK_END);
6447 long sz = std::ftell(fp);
6448 v->resize(
static_cast<typename CharContainer::size_type
>(sz));
6452 size_t ret = std::fread(&(*v)[0], 1, v->size(), fp);
6453 if(ret != (
size_t)sz) _RYML_ERR_BASIC(
"{}: failed to read: expect {}B, got {}B", filename, sz, ret);
6460 template<
class CharContainer>
6469 template<
class CharContainer>
6470 void file_put_contents(
const char *filename, CharContainer
const& v,
const char* access)
6476 void file_put_contents(
const char *filename,
const char *buf,
size_t sz,
const char* access)
6478 std::FILE *fp = std::fopen(filename, access);
6479 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6480 std::fwrite(buf, 1, sz, fp);
6483 C4_SUPPRESS_WARNING_CLANG_POP
6484 C4_SUPPRESS_WARNING_MSVC_POP
6490 C4_SUPPRESS_WARNING_GCC_CLANG_POP
Holds a pointer to an existing tree, and a node id.
Tree const * tree() const noexcept
id_type id() const noexcept
bool invalid() 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)
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens,...
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.
void clear()
clear the tree and zero every node
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 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)
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
Callbacks const & callbacks() const
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.
csubstr const & key(id_type node) const
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)
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()
csubstr const & val(id_type node) const
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.
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.
left_< T > left(T val, size_t width, char padchar=' ')
mark an argument to be aligned left
right_< T > right(T val, size_t width, char padchar=' ')
mark an argument to be aligned right
const_base64_wrapper base64(Args const &...args)
mark a variable to be written in base64 format
size_t base64_decode(csubstr encoded, blob data)
decode the base64 encoding in the given buffer
boolalpha_< T > boolalpha(T const &val, bool strict_read=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
substr cat_sub(substr buf, Args &&...args)
like c4::cat() but return a substr instead of a size
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.
csubstr catseprs_append(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize+append: like 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_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.
integral_< intptr_t > hex(std::nullptr_t)
format null as an hexadecimal value
integral_< intptr_t > bin(std::nullptr_t)
format null as a binary 0-1 value
integral_< intptr_t > oct(std::nullptr_t)
format null as an octal 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 >
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.
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 file_put_contents(const char *filename, CharContainer const &v, const char *access="wb")
save a buffer into a file
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
CharContainer file_get_contents(const char *filename)
load a file from disk and return a newly created CharContainer
#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
size_t to_chars(ryml::substr buf, vec2< T > v)
csubstr to_csubstr(substr s) noexcept
neutral version for use in generic code
substr to_substr(substr s) noexcept
neutral version for use in generic code
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)
@ TAG_SET
!!set Unordered set of non-equal values.
@ TAG_INT
!!float Mathematical integers.
@ TAG_SEQ
!!seq Sequence of arbitrary values.
@ TAG_STR
!!str A sequence of zero or more Unicode characters.
@ TAG_MAP
!!map Unordered set of key: value pairs without duplicates.
size_t uncat(csubstr buf, Arg &a, Args &...more)
deserialize the arguments from the given buffer.
size_t uncatsep(csubstr buf, Sep &sep, Arg &a, Args &...more)
deserialize the arguments from the given buffer.
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)
void * allocate(size_t len)
~GlobalAllocatorExample()
std::vector< char > memory_pool
static void s_free(void *mem, size_t len, void *this_)
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 free(void *mem, size_t len)
void * allocate(size_t len)
Shows how to create a scoped error handler.
~ScopedErrorHandlerExample()
ScopedErrorHandlerExample()
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.
Exception thrown by the default basic error implementation.
ErrorDataBasic errdata_basic
error data
const char * what() const noexcept override
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 & locations(bool enabled) noexcept
enable/disable source location tracking
ParserOptions & detect_flow_ml(bool enabled) noexcept
enable/disable detection of FLOW_ML container style.
bool create_from_str(csubstr directive_)
leaves next_node_id unfilled
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