75 #if defined(RYML_SINGLE_HEADER)
76 #define RYML_SINGLE_HDR_DEFINE_NOW
77 #include <ryml_all.hpp>
78 #elif defined(RYML_SINGLE_HEADER_LIB)
79 #include <ryml_all.hpp>
207 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
208 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wcast-qual")
209 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
210 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
229 template<
class Fn>
bool check_error_occurs(Fn &&fn);
230 template<
class Fn>
bool check_assertion_occurs(Fn &&fn);
231 void check_enabled()
const;
232 void check_disabled()
const;
241 [[noreturn]]
static void s_error_basic(ryml::csubstr msg,
ryml::ErrorDataBasic const& errdata,
void *this_);
242 [[noreturn]]
static void s_error_parse(ryml::csubstr msg,
ryml::ErrorDataParse const& errdata,
void *this_);
243 [[noreturn]]
static void s_error_visit(ryml::csubstr msg,
ryml::ErrorDataVisit const& errdata,
void *this_);
267 template<
class CharContainer> CharContainer
file_get_contents(
const char *filename);
268 template<
class CharContainer>
size_t file_get_contents(
const char *filename, CharContainer *v);
269 template<
class CharContainer>
void file_put_contents(
const char *filename, CharContainer
const& v,
const char* access=
"wb");
270 void file_put_contents(
const char *filename,
const char *buf,
size_t sz,
const char* access);
273 bool report_check(
int line,
const char *predicate,
bool result);
276 #if defined(__DOXYGEN__) || defined(_DOXYGEN_)
278 # define CHECK(predicate) assert(predicate)
280 # if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
282 # define CHECK(predicate) do { if(!report_check(__LINE__, #predicate, (predicate))) { RYML_DEBUG_BREAK(); } } while(0)
285 # define CHECK CheckPredicate{__FILE__, __LINE__}
286 struct CheckPredicate
290 void operator() (
bool result)
const
313 char yml_buf[] =
"{foo: 1, bar: [2, 3], john: doe}";
318 CHECK(bar[0].val() ==
"2");
319 CHECK(bar[1].val() ==
"3");
320 CHECK(bar[0].val().str == yml_buf + 15);
321 CHECK(bar[1].val().str == yml_buf + 18);
324 int bar0 = 0, bar1 = 0;
333 CHECK(bar[0].val() ==
"10");
334 CHECK(bar[1].val() ==
"11");
338 CHECK(bar[2].val() ==
"12");
342 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"({foo: 1,bar: [10,11,12],john: doe})");
349 CHECK(ryml::emitrs_yaml<std::string>(foo) ==
"foo: 1\n");
429 CHECK(tree[
"foo"].is_keyval());
430 CHECK(tree[
"foo"].val() ==
"1");
432 CHECK(tree[
"bar"].is_seq());
433 CHECK(tree[
"bar"].has_key());
436 CHECK(tree[
"bar"][0].val() ==
"2");
437 CHECK(tree[
"bar"][1].val() ==
"3");
438 CHECK(tree[
"john"].val() ==
"doe");
442 CHECK(tree[0].
id() == tree[
"foo"].
id());
443 CHECK(tree[1].
id() == tree[
"bar"].
id());
444 CHECK(tree[2].
id() == tree[
"john"].
id());
446 CHECK(tree[0].
id() == tree[
"foo"].
id());
447 CHECK(tree[1].
id() == tree[
"bar"].
id());
448 CHECK(tree[2].
id() == tree[
"john"].
id());
450 CHECK(bar[0].val() ==
"2");
451 CHECK(bar[1].val() ==
"3");
458 CHECK(tree[
"john"].
key() ==
"john");
463 CHECK(root[
"foo"].
id() == root[0].
id());
464 CHECK(root[
"bar"].
id() == root[1].
id());
465 CHECK(root[
"john"].
id() == root[2].
id());
519 ryml::csubstr expected_keys[] = {
"foo",
"bar",
"john"};
524 CHECK(child.key() == expected_keys[count++]);
530 CHECK(child.key() == expected_keys[count++]);
536 CHECK(tree.
key(child_id) == expected_keys[count++]);
545 CHECK(tree.
key(child_id) == expected_keys[count++]);
605 int foo = 0, bar0 = 0, bar1 = 0;
606 std::string john_str;
609 root[
"bar"][0] >> bar0;
610 root[
"bar"][1] >> bar1;
611 root[
"john"] >> john_str;
616 CHECK(john_str ==
"doe");
617 CHECK(bar_str ==
"bar");
634 wroot[
"foo"] =
"says you";
635 wroot[
"bar"][0] =
"-2";
636 wroot[
"bar"][1] =
"-3";
637 wroot[
"john"] =
"ron";
641 CHECK(root[
"foo"].val() ==
"says you");
642 CHECK(root[
"bar"][0].val() ==
"-2");
643 CHECK(root[
"bar"][1].val() ==
"-3");
644 CHECK(root[
"john"].val() ==
"ron");
659 wroot[
"foo"] <<
"says who";
660 wroot[
"bar"][0] << 20;
661 wroot[
"bar"][1] << 30;
662 wroot[
"john"] <<
"deere";
663 CHECK(root[
"foo"].val() ==
"says who");
664 CHECK(root[
"bar"][0].val() ==
"20");
665 CHECK(root[
"bar"][1].val() ==
"30");
666 CHECK(root[
"john"].val() ==
"deere");
670 std::string ok(
"in_scope");
674 CHECK(root[
"john"].val() ==
"in_scope");
676 wroot[
"float"] << 2.4f;
680 CHECK(tree.
arena() ==
"says who2030deerein_scope2.42.400000");
688 wroot[
"newkeyval"] =
"shiny and new";
691 CHECK(root[
"newkeyval"].
key() ==
"newkeyval");
692 CHECK(root[
"newkeyval"].val() ==
"shiny and new");
693 CHECK(root[
"newkeyval (serialized)"].
key() ==
"newkeyval (serialized)");
694 CHECK(root[
"newkeyval (serialized)"].val() ==
"shiny and new (serialized)");
700 CHECK(root[
"bar"].num_children() == 2);
701 wroot[
"bar"][2] =
"oh so nice";
702 wroot[
"bar"][3] <<
"oh so nice (serialized)";
703 CHECK(root[
"bar"].num_children() == 4);
704 CHECK(root[
"bar"][2].val() ==
"oh so nice");
705 CHECK(root[
"bar"][3].val() ==
"oh so nice (serialized)");
711 CHECK(root[
"newseq"].num_children() == 0);
712 CHECK(root[
"newseq"].is_seq());
713 CHECK(root[
"newseq (serialized)"].num_children() == 0);
714 CHECK(root[
"newseq (serialized)"].is_seq());
720 CHECK(root[
"newmap"].num_children() == 0);
721 CHECK(root[
"newmap"].is_map());
722 CHECK(root[
"newmap (serialized)"].num_children() == 0);
723 CHECK(root[
"newmap (serialized)"].is_map());
751 nothing = wroot[
"I am nothing"];
766 something =
"indeed";
768 CHECK(root[
"I am something"].val() ==
"indeed");
799 CHECK(wbar[0].readable() && wbar[0].val() ==
"20");
800 CHECK( ! wbar[100].readable());
801 CHECK( ! wbar[100].readable() || wbar[100].val() ==
"100");
803 CHECK( ! wbar[0].is_seed() && wbar[0].val() ==
"20");
804 CHECK(wbar[100].is_seed() || wbar[100].val() ==
"100");
832 return seed_node.at(
"is").at(
"an").at(
"invalid").at(
"operation");
839 return seed_node[
"is"][
"an"][
"invalid"][
"operation"];
849 ryml::csubstr expected_result = R
"(foo: says who
850 bar: [20,30,oh so nice,oh so nice (serialized)]
854 newkeyval: shiny and new
855 newkeyval (serialized): shiny and new (serialized)
857 newseq (serialized): []
859 newmap (serialized): {}
860 I am something: indeed
866 std::stringstream ss;
868 std::string stream_result = ss.str();
870 std::string str_result = ryml::emitrs_yaml<std::string>(tree);
875 CHECK(buf_result == expected_result);
876 CHECK(str_result == expected_result);
877 CHECK(stream_result == expected_result);
893 CHECK(tree[
"bar"][0].val() ==
"21");
895 CHECK(tree[
"bar"][0].val() ==
"22");
901 constnoderef = noderef;
907 noderef = tree[
"bar"][0];
908 constnoderef = consttree[
"bar"][0];
912 CHECK(constnoderef == noderef);
913 CHECK(!(constnoderef != noderef));
938 fr: Planète (Gazeuse)
942 # UTF8 decoding only happens in double-quoted strings,
943 # as per the YAML standard
944 decode this: "\u263A c\x61f\xE9"
945 and this as well: "\u2705 \U0001D11E"
946 not decoded: '\u263A \xE2\x98\xBA'
947 neither this: '\u2705 \U0001D11E'
950 CHECK(langs[
"en"].val() ==
"Planet (Gas)");
951 CHECK(langs[
"fr"].val() ==
"Planète (Gazeuse)");
952 CHECK(langs[
"ru"].val() ==
"Планета (Газ)");
953 CHECK(langs[
"ja"].val() ==
"惑星(ガス)");
954 CHECK(langs[
"zh"].val() ==
"行星(气体)");
958 CHECK(langs[
"decode this"].val() ==
"☺ café");
959 CHECK(langs[
"and this as well"].val() ==
"✅ 𝄞");
960 CHECK(langs[
"not decoded"].val() ==
"\\u263A \\xE2\\x98\\xBA");
961 CHECK(langs[
"neither this"].val() ==
"\\u2705 \\U0001D11E");
989 const char foobar_str[] =
"foobar";
990 auto s = ryml::csubstr(foobar_str, strlen(foobar_str));
991 CHECK(s ==
"foobar");
992 CHECK(s.size() == 6);
993 CHECK(s.data() == foobar_str);
994 CHECK(s.size() == s.len);
995 CHECK(s.data() == s.str);
1000 const char foobar_str[] =
"foobar";
1001 ryml::csubstr s = foobar_str;
1002 CHECK(s ==
"foobar");
1003 CHECK(s !=
"foobar0");
1004 CHECK(s.size() == 6);
1005 CHECK(s.data() == foobar_str);
1006 CHECK(s.size() == s.len);
1007 CHECK(s.data() == s.str);
1011 ryml::csubstr s =
"foobar";
1012 CHECK(s ==
"foobar");
1013 CHECK(s !=
"foobar0");
1014 CHECK(s.size() == 6);
1015 CHECK(s.size() == s.len);
1016 CHECK(s.data() == s.str);
1025 const char *foobar_str =
"foobar";
1027 CHECK(s ==
"foobar");
1028 CHECK(s !=
"foobar0");
1029 CHECK(s.size() == 6);
1030 CHECK(s.size() == s.len);
1031 CHECK(s.data() == s.str);
1042 std::string foobar_str =
"foobar";
1044 CHECK(s ==
"foobar");
1045 CHECK(s !=
"foobar0");
1046 CHECK(s.size() == 6);
1047 CHECK(s.size() == s.len);
1048 CHECK(s.data() == s.str);
1054 ryml::substr foo = buf;
1055 CHECK(foo.len == 3);
1056 CHECK(foo.data() == buf);
1057 ryml::csubstr cfoo = foo;
1058 CHECK(cfoo.data() == buf);
1067 char const foobar_str_ro[] =
"foobar";
1068 char foobar_str_rw[] =
"foobar";
1069 static_assert(std::is_array<decltype(foobar_str_ro)>::value,
"this is an array");
1070 static_assert(std::is_array<decltype(foobar_str_rw)>::value,
"this is an array");
1073 ryml::csubstr foobar = foobar_str_ro;
1074 CHECK(foobar.data() == foobar_str_ro);
1075 CHECK(foobar.size() == strlen(foobar_str_ro));
1076 CHECK(foobar ==
"foobar");
1080 ryml::csubstr foobar = foobar_str_rw;
1081 CHECK(foobar.data() == foobar_str_rw);
1082 CHECK(foobar.size() == strlen(foobar_str_rw));
1083 CHECK(foobar ==
"foobar");
1087 ryml::substr foobar = foobar_str_rw;
1088 CHECK(foobar.data() == foobar_str_rw);
1089 CHECK(foobar.size() == strlen(foobar_str_rw));
1090 CHECK(foobar ==
"foobar");
1101 char const* foobar_str_ro =
"foobar";
1102 char foobar_str_rw_[] =
"foobar";
1103 char * foobar_str_rw = foobar_str_rw_;
1104 static_assert(!std::is_array<decltype(foobar_str_ro)>::value,
"this is a decayed pointer");
1105 static_assert(!std::is_array<decltype(foobar_str_rw)>::value,
"this is a decayed pointer");
1110 CHECK(foobar.data() == foobar_str_ro);
1111 CHECK(foobar.size() == strlen(foobar_str_ro));
1112 CHECK(foobar ==
"foobar");
1117 CHECK(foobar.data() == foobar_str_rw);
1118 CHECK(foobar.size() == strlen(foobar_str_rw));
1119 CHECK(foobar ==
"foobar");
1124 CHECK(foobar.data() == foobar_str_rw);
1125 CHECK(foobar.size() == strlen(foobar_str_rw));
1126 CHECK(foobar ==
"foobar");
1136 char buf[] =
"foobar";
1137 ryml::substr foobar = buf;
1138 CHECK(foobar ==
"foobar");
1139 foobar[0] =
'F';
CHECK(foobar ==
"Foobar");
1140 foobar.back() =
'R';
CHECK(foobar ==
"FoobaR");
1141 foobar.reverse();
CHECK(foobar ==
"RabooF");
1142 foobar.reverse();
CHECK(foobar ==
"FoobaR");
1143 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FabooR");
1144 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FoobaR");
1145 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoaboR");
1146 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoobaR");
1147 foobar.replace(
'o',
'0');
CHECK(foobar ==
"F00baR");
1148 foobar.replace(
'a',
'_');
CHECK(foobar ==
"F00b_R");
1149 foobar.replace(
"_0b",
'a');
CHECK(foobar ==
"FaaaaR");
1150 foobar.toupper();
CHECK(foobar ==
"FAAAAR");
1151 foobar.tolower();
CHECK(foobar ==
"faaaar");
1152 foobar.fill(
'.');
CHECK(foobar ==
"......");
1160 ryml::csubstr s =
"fooFOObarBAR";
1161 CHECK(s.len == 12u);
1163 CHECK(s.sub(0) ==
"fooFOObarBAR");
1164 CHECK(s.sub(0, 12) ==
"fooFOObarBAR");
1165 CHECK(s.sub(0, 3) ==
"foo" );
1166 CHECK(s.sub(3) ==
"FOObarBAR");
1167 CHECK(s.sub(3, 3) ==
"FOO" );
1168 CHECK(s.sub(6) ==
"barBAR");
1169 CHECK(s.sub(6, 3) ==
"bar" );
1170 CHECK(s.sub(9) ==
"BAR");
1171 CHECK(s.sub(9, 3) ==
"BAR");
1173 CHECK(s.first(0) ==
"" );
1174 CHECK(s.first(1) ==
"f" );
1175 CHECK(s.first(2) !=
"f" );
1176 CHECK(s.first(2) ==
"fo" );
1177 CHECK(s.first(3) ==
"foo");
1179 CHECK(s.last(0) ==
"");
1180 CHECK(s.last(1) ==
"R");
1181 CHECK(s.last(2) ==
"AR");
1182 CHECK(s.last(3) ==
"BAR");
1184 CHECK(s.range(0, 12) ==
"fooFOObarBAR");
1185 CHECK(s.range(1, 12) ==
"ooFOObarBAR");
1186 CHECK(s.range(1, 11) ==
"ooFOObarBA" );
1187 CHECK(s.range(2, 10) ==
"oFOObarB" );
1188 CHECK(s.range(3, 9) ==
"FOObar" );
1190 CHECK(s.offs(0, 0) ==
"fooFOObarBAR");
1191 CHECK(s.offs(1, 0) ==
"ooFOObarBAR");
1192 CHECK(s.offs(1, 1) ==
"ooFOObarBA" );
1193 CHECK(s.offs(2, 1) ==
"oFOObarBA" );
1194 CHECK(s.offs(2, 2) ==
"oFOObarB" );
1195 CHECK(s.offs(3, 3) ==
"FOObar" );
1197 CHECK(s.right_of(0,
true) ==
"fooFOObarBAR");
1198 CHECK(s.right_of(0,
false) ==
"ooFOObarBAR");
1199 CHECK(s.right_of(1,
true) ==
"ooFOObarBAR");
1200 CHECK(s.right_of(1,
false) ==
"oFOObarBAR");
1201 CHECK(s.right_of(2,
true) ==
"oFOObarBAR");
1202 CHECK(s.right_of(2,
false) ==
"FOObarBAR");
1203 CHECK(s.right_of(3,
true) ==
"FOObarBAR");
1204 CHECK(s.right_of(3,
false) ==
"OObarBAR");
1206 CHECK(s.left_of(12,
false) ==
"fooFOObarBAR");
1207 CHECK(s.left_of(11,
true) ==
"fooFOObarBAR");
1208 CHECK(s.left_of(11,
false) ==
"fooFOObarBA" );
1209 CHECK(s.left_of(10,
true) ==
"fooFOObarBA" );
1210 CHECK(s.left_of(10,
false) ==
"fooFOObarB" );
1211 CHECK(s.left_of( 9,
true) ==
"fooFOObarB" );
1212 CHECK(s.left_of( 9,
false) ==
"fooFOObar" );
1214 ryml::csubstr FOO = s.sub(3, 3);
1215 CHECK(s.is_super(FOO));
1216 CHECK(s.left_of(FOO) ==
"foo");
1217 CHECK(s.right_of(FOO) ==
"barBAR");
1222 ryml::csubstr s =
"some substring";
1223 ryml::csubstr some = s.first(4);
1224 CHECK(some ==
"some");
1225 CHECK(s ==
"some substring");
1228 char result[32] = {0};
1229 std::snprintf(result,
sizeof(result),
"%.*s", (
int)some.len, some.str);
1230 printf(
"~~~%s~~~\n", result);
1240 char result[32] = {0};
1241 std::snprintf(result,
sizeof(result),
"%s", some.str);
1249 ryml::csubstr s =
"some substring";
1250 ryml::csubstr some = s.first(4);
1251 CHECK(some ==
"some");
1252 CHECK(s ==
"some substring");
1255 std::stringstream ss;
1257 CHECK(ss.str() ==
"some substring");
1258 CHECK(ss.str() == s);
1266 std::stringstream ss;
1268 CHECK(ss.str() ==
"some substring");
1269 CHECK(ss.str() == s);
1273 std::stringstream ss;
1275 CHECK(ss.str() ==
"some substring");
1276 CHECK(ss.str() == s);
1280 std::stringstream ss;
1282 CHECK(ss.str() ==
"some");
1283 CHECK(ss.str() == some);
1289 ryml::csubstr foobar =
"foobar";
1290 ryml::csubstr foo = foobar.first(3);
1291 CHECK(foo.is_sub(foobar));
1292 CHECK(foo.is_sub(foo));
1293 CHECK(!foo.is_super(foobar));
1294 CHECK(!foobar.is_sub(foo));
1296 CHECK(foo.is_super(foo));
1297 CHECK(foo.is_sub(foo));
1298 CHECK(foobar.is_sub(foobar));
1299 CHECK(foobar.is_super(foobar));
1304 ryml::csubstr foobar =
"foobar";
1305 ryml::csubstr foo = foobar.first(3);
1306 ryml::csubstr oba = foobar.offs(2, 1);
1307 ryml::csubstr abc =
"abc";
1308 CHECK(foobar.overlaps(foo));
1309 CHECK(foobar.overlaps(oba));
1310 CHECK(foo.overlaps(foobar));
1311 CHECK(foo.overlaps(oba));
1312 CHECK(!foo.overlaps(abc));
1313 CHECK(!abc.overlaps(foo));
1320 CHECK(ryml::csubstr(
" \t\n\rcontents without whitespace\t \n\r").trim(
"\t \n\r") ==
"contents without whitespace");
1321 ryml::csubstr aaabbb =
"aaabbb";
1322 ryml::csubstr aaa___bbb =
"aaa___bbb";
1324 CHECK(aaabbb.triml(
'a') == aaabbb.last(3));
1325 CHECK(aaabbb.trimr(
'a') == aaabbb);
1326 CHECK(aaabbb.trim (
'a') == aaabbb.last(3));
1327 CHECK(aaabbb.triml(
'b') == aaabbb);
1328 CHECK(aaabbb.trimr(
'b') == aaabbb.first(3));
1329 CHECK(aaabbb.trim (
'b') == aaabbb.first(3));
1330 CHECK(aaabbb.triml(
'c') == aaabbb);
1331 CHECK(aaabbb.trimr(
'c') == aaabbb);
1332 CHECK(aaabbb.trim (
'c') == aaabbb);
1333 CHECK(aaa___bbb.triml(
'a') == aaa___bbb.last(6));
1334 CHECK(aaa___bbb.trimr(
'a') == aaa___bbb);
1335 CHECK(aaa___bbb.trim (
'a') == aaa___bbb.last(6));
1336 CHECK(aaa___bbb.triml(
'b') == aaa___bbb);
1337 CHECK(aaa___bbb.trimr(
'b') == aaa___bbb.first(6));
1338 CHECK(aaa___bbb.trim (
'b') == aaa___bbb.first(6));
1339 CHECK(aaa___bbb.triml(
'c') == aaa___bbb);
1340 CHECK(aaa___bbb.trimr(
'c') == aaa___bbb);
1341 CHECK(aaa___bbb.trim (
'c') == aaa___bbb);
1343 CHECK(aaabbb.triml(
"ab") ==
"");
1344 CHECK(aaabbb.trimr(
"ab") ==
"");
1345 CHECK(aaabbb.trim (
"ab") ==
"");
1346 CHECK(aaabbb.triml(
"ba") ==
"");
1347 CHECK(aaabbb.trimr(
"ba") ==
"");
1348 CHECK(aaabbb.trim (
"ba") ==
"");
1349 CHECK(aaabbb.triml(
"cd") == aaabbb);
1350 CHECK(aaabbb.trimr(
"cd") == aaabbb);
1351 CHECK(aaabbb.trim (
"cd") == aaabbb);
1352 CHECK(aaa___bbb.triml(
"ab") == aaa___bbb.last(6));
1353 CHECK(aaa___bbb.triml(
"ba") == aaa___bbb.last(6));
1354 CHECK(aaa___bbb.triml(
"cd") == aaa___bbb);
1355 CHECK(aaa___bbb.trimr(
"ab") == aaa___bbb.first(6));
1356 CHECK(aaa___bbb.trimr(
"ba") == aaa___bbb.first(6));
1357 CHECK(aaa___bbb.trimr(
"cd") == aaa___bbb);
1358 CHECK(aaa___bbb.trim (
"ab") == aaa___bbb.range(3, 6));
1359 CHECK(aaa___bbb.trim (
"ba") == aaa___bbb.range(3, 6));
1360 CHECK(aaa___bbb.trim (
"cd") == aaa___bbb);
1365 CHECK(ryml::csubstr(R
"('this is is single quoted')").unquoted() == "this is is single quoted");
1366 CHECK(ryml::csubstr(R
"("this is is double quoted")").unquoted() == "this is is double quoted");
1372 ryml::csubstr abc___cba =
"abc___cba";
1373 ryml::csubstr abc___abc =
"abc___abc";
1374 CHECK(abc___cba.stripl(
"abc") == abc___cba.last(6));
1375 CHECK(abc___cba.stripr(
"abc") == abc___cba);
1376 CHECK(abc___cba.stripl(
"ab") == abc___cba.last(7));
1377 CHECK(abc___cba.stripr(
"ab") == abc___cba);
1378 CHECK(abc___cba.stripl(
"a") == abc___cba.last(8));
1379 CHECK(abc___cba.stripr(
"a") == abc___cba.first(8));
1380 CHECK(abc___abc.stripl(
"abc") == abc___abc.last(6));
1381 CHECK(abc___abc.stripr(
"abc") == abc___abc.first(6));
1382 CHECK(abc___abc.stripl(
"ab") == abc___abc.last(7));
1383 CHECK(abc___abc.stripr(
"ab") == abc___abc);
1384 CHECK(abc___abc.stripl(
"a") == abc___abc.last(8));
1385 CHECK(abc___abc.stripr(
"a") == abc___abc);
1391 ryml::csubstr s =
"foobar123";
1393 CHECK(s.begins_with(
'f'));
1394 CHECK(s.ends_with(
'3'));
1395 CHECK(!s.ends_with(
'2'));
1396 CHECK(!s.ends_with(
'o'));
1398 CHECK(s.begins_with(
"foobar"));
1399 CHECK(s.begins_with(
"foo"));
1400 CHECK(s.begins_with_any(
"foo"));
1401 CHECK(!s.begins_with(
"oof"));
1402 CHECK(s.begins_with_any(
"oof"));
1403 CHECK(s.ends_with(
"23"));
1404 CHECK(s.ends_with(
"123"));
1405 CHECK(s.ends_with_any(
"123"));
1406 CHECK(!s.ends_with(
"321"));
1407 CHECK(s.ends_with_any(
"231"));
1412 ryml::csubstr s =
"0123456789";
1413 CHECK(s.select(
'0') == s.sub(0, 1));
1414 CHECK(s.select(
'1') == s.sub(1, 1));
1415 CHECK(s.select(
'2') == s.sub(2, 1));
1416 CHECK(s.select(
'8') == s.sub(8, 1));
1417 CHECK(s.select(
'9') == s.sub(9, 1));
1418 CHECK(s.select(
"0123") == s.range(0, 4));
1419 CHECK(s.select(
"012" ) == s.range(0, 3));
1420 CHECK(s.select(
"01" ) == s.range(0, 2));
1421 CHECK(s.select(
"0" ) == s.range(0, 1));
1422 CHECK(s.select(
"123") == s.range(1, 4));
1423 CHECK(s.select(
"23") == s.range(2, 4));
1424 CHECK(s.select(
"3") == s.range(3, 4));
1429 ryml::csubstr s012345 =
"012345";
1432 CHECK(s012345.find(
'0' ) == 0u);
1434 CHECK(s012345.find(
'1' ) == 1u);
1436 CHECK(s012345.find(
'2' ) == 2u);
1438 CHECK(s012345.find(
'3' ) == 3u);
1442 CHECK(s012345.find(
"01" ) == 0u);
1444 CHECK(s012345.find(
"12" ) == 1u);
1446 CHECK(s012345.find(
"23" ) == 2u);
1452 ryml::csubstr buf =
"00110022003300440055";
1453 CHECK(buf.count(
'1' ) == 2u);
1454 CHECK(buf.count(
'1', 0u) == 2u);
1455 CHECK(buf.count(
'1', 1u) == 2u);
1456 CHECK(buf.count(
'1', 2u) == 2u);
1457 CHECK(buf.count(
'1', 3u) == 1u);
1458 CHECK(buf.count(
'1', 4u) == 0u);
1459 CHECK(buf.count(
'1', 5u) == 0u);
1460 CHECK(buf.count(
'0' ) == 10u);
1461 CHECK(buf.count(
'0', 0u) == 10u);
1462 CHECK(buf.count(
'0', 1u) == 9u);
1463 CHECK(buf.count(
'0', 2u) == 8u);
1464 CHECK(buf.count(
'0', 3u) == 8u);
1465 CHECK(buf.count(
'0', 4u) == 8u);
1466 CHECK(buf.count(
'0', 5u) == 7u);
1467 CHECK(buf.count(
'0', 6u) == 6u);
1468 CHECK(buf.count(
'0', 7u) == 6u);
1469 CHECK(buf.count(
'0', 8u) == 6u);
1470 CHECK(buf.count(
'0', 9u) == 5u);
1471 CHECK(buf.count(
'0', 10u) == 4u);
1472 CHECK(buf.count(
'0', 11u) == 4u);
1473 CHECK(buf.count(
'0', 12u) == 4u);
1474 CHECK(buf.count(
'0', 13u) == 3u);
1475 CHECK(buf.count(
'0', 14u) == 2u);
1476 CHECK(buf.count(
'0', 15u) == 2u);
1477 CHECK(buf.count(
'0', 16u) == 2u);
1478 CHECK(buf.count(
'0', 17u) == 1u);
1479 CHECK(buf.count(
'0', 18u) == 0u);
1480 CHECK(buf.count(
'0', 19u) == 0u);
1481 CHECK(buf.count(
'0', 20u) == 0u);
1486 ryml::csubstr s012345 =
"012345";
1489 CHECK(s012345.first_of(
'0') == 0u);
1490 CHECK(s012345.first_of(
"0") == 0u);
1491 CHECK(s012345.first_of(
"01") == 0u);
1492 CHECK(s012345.first_of(
"10") == 0u);
1493 CHECK(s012345.first_of(
"012") == 0u);
1494 CHECK(s012345.first_of(
"210") == 0u);
1495 CHECK(s012345.first_of(
"0123") == 0u);
1496 CHECK(s012345.first_of(
"3210") == 0u);
1497 CHECK(s012345.first_of(
"01234") == 0u);
1498 CHECK(s012345.first_of(
"43210") == 0u);
1499 CHECK(s012345.first_of(
"012345") == 0u);
1500 CHECK(s012345.first_of(
"543210") == 0u);
1501 CHECK(s012345.first_of(
'5') == 5u);
1502 CHECK(s012345.first_of(
"5") == 5u);
1503 CHECK(s012345.first_of(
"45") == 4u);
1504 CHECK(s012345.first_of(
"54") == 4u);
1505 CHECK(s012345.first_of(
"345") == 3u);
1506 CHECK(s012345.first_of(
"543") == 3u);
1507 CHECK(s012345.first_of(
"2345") == 2u);
1508 CHECK(s012345.first_of(
"5432") == 2u);
1509 CHECK(s012345.first_of(
"12345") == 1u);
1510 CHECK(s012345.first_of(
"54321") == 1u);
1511 CHECK(s012345.first_of(
"012345") == 0u);
1512 CHECK(s012345.first_of(
"543210") == 0u);
1519 CHECK(s012345.last_of(
'0') == 0u);
1520 CHECK(s012345.last_of(
"0") == 0u);
1521 CHECK(s012345.last_of(
"01") == 1u);
1522 CHECK(s012345.last_of(
"10") == 1u);
1523 CHECK(s012345.last_of(
"012") == 2u);
1524 CHECK(s012345.last_of(
"210") == 2u);
1525 CHECK(s012345.last_of(
"0123") == 3u);
1526 CHECK(s012345.last_of(
"3210") == 3u);
1527 CHECK(s012345.last_of(
"01234") == 4u);
1528 CHECK(s012345.last_of(
"43210") == 4u);
1529 CHECK(s012345.last_of(
"012345") == 5u);
1530 CHECK(s012345.last_of(
"543210") == 5u);
1531 CHECK(s012345.last_of(
'5') == 5u);
1532 CHECK(s012345.last_of(
"5") == 5u);
1533 CHECK(s012345.last_of(
"45") == 5u);
1534 CHECK(s012345.last_of(
"54") == 5u);
1535 CHECK(s012345.last_of(
"345") == 5u);
1536 CHECK(s012345.last_of(
"543") == 5u);
1537 CHECK(s012345.last_of(
"2345") == 5u);
1538 CHECK(s012345.last_of(
"5432") == 5u);
1539 CHECK(s012345.last_of(
"12345") == 5u);
1540 CHECK(s012345.last_of(
"54321") == 5u);
1541 CHECK(s012345.last_of(
"012345") == 5u);
1542 CHECK(s012345.last_of(
"543210") == 5u);
1543 CHECK(s012345.last_of(
'0', 6u) == 0u);
1544 CHECK(s012345.last_of(
'5', 6u) == 5u);
1545 CHECK(s012345.last_of(
"012345", 6u) == 5u);
1550 ryml::csubstr s012345 =
"012345";
1551 CHECK(s012345.first_not_of(
'a') == 0u);
1552 CHECK(s012345.first_not_of(
"ab") == 0u);
1553 CHECK(s012345.first_not_of(
'0') == 1u);
1554 CHECK(s012345.first_not_of(
"0") == 1u);
1555 CHECK(s012345.first_not_of(
"01") == 2u);
1556 CHECK(s012345.first_not_of(
"10") == 2u);
1557 CHECK(s012345.first_not_of(
"012") == 3u);
1558 CHECK(s012345.first_not_of(
"210") == 3u);
1559 CHECK(s012345.first_not_of(
"0123") == 4u);
1560 CHECK(s012345.first_not_of(
"3210") == 4u);
1561 CHECK(s012345.first_not_of(
"01234") == 5u);
1562 CHECK(s012345.first_not_of(
"43210") == 5u);
1565 CHECK(s012345.first_not_of(
'5') == 0u);
1566 CHECK(s012345.first_not_of(
"5") == 0u);
1567 CHECK(s012345.first_not_of(
"45") == 0u);
1568 CHECK(s012345.first_not_of(
"54") == 0u);
1569 CHECK(s012345.first_not_of(
"345") == 0u);
1570 CHECK(s012345.first_not_of(
"543") == 0u);
1571 CHECK(s012345.first_not_of(
"2345") == 0u);
1572 CHECK(s012345.first_not_of(
"5432") == 0u);
1573 CHECK(s012345.first_not_of(
"12345") == 0u);
1574 CHECK(s012345.first_not_of(
"54321") == 0u);
1577 CHECK(s012345.last_not_of(
'a') == 5u);
1578 CHECK(s012345.last_not_of(
"ab") == 5u);
1579 CHECK(s012345.last_not_of(
'5') == 4u);
1580 CHECK(s012345.last_not_of(
"5") == 4u);
1581 CHECK(s012345.last_not_of(
"45") == 3u);
1582 CHECK(s012345.last_not_of(
"54") == 3u);
1583 CHECK(s012345.last_not_of(
"345") == 2u);
1584 CHECK(s012345.last_not_of(
"543") == 2u);
1585 CHECK(s012345.last_not_of(
"2345") == 1u);
1586 CHECK(s012345.last_not_of(
"5432") == 1u);
1587 CHECK(s012345.last_not_of(
"12345") == 0u);
1588 CHECK(s012345.last_not_of(
"54321") == 0u);
1591 CHECK(s012345.last_not_of(
'0') == 5u);
1592 CHECK(s012345.last_not_of(
"0") == 5u);
1593 CHECK(s012345.last_not_of(
"01") == 5u);
1594 CHECK(s012345.last_not_of(
"10") == 5u);
1595 CHECK(s012345.last_not_of(
"012") == 5u);
1596 CHECK(s012345.last_not_of(
"210") == 5u);
1597 CHECK(s012345.last_not_of(
"0123") == 5u);
1598 CHECK(s012345.last_not_of(
"3210") == 5u);
1599 CHECK(s012345.last_not_of(
"01234") == 5u);
1600 CHECK(s012345.last_not_of(
"43210") == 5u);
1607 CHECK(ryml::csubstr(
"foo bar").first_non_empty_span() ==
"foo");
1608 CHECK(ryml::csubstr(
" foo bar").first_non_empty_span() ==
"foo");
1609 CHECK(ryml::csubstr(
"\n \r \t foo bar").first_non_empty_span() ==
"foo");
1610 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1611 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1612 CHECK(ryml::csubstr(
",\n \r \t foo\n\r\t bar").first_non_empty_span() ==
",");
1616 CHECK(ryml::csubstr(
"1234 asdkjh").first_uint_span() ==
"1234");
1617 CHECK(ryml::csubstr(
"1234\rasdkjh").first_uint_span() ==
"1234");
1618 CHECK(ryml::csubstr(
"1234\tasdkjh").first_uint_span() ==
"1234");
1619 CHECK(ryml::csubstr(
"1234\nasdkjh").first_uint_span() ==
"1234");
1620 CHECK(ryml::csubstr(
"1234]asdkjh").first_uint_span() ==
"1234");
1621 CHECK(ryml::csubstr(
"1234)asdkjh").first_uint_span() ==
"1234");
1622 CHECK(ryml::csubstr(
"1234gasdkjh").first_uint_span() ==
"");
1626 CHECK(ryml::csubstr(
"-1234 asdkjh").first_int_span() ==
"-1234");
1627 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_int_span() ==
"-1234");
1628 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_int_span() ==
"-1234");
1629 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_int_span() ==
"-1234");
1630 CHECK(ryml::csubstr(
"-1234]asdkjh").first_int_span() ==
"-1234");
1631 CHECK(ryml::csubstr(
"-1234)asdkjh").first_int_span() ==
"-1234");
1632 CHECK(ryml::csubstr(
"-1234gasdkjh").first_int_span() ==
"");
1636 CHECK(ryml::csubstr(
"-1234 asdkjh").first_real_span() ==
"-1234");
1637 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_real_span() ==
"-1234");
1638 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_real_span() ==
"-1234");
1639 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_real_span() ==
"-1234");
1640 CHECK(ryml::csubstr(
"-1234]asdkjh").first_real_span() ==
"-1234");
1641 CHECK(ryml::csubstr(
"-1234)asdkjh").first_real_span() ==
"-1234");
1642 CHECK(ryml::csubstr(
"-1234gasdkjh").first_real_span() ==
"");
1643 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1644 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1645 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1646 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1647 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1648 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1649 CHECK(ryml::csubstr(
"-1.234 asdkjh").first_real_span() ==
"-1.234");
1650 CHECK(ryml::csubstr(
"-1.234e+5 asdkjh").first_real_span() ==
"-1.234e+5");
1651 CHECK(ryml::csubstr(
"-1.234e-5 asdkjh").first_real_span() ==
"-1.234e-5");
1653 CHECK(ryml::csubstr(
"0x1.e8480p+19 asdkjh").first_real_span() ==
"0x1.e8480p+19");
1654 CHECK(ryml::csubstr(
"0x1.e8480p-19 asdkjh").first_real_span() ==
"0x1.e8480p-19");
1655 CHECK(ryml::csubstr(
"-0x1.e8480p+19 asdkjh").first_real_span() ==
"-0x1.e8480p+19");
1656 CHECK(ryml::csubstr(
"-0x1.e8480p-19 asdkjh").first_real_span() ==
"-0x1.e8480p-19");
1657 CHECK(ryml::csubstr(
"+0x1.e8480p+19 asdkjh").first_real_span() ==
"+0x1.e8480p+19");
1658 CHECK(ryml::csubstr(
"+0x1.e8480p-19 asdkjh").first_real_span() ==
"+0x1.e8480p-19");
1660 CHECK(ryml::csubstr(
"0b101.011p+19 asdkjh").first_real_span() ==
"0b101.011p+19");
1661 CHECK(ryml::csubstr(
"0b101.011p-19 asdkjh").first_real_span() ==
"0b101.011p-19");
1662 CHECK(ryml::csubstr(
"-0b101.011p+19 asdkjh").first_real_span() ==
"-0b101.011p+19");
1663 CHECK(ryml::csubstr(
"-0b101.011p-19 asdkjh").first_real_span() ==
"-0b101.011p-19");
1664 CHECK(ryml::csubstr(
"+0b101.011p+19 asdkjh").first_real_span() ==
"+0b101.011p+19");
1665 CHECK(ryml::csubstr(
"+0b101.011p-19 asdkjh").first_real_span() ==
"+0b101.011p-19");
1667 CHECK(ryml::csubstr(
"0o173.045p+19 asdkjh").first_real_span() ==
"0o173.045p+19");
1668 CHECK(ryml::csubstr(
"0o173.045p-19 asdkjh").first_real_span() ==
"0o173.045p-19");
1669 CHECK(ryml::csubstr(
"-0o173.045p+19 asdkjh").first_real_span() ==
"-0o173.045p+19");
1670 CHECK(ryml::csubstr(
"-0o173.045p-19 asdkjh").first_real_span() ==
"-0o173.045p-19");
1671 CHECK(ryml::csubstr(
"+0o173.045p+19 asdkjh").first_real_span() ==
"+0o173.045p+19");
1672 CHECK(ryml::csubstr(
"+0o173.045p-19 asdkjh").first_real_span() ==
"+0o173.045p-19");
1678 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").basename() ==
"file.tar.gz");
1679 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").dirname() ==
"/path/to/");
1680 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").basename(
'\\') ==
"file.tar.gz");
1681 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").dirname(
'\\') ==
"C:\\path\\to\\");
1682 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extshort() ==
"gz");
1683 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extlong() ==
"tar.gz");
1684 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extshort() ==
"/path/to/file.tar");
1685 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extlong() ==
"/path/to/file");
1690 using namespace ryml;
1691 csubstr parts[] = {
"aa",
"bb",
"cc",
"dd",
"ee",
"ff"};
1694 for(csubstr part : csubstr(
"aa/bb/cc/dd/ee/ff").split(
'/'))
1695 CHECK(part == parts[count++]);
1700 for(csubstr part : csubstr(
"aa.bb.cc.dd.ee.ff").split(
'.'))
1701 CHECK(part == parts[count++]);
1706 for(csubstr part : csubstr(
"aa-bb-cc-dd-ee-ff").split(
'-'))
1707 CHECK(part == parts[count++]);
1716 const bool skip_empty =
true;
1718 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/' ) ==
"0" );
1719 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/' ) ==
"" );
1720 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/' ) ==
"" );
1721 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/', skip_empty) ==
"0" );
1722 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/', skip_empty) ==
"/0" );
1723 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/', skip_empty) ==
"//0" );
1725 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/' ) ==
"0/1" );
1726 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/' ) ==
"/0/1" );
1727 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/' ) ==
"//0/1" );
1728 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/' ) ==
"0/1/2");
1729 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/' ) ==
"/0/1/2");
1730 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/' ) ==
"//0/1/2");
1731 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/' ) ==
"0/1/2/");
1732 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/' ) ==
"/0/1/2/");
1733 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/' ) ==
"//0/1/2/");
1734 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1735 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1736 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1737 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1738 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1739 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1740 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1741 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1742 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1744 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/' ) ==
"2" );
1745 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/' ) ==
"" );
1746 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/' ) ==
"" );
1747 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/', skip_empty) ==
"2" );
1748 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/', skip_empty) ==
"2/" );
1749 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/', skip_empty) ==
"2//" );
1751 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/' ) ==
"1/2");
1752 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/' ) ==
"1/2/" );
1753 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/' ) ==
"1/2//" );
1754 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/' ) ==
"0/1/2");
1755 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/' ) ==
"0/1/2/" );
1756 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/' ) ==
"0/1/2//" );
1757 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/' ) ==
"/0/1/2");
1758 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/' ) ==
"/0/1/2/" );
1759 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/' ) ==
"/0/1/2//" );
1760 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1761 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1762 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1763 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1764 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1765 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1766 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2");
1767 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1768 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//" );
1791 const char filename[] =
"ryml_example.yml";
1805 std::string contents = file_get_contents<std::string>(filename);
1807 CHECK(tree[
"foo"].val() ==
"1");
1808 CHECK(tree[
"bar"][0].val() ==
"2");
1809 CHECK(tree[
"bar"][1].val() ==
"3");
1814 std::vector<char> contents = file_get_contents<std::vector<char>>(filename);
1816 CHECK(tree[
"foo"].val() ==
"1");
1817 CHECK(tree[
"bar"][0].val() ==
"2");
1818 CHECK(tree[
"bar"][1].val() ==
"3");
1839 char src[] =
"{foo: 1, bar: [2, 3]}";
1840 ryml::substr srcview = src;
1845 CHECK(root[
"foo"].is_keyval());
1847 CHECK(root[
"foo"].val() ==
"1");
1848 CHECK(root[
"bar"].is_seq());
1849 CHECK(root[
"bar"].has_key());
1851 CHECK(root[
"bar"][0].val() ==
"2");
1852 CHECK(root[
"bar"][1].val() ==
"3");
1855 int foo = 0, bar0 = 0, bar1 = 0;
1857 root[
"bar"][0] >> bar0;
1858 root[
"bar"][1] >> bar1;
1864 CHECK(root[
"foo"].val().data() == src + strlen(
"{foo: "));
1865 CHECK(root[
"foo"].val().begin() == src + strlen(
"{foo: "));
1866 CHECK(root[
"foo"].val().end() == src + strlen(
"{foo: 1"));
1867 CHECK(root[
"foo"].val().is_sub(srcview));
1868 CHECK(root[
"bar"][0].val().data() == src + strlen(
"{foo: 1, bar: ["));
1869 CHECK(root[
"bar"][0].val().begin() == src + strlen(
"{foo: 1, bar: ["));
1870 CHECK(root[
"bar"][0].val().end() == src + strlen(
"{foo: 1, bar: [2"));
1871 CHECK(root[
"bar"][0].val().is_sub(srcview));
1872 CHECK(root[
"bar"][1].val().data() == src + strlen(
"{foo: 1, bar: [2, "));
1873 CHECK(root[
"bar"][1].val().begin() == src + strlen(
"{foo: 1, bar: [2, "));
1874 CHECK(root[
"bar"][1].val().end() == src + strlen(
"{foo: 1, bar: [2, 3"));
1875 CHECK(root[
"bar"][1].val().is_sub(srcview));
1879 ryml::csubstr csrcview = srcview;
1897 CHECK(root[
"foo"].is_keyval());
1899 CHECK(root[
"foo"].val() ==
"1");
1900 CHECK(root[
"bar"].is_seq());
1901 CHECK(root[
"bar"].has_key());
1903 CHECK(root[
"bar"][0].val() ==
"2");
1904 CHECK(root[
"bar"][1].val() ==
"3");
1907 int foo = 0, bar0 = 0, bar1 = 0;
1909 root[
"bar"][0] >> bar0;
1910 root[
"bar"][1] >> bar1;
1918 char src[] =
"{foo: is it really true}";
1919 ryml::substr srcview = src;
1925 ryml::csubstr csrcview = srcview;
1927 CHECK(tree[
"foo"].val() ==
"is it really true");
1946 ryml::csubstr yaml = R
"(foo: 1
1954 CHECK(root["foo"].is_keyval());
1956 CHECK(root[
"foo"].val() ==
"1");
1957 CHECK(root[
"bar"].is_seq());
1958 CHECK(root[
"bar"].has_key());
1960 CHECK(root[
"bar"][0].val() ==
"2");
1961 CHECK(root[
"bar"][1].val() ==
"3");
1962 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(foo: 1
1968 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(foo: 1
1974 CHECK(root["foo2"].is_keyval());
1975 CHECK(root[
"foo2"].
key() ==
"foo2");
1976 CHECK(root[
"foo2"].val() ==
"12");
1977 CHECK(root[
"bar2"].is_seq());
1978 CHECK(root[
"bar2"].has_key());
1979 CHECK(root[
"bar2"].
key() ==
"bar2");
1980 CHECK(root[
"bar2"][0].val() ==
"22");
1981 CHECK(root[
"bar2"][1].val() ==
"32");
1987 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
"- a\n- b\n- {x0: 1,x1: 2}\n");
1989 CHECK(root[0].val() ==
"a");
1990 CHECK(root[1].val() ==
"b");
1991 CHECK(root[2].is_map());
1992 CHECK(root[2][
"x0"].val() ==
"1");
1993 CHECK(root[2][
"x1"].val() ==
"2");
1998 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2001 - champagne: Dom Perignon
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");
2010 CHECK(root[3].is_map());
2011 CHECK(root[3][
"champagne"].val() ==
"Dom Perignon");
2012 CHECK(root[3][
"coffee"].val() ==
"Arabica");
2022 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2025 - champagne: Dom Perignon
2028 vinho verde: Soalheiro
2029 vinho tinto: Redoma 2017
2034 always: lots of water
2039 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2042 - champagne: Dom Perignon
2045 vinho verde: Soalheiro
2046 vinho tinto: Redoma 2017
2051 always: lots of water
2060 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- a
2063 - champagne: Dom Perignon
2066 vinho verde: Soalheiro
2067 vinho tinto: Redoma 2017
2073 always: lots of water
2101 ryml::Tree champagnes =
parse_in_arena(&parser,
"champagnes.yml",
"[Dom Perignon, Gosset Grande Reserve, Jacquesson 742]");
2102 CHECK(ryml::emitrs_yaml<std::string>(champagnes) ==
"[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]");
2105 CHECK(ryml::emitrs_yaml<std::string>(beers) ==
"[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]");
2135 ryml::csubstr champagnes =
"- Dom Perignon\n- Gosset Grande Reserve\n- Jacquesson 742";
2136 ryml::csubstr beers =
"- Rochefort 10\n- Busch\n- Leffe Rituel\n- Kasteel Donker";
2137 ryml::csubstr wines =
"- Soalheiro\n- Niepoort Redoma 2017\n- Vina Esmeralda";
2140 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Dom Perignon
2141 - Gosset Grande Reserve
2147 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Dom Perignon
2148 - Gosset Grande Reserve
2159 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(- Soalheiro
2160 - Niepoort Redoma 2017
2175 ray: "a drop of golden sun"
2190 location: a pear tree
2198 std::vector<ryml::csubstr> keys, vals;
2201 keys.emplace_back(n.key());
2202 vals.emplace_back(n.has_val() ? n.val() : ryml::csubstr{});
2204 CHECK(keys[0] ==
"doe");
2205 CHECK(vals[0] ==
"a deer, a female deer");
2206 CHECK(keys[1] ==
"ray");
2207 CHECK(vals[1] ==
"a drop of golden sun");
2208 CHECK(keys[2] ==
"pi");
2209 CHECK(vals[2] ==
"3.14159");
2210 CHECK(keys[3] ==
"xmas");
2211 CHECK(vals[3] ==
"true");
2212 CHECK(root[5].has_key());
2213 CHECK(root[5].is_seq());
2214 CHECK(root[5].
key() ==
"calling-birds");
2215 CHECK(!root[5].has_val());
2217 CHECK(keys[5] ==
"calling-birds");
2218 CHECK(vals[5] ==
"");
2224 ryml::csubstr calling_birds[] = {
"huey",
"dewey",
"louie",
"fred"};
2226 CHECK(n.val() == calling_birds[count++]);
2251 const char a_deer[] =
"a deer, a female deer";
2260 std::string a_drop =
"a drop of golden sun";
2263 root[
"ray"] << a_drop;
2269 CHECK(root[
"ray"].val() ==
"a drop of golden sun");
2274 root[
"french-hens"] << 3;
2283 xmas5[
"calling-birds"] =
"four";
2284 xmas5[
"french-hens"] << 3;
2285 xmas5[
"golden-rings"] << 5;
2287 xmas5[
"partridges"][
"count"] << 1;
2288 xmas5[
"partridges"][
"location"] =
"a pear tree";
2289 xmas5[
"turtle-doves"] =
"two";
2290 root[
"cars"] =
"GTO";
2292 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(doe: 'a deer, a female deer'
2293 ray: a drop of golden sun
2308 location: a pear tree
2323 char buf[] =
"[a, b, c, d]";
2324 ryml::substr yml = buf;
2330 CHECK(root[0].val().is_sub(yml));
2331 CHECK(root[1].val().is_sub(yml));
2332 CHECK(root[2].val().is_sub(yml));
2333 CHECK(root[3].val().is_sub(yml));
2334 CHECK(yml.is_super(root[0].
val()));
2335 CHECK(yml.is_super(root[1].
val()));
2336 CHECK(yml.is_super(root[2].
val()));
2337 CHECK(yml.is_super(root[3].
val()));
2344 ryml::csubstr yml =
"[a, b, c, d]";
2352 ryml::csubstr arena = tree.
arena();
2353 CHECK(root[0].val().is_sub(arena));
2354 CHECK(root[1].val().is_sub(arena));
2355 CHECK(root[2].val().is_sub(arena));
2356 CHECK(root[3].val().is_sub(arena));
2357 CHECK(arena.is_super(root[0].
val()));
2358 CHECK(arena.is_super(root[1].
val()));
2359 CHECK(arena.is_super(root[2].
val()));
2360 CHECK(arena.is_super(root[3].
val()));
2366 char buf[] =
"[a, b, c, d]";
2367 ryml::substr yml = buf;
2374 CHECK(root[2].val() ==
"c");
2375 CHECK(root[2].val().is_sub(yml));
2377 CHECK(root[2].val() ==
"12345");
2383 CHECK(root[3].val() ==
"d");
2384 CHECK(root[3].val().is_sub(yml));
2386 CHECK(root[3].val() ==
"67890");
2394 ryml::csubstr yml =
"[a, b, c, d]";
2402 CHECK(root[2].val() ==
"c");
2404 CHECK(root[2].val() ==
"12345");
2413 CHECK(root[3].val() ==
"67890");
2417 CHECK(tree.
arena() ==
"[a, b, c, d]1234567890");
2424 ryml::csubstr c10 = tree.
to_arena(10101010);
2425 CHECK(c10 ==
"10101010");
2435 CHECK(root[
"a"].val() ==
"2222");
2442 ryml::csubstr mystr =
"Gosset Grande Reserve";
2444 CHECK(!copied.overlaps(mystr));
2445 CHECK(copied == mystr);
2446 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2452 ryml::csubstr mystr =
"Gosset Grande Reserve";
2453 ryml::substr copied = tree.
alloc_arena(mystr.size());
2454 CHECK(!copied.overlaps(mystr));
2455 memcpy(copied.str, mystr.str, mystr.len);
2456 CHECK(copied == mystr);
2457 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2463 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2466 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2468 CHECK(tree.
arena().first(12) ==
"{a: b}123456");
2506 CHECK(tree.
to_arena(
double(0.234)) ==
"0.234");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.234");
2516 const float fnan = std::numeric_limits<float >::quiet_NaN();
2517 const double dnan = std::numeric_limits<double>::quiet_NaN();
2518 const float finf = std::numeric_limits<float >::infinity();
2519 const double dinf = std::numeric_limits<double>::infinity();
2520 CHECK(tree.
to_arena( finf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf");
2521 CHECK(tree.
to_arena( dinf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf");
2522 CHECK(tree.
to_arena(-finf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf");
2523 CHECK(tree.
to_arena(-dinf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf");
2524 CHECK(tree.
to_arena( fnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan");
2525 CHECK(tree.
to_arena( dnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan.nan");
2529 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
2535 tree[
"ninf"] >> f;
CHECK(f == -finf);
2536 tree[
"ninf"] >> d;
CHECK(d == -dinf);
2537 tree[
"pinf"] >> f;
CHECK(f == finf);
2538 tree[
"pinf"] >> d;
CHECK(d == dinf);
2539 tree[
"nan" ] >> f;
CHECK(std::isnan(f));
2540 tree[
"nan" ] >> d;
CHECK(std::isnan(d));
2541 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2554 t[
"val"] >> valu8;
CHECK(valu8 == 2);
2555 t[
"val"] >> vali8;
CHECK(vali8 == 2);
2557 CHECK(ryml::overflows<uint8_t>(t[
"val"].val()));
2558 CHECK(ryml::overflows<int8_t>(t[
"val"].val()));
2559 CHECK( ! ryml::overflows<int16_t>(t[
"val"].val()));
2562 auto checku8 = ryml::fmt::overflow_checked(valu8);
2563 t[
"val"] >> checku8;
2566 auto checki8 = ryml::fmt::overflow_checked(vali8);
2567 t[
"val"] >> checki8;
2586 all_null: [~, null, Null, NULL]
2587 non_null: [nULL, non_null, non null, null it is not]
2591 CHECK(tree[
"plain"].has_val());
2592 CHECK(tree[
"squoted"].has_val());
2593 CHECK(tree[
"dquoted"].has_val());
2594 CHECK(tree[
"literal"].has_val());
2595 CHECK(tree[
"folded"].has_val());
2596 CHECK( ! tree[
"all_null"].has_val());
2597 CHECK( ! tree[
"non_null"].has_val());
2599 CHECK( ! tree[
"plain"].is_container());
2600 CHECK( ! tree[
"squoted"].is_container());
2601 CHECK( ! tree[
"dquoted"].is_container());
2602 CHECK( ! tree[
"literal"].is_container());
2603 CHECK( ! tree[
"folded"].is_container());
2604 CHECK(tree[
"all_null"].is_container());
2605 CHECK(tree[
"non_null"].is_container());
2610 CHECK(tree[
"plain"].val().len == 0);
2611 CHECK(tree[
"squoted"].val().len == 0);
2612 CHECK(tree[
"dquoted"].val().len == 0);
2613 CHECK(tree[
"literal"].val().len == 0);
2614 CHECK(tree[
"folded"].val().len == 0);
2616 CHECK(tree[
"plain"].val().str ==
nullptr);
2617 CHECK(tree[
"squoted"].val().str !=
nullptr);
2618 CHECK(tree[
"dquoted"].val().str !=
nullptr);
2619 CHECK(tree[
"literal"].val().str !=
nullptr);
2620 CHECK(tree[
"folded"].val().str !=
nullptr);
2624 CHECK(tree[
"plain"].val() ==
nullptr);
2625 CHECK(tree[
"squoted"].val() !=
nullptr);
2626 CHECK(tree[
"dquoted"].val() !=
nullptr);
2627 CHECK(tree[
"literal"].val() !=
nullptr);
2628 CHECK(tree[
"folded"].val() !=
nullptr);
2633 CHECK(tree[
"plain"].val_is_null());
2634 CHECK( ! tree[
"squoted"].val_is_null());
2635 CHECK( ! tree[
"dquoted"].val_is_null());
2636 CHECK( ! tree[
"literal"].val_is_null());
2637 CHECK( ! tree[
"folded"].val_is_null());
2642 CHECK(child.val() !=
nullptr);
2643 CHECK(child.val_is_null());
2647 CHECK(child.val() !=
nullptr);
2648 CHECK( ! child.val_is_null());
2659 ryml::csubstr
null = {};
2660 ryml::csubstr nonnull =
"";
2661 ryml::csubstr strnull =
"null";
2662 ryml::csubstr tilde =
"~";
2663 CHECK(
null .len == 0);
CHECK(
null .str ==
nullptr);
CHECK(
null ==
nullptr);
2664 CHECK(nonnull.len == 0);
CHECK(nonnull.str !=
nullptr);
CHECK(nonnull !=
nullptr);
2665 CHECK(strnull.len != 0);
CHECK(strnull.str !=
nullptr);
CHECK(strnull !=
nullptr);
2666 CHECK(tilde .len != 0);
CHECK(tilde .str !=
nullptr);
CHECK(tilde !=
nullptr);
2671 tree[
"empty_null"] <<
null;
CHECK(tree.
arena() ==
"");
2673 tree[
"empty_nonnull"] << nonnull;
CHECK(tree.
arena() ==
"");
2675 tree[
"str_null"] << strnull;
CHECK(tree.
arena() ==
"null");
2677 tree[
"str_tilde"] << tilde;
CHECK(tree.
arena() ==
"null~");
2679 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null:
2689 auto null_if_nullptr = [](ryml::csubstr s) {
2690 return s.str ==
nullptr ?
"null" : s;
2692 tree[
"empty_null"] << null_if_nullptr(
null);
2693 tree[
"empty_nonnull"] << null_if_nullptr(nonnull);
2694 tree[
"str_null"] << null_if_nullptr(strnull);
2695 tree[
"str_tilde"] << null_if_nullptr(tilde);
2697 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: null
2705 auto null_if_predicate = [](ryml::csubstr s) {
2708 tree[
"empty_null"] << null_if_predicate(
null);
2709 tree[
"empty_nonnull"] << null_if_predicate(nonnull);
2710 tree[
"str_null"] << null_if_predicate(strnull);
2711 tree[
"str_tilde"] << null_if_predicate(tilde);
2713 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: null
2721 auto tilde_if_predicate = [](ryml::csubstr s) {
2724 tree[
"empty_null"] << tilde_if_predicate(
null);
2725 tree[
"empty_nonnull"] << tilde_if_predicate(nonnull);
2726 tree[
"str_null"] << tilde_if_predicate(strnull);
2727 tree[
"str_tilde"] << tilde_if_predicate(tilde);
2729 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(empty_null: ~
2748 char buf_[256] = {};
2749 ryml::substr buf = buf_;
2750 size_t size =
ryml::format(buf,
"a={} foo {} {} bar {}", 0.1, 10, 11, 12);
2751 CHECK(size == strlen(
"a=0.1 foo 10 11 bar 12"));
2752 CHECK(buf.first(size) ==
"a=0.1 foo 10 11 bar 12");
2755 size =
ryml::format({} ,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12);
2756 CHECK(size ==
ryml::format(buf,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12));
2757 CHECK(size == strlen(
"a=this_is_a foo 10 11 bar 12"));
2759 char smallbuf[8] = {};
2760 size =
ryml::format(smallbuf,
"{} is too large {}",
"this",
"for the buffer");
2761 CHECK(size == strlen(
"this is too large for the buffer"));
2763 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2767 CHECK(result ==
"b=1, damn it.");
2768 CHECK(result.is_sub(buf));
2786 CHECK(sbuf ==
"and c=2 seems about right");
2787 std::vector<char> vbuf;
2789 CHECK(sbuf ==
"and c=2 seems about right");
2792 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2799 int a = 0, b = 1, c = 2;
2800 ryml::csubstr result =
ryml::format_sub(buf_,
"{} and {} and {}", a, b, c);
2801 CHECK(result ==
"0 and 1 and 2");
2802 int aa = -1, bb = -2, cc = -3;
2803 size_t num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2805 CHECK(num_characters == result.size());
2811 CHECK(result ==
"10 and 20 and 30");
2812 num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2814 CHECK(num_characters == result.size());
2822 char buf_[256] = {};
2823 ryml::substr buf = buf_;
2824 size_t size =
ryml::cat(buf,
"a=", 0.1,
"foo", 10, 11,
"bar", 12);
2825 CHECK(size == strlen(
"a=0.1foo1011bar12"));
2826 CHECK(buf.first(size) ==
"a=0.1foo1011bar12");
2831 char smallbuf[8] = {};
2832 size =
ryml::cat(smallbuf,
"this",
" is too large ",
"for the buffer");
2833 CHECK(size == strlen(
"this is too large for the buffer"));
2835 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2838 ryml::csubstr result =
ryml::cat_sub(buf,
"b=", 1,
", damn it.");
2839 CHECK(result ==
"b=1, damn it.");
2840 CHECK(result.is_sub(buf));
2857 ryml::catrs(&sbuf,
"and c=", 2,
" seems about right");
2858 CHECK(sbuf ==
"and c=2 seems about right");
2859 std::vector<char> vbuf;
2860 ryml::catrs(&vbuf,
"and c=", 2,
" seems about right");
2861 CHECK(sbuf ==
"and c=2 seems about right");
2864 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2871 int a = 0, b = 1, c = 2;
2872 ryml::csubstr result =
ryml::cat_sub(buf_, a,
' ', b,
' ', c);
2873 CHECK(result ==
"0 1 2");
2874 int aa = -1, bb = -2, cc = -3;
2875 char sep1 =
'a', sep2 =
'b';
2876 size_t num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2877 CHECK(num_characters == result.size());
2885 CHECK(result ==
"10 20 30");
2886 num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2887 CHECK(num_characters == result.size());
2897 char buf_[256] = {};
2898 ryml::substr buf = buf_;
2900 size_t size =
ryml::catsep(buf,
' ',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2901 CHECK(buf.first(size) ==
"a= 0 b= 1 c= 2 45 67");
2904 size =
ryml::catsep(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2905 CHECK(buf.first(size) ==
"a=0 and b=1 and c=2 and 45 and 67");
2907 size =
ryml::catsep(buf,
" ... ",
"a=0",
"b=1",
"c=2", 45, 67);
2908 CHECK(buf.first(size) ==
"a=0 ... b=1 ... c=2 ... 45 ... 67");
2910 size =
ryml::catsep(buf,
'/',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2911 CHECK(buf.first(size) ==
"a=/0/b=/1/c=/2/45/67");
2913 size =
ryml::catsep(buf, 888,
"a=0",
"b=1",
"c=2", 45, 67);
2914 CHECK(buf.first(size) ==
"a=0888b=1888c=28884588867");
2920 char smallbuf[8] = {};
2922 CHECK(size == strlen(
"a=0888b=1888c=28884588867"));
2924 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"a=0888b\0");
2927 ryml::csubstr result =
ryml::catsep_sub(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2928 CHECK(result ==
"a=0 and b=1 and c=2 and 45 and 67");
2929 CHECK(result.is_sub(buf));
2947 CHECK(sbuf ==
"a=0 and b=1 and c=2 and 45 and 67");
2948 std::vector<char> vbuf;
2954 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");
2959 char buf_[256] = {};
2961 int a = 0, b = 1, c = 2;
2963 CHECK(result ==
"0 1 2");
2964 int aa = -1, bb = -2, cc = -3;
2967 CHECK(num_characters == result.size());
2975 CHECK(result ==
"10 20 30");
2977 CHECK(num_characters == result.size());
2986 using namespace ryml;
2987 char buf_[256] = {};
3006 CHECK(
"3735928559" ==
cat_sub(buf, UINT32_C(0xdeadbeef)));
3130 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wcast-align")
3131 const uint32_t payload[] = {10, 20, 30, 40, UINT32_C(0xdeadbeef)};
3133 csubstr expected = csubstr((
const char *)payload,
sizeof(payload));
3135 CHECK(!actual.overlaps(expected));
3136 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3138 for(
const uint32_t value : payload)
3141 expected = csubstr((
const char *)&value,
sizeof(value));
3143 CHECK(actual.size() ==
sizeof(uint32_t));
3144 CHECK(!actual.overlaps(expected));
3145 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3148 CHECK(actual.size() ==
sizeof(uint32_t));
3149 CHECK(!actual.overlaps(expected));
3150 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3155 CHECK(&result == (uint32_t*)reader.buf);
3156 CHECK(reader.len ==
sizeof(uint32_t));
3157 uncat(actual, reader);
3160 result = *(uint32_t*)reader.buf;
3161 CHECK(result == value);
3163 C4_SUPPRESS_WARNING_GCC_CLANG_POP
3182 struct text_and_base64 { ryml::csubstr text,
base64; };
3183 text_and_base64 cases[] = {
3184 {{
"Love all, trust a few, do wrong to none."}, {
"TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg=="}},
3185 {{
"The fool doth think he is wise, but the wise man knows himself to be a fool."}, {
"VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg=="}},
3186 {{
"Brevity is the soul of wit."}, {
"QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu"}},
3187 {{
"All that glitters is not gold."}, {
"QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu"}},
3190 for(text_and_base64 c : cases)
3193 CHECK(tree[c.text].
val() == c.base64);
3196 for(text_and_base64 c : cases)
3199 CHECK(tree[c.base64].
val() == c.text);
3201 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"('Love all, trust a few, do wrong to none.': TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg==
3202 'The fool doth think he is wise, but the wise man knows himself to be a fool.': VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg==
3203 Brevity is the soul of wit.: QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu
3204 All that glitters is not gold.: QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu
3205 TG92ZSBhbGwsIHRydXN0IGEgZmV3LCBkbyB3cm9uZyB0byBub25lLg==: 'Love all, trust a few, do wrong to none.'
3206 VGhlIGZvb2wgZG90aCB0aGluayBoZSBpcyB3aXNlLCBidXQgdGhlIHdpc2UgbWFuIGtub3dzIGhpbXNlbGYgdG8gYmUgYSBmb29sLg==: 'The fool doth think he is wise, but the wise man knows himself to be a fool.'
3207 QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu: Brevity is the soul of wit.
3208 QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu: All that glitters is not gold.
3210 char buf1_[128], buf2_[128];
3211 ryml::substr buf1 = buf1_;
3212 ryml::substr buf2 = buf2_;
3213 std::string result = {};
3215 for(
const text_and_base64 c : cases)
3220 CHECK(len <= buf1.len);
3221 CHECK(len <= buf2.len);
3222 CHECK(c.text.len == len);
3223 CHECK(buf1.first(len) == c.text);
3224 CHECK(buf2.first(len) == c.text);
3229 if(len > result.size())
3235 CHECK(result == c.text);
3239 ryml::blob strblob(&result[0], result.size());
3240 CHECK(strblob.buf == result.data());
3241 CHECK(strblob.len == result.size());
3243 if(len > result.size())
3246 strblob = {&result[0], result.
size()};
3247 CHECK(strblob.buf == result.data());
3248 CHECK(strblob.len == result.size());
3252 CHECK(result == c.text);
3257 ryml::csubstr encoded = tree[c.text].
val();
3258 CHECK(encoded == c.base64);
3259 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3260 if(len > result.size())
3263 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3266 CHECK(result == c.text);
3269 for(
const text_and_base64 c : cases)
3274 CHECK(len <= buf1.len);
3275 CHECK(len <= buf2.len);
3276 CHECK(c.text.len == len);
3277 CHECK(buf1.first(len) == c.text);
3278 CHECK(buf2.first(len) == c.text);
3282 if(len > result.size())
3288 CHECK(result == c.text);
3292 ryml::blob strblob = {&result[0], result.size()};
3293 CHECK(strblob.buf == result.data());
3294 CHECK(strblob.len == result.size());
3296 if(len > result.size())
3299 strblob = {&result[0], result.
size()};
3300 CHECK(strblob.buf == result.data());
3301 CHECK(strblob.len == result.size());
3305 CHECK(result == c.text);
3310 ryml::csubstr encoded = tree[c.base64].
key();
3311 CHECK(encoded == c.base64);
3312 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3313 if(len > result.size())
3316 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3319 CHECK(result == c.text);
3323 const uint64_t valin = UINT64_C(0xdeadbeef);
3324 uint64_t valout = 0;
3327 CHECK(len <=
sizeof(valout));
3328 CHECK(valout == UINT64_C(0xdeadbeef));
3332 const uint32_t data_in[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xdeadbeef};
3333 uint32_t data_out[11] = {};
3334 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) != 0);
3337 CHECK(len <=
sizeof(data_out));
3338 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) == 0);
3573 CHECK(v2in.x == v2out.x);
3574 CHECK(v2in.y == v2out.y);
3579 CHECK(v3in.x == v3out.x);
3580 CHECK(v3in.y == v3out.y);
3581 CHECK(v3in.z == v3out.z);
3586 CHECK(v4in.x == v4out.x);
3587 CHECK(v4in.y == v4out.y);
3588 CHECK(v4in.z == v4out.z);
3589 CHECK(v4in.w == v4out.w);
3590 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(10,11)'
3592 v4: '(1000,1001,1002,1003)'
3602 CHECK(eov2in.x == pov2out.x);
3603 CHECK(eov2in.y == pov2out.y);
3608 CHECK(eov3in.x == pov3out.x);
3609 CHECK(eov3in.y == pov3out.y);
3610 CHECK(eov3in.z == pov3out.z);
3615 CHECK(eov4in.x == pov4out.x);
3616 CHECK(eov4in.y == pov4out.y);
3617 CHECK(eov4in.z == pov4out.z);
3618 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(20,21)'
3672 template<
class K,
class V>
3697 template<
class K,
class V>
3725 template<
class K,
class V>
3730 for(
auto const ch : n)
3733 map->
map_member.emplace(std::make_pair(std::move(k), std::move(v)));
3744 n[
"seq"] >> val->
seq;
3745 n[
"map"] >> val->
map;
3764 {{101, 102, 103, 104, 105, 106, 107}},
3765 {{{1001, 2001}, {1002, 2002}, {1003, 2003}}},
3781 CHECK(mt_in.seq.seq_member.size() > 0);
3783 for(
size_t i = 0; i < mt_in.seq.seq_member.size(); ++i)
3787 CHECK(mt_in.map.map_member.size() > 0);
3789 for(
auto const& kv : mt_in.map.map_member)
3794 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(v2: '(20,21)'
3821 std::string yml_std_string = R
"(- v2: '(20,21)'
3838 v4: '(140,141,142,143)'
3853 v4: '(240,241,242,243)'
3871 std::vector<my_type> vmt;
3873 CHECK(vmt.size() == 3);
3876 CHECK(ryml::emitrs_yaml<std::string>(tree_out) == yml_std_string);
3885 std::vector<double> reference{1.23234412342131234, 2.12323123143434237, 3.67847983572591234};
3889 const double precision_safe = 1.e-14;
3890 const size_t num_digits_safe = 14;
3891 const size_t num_digits_original = 17;
3892 auto get_num_digits = [](ryml::csubstr number){
return number.sub(2).len; };
3898 std::vector<double> output;
3900 CHECK(output.size() == reference.size());
3901 for(
size_t i = 0; i < reference.size(); ++i)
3904 CHECK(fabs(output[i] - reference[i]) < precision_safe);
3913 serialized.
rootref() << reference;
3914 std::cout << serialized;
3916 #if (!C4CORE_HAVE_STD_TOCHARS)
3917 CHECK(ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.23234
3920 )" || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3921 C4_UNUSED(num_digits_safe);
3923 CHECK((ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.2323441234213124
3924 - 2.1232312314343424
3925 - 3.6784798357259123
3926 )") || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3930 CHECK(get_num_digits(child.val()) >= num_digits_safe);
3933 CHECK(fabs(out - reference[pos++]) < precision_safe);
3964 auto check_precision = [&](
ryml::Tree const& serialized){
3965 std::cout << serialized;
3967 CHECK((ryml::emitrs_yaml<std::string>(serialized) == R
"(- 1.23234412342131239
3968 - 2.12323123143434245
3969 - 3.67847983572591231
3970 )") || (bool)
"this is indicative; the exact results will vary from platform to platform.");
3974 CHECK(get_num_digits(child.val()) == num_digits_original);
3977 CHECK(fabs(out - reference[pos++]) < precision_safe);
3986 for(
const double v : reference)
3988 check_precision(serialized);
3997 for(
const double v : reference)
4002 (void)snprintf(tmp,
sizeof(tmp),
"%.18g", v);
4008 check_precision(serialized);
4020 ryml::csubstr ymla =
"- 1\n- 2\n";
4021 ryml::csubstr ymlb = R
"(- a
4025 - champagne: Dom Perignon
4028 vinho verde: Soalheiro
4029 vinho tinto: Redoma 2017
4048 CHECK(output.str ==
nullptr);
4049 CHECK(output.len > 0);
4050 size_t num_needed_chars = output.len;
4051 std::vector<char> buf(num_needed_chars);
4054 CHECK(output == ymla);
4059 CHECK(output.str ==
nullptr);
4060 CHECK(output.len > 0);
4061 CHECK(output.len == ymlb.len);
4062 num_needed_chars = output.len;
4063 buf.resize(num_needed_chars);
4066 CHECK(output == ymlb);
4071 CHECK(output == ymlb);
4075 std::vector<char> another = ryml::emitrs_yaml<std::vector<char>>(treeb);
4079 another = ryml::emitrs_yaml<std::vector<char>>(treeb[3][2]);
4081 vinho verde: Soalheiro
4082 vinho tinto: Redoma 2017
4093 CHECK(output.str ==
nullptr);
4094 CHECK(output.len > 0);
4095 size_t num_needed_chars = output.len;
4097 buf.resize(num_needed_chars);
4100 CHECK(output == ymla);
4105 CHECK(output.str ==
nullptr);
4106 CHECK(output.len > 0);
4107 CHECK(output.len == ymlb.len);
4108 num_needed_chars = output.len;
4109 buf.resize(num_needed_chars);
4112 CHECK(output == ymlb);
4117 CHECK(output == ymlb);
4121 std::string another = ryml::emitrs_yaml<std::string>(treeb);
4125 another = ryml::emitrs_yaml<std::string>(treeb[3][2]);
4127 vinho verde: Soalheiro
4128 vinho tinto: Redoma 2017
4139 ryml::csubstr ymlb = R
"(- a
4143 - champagne: Dom Perignon
4146 vinho verde: Soalheiro
4147 vinho tinto: Redoma 2017
4163 std::stringstream ss;
4171 std::stringstream ss;
4182 "champagne": "Dom Perignon",
4183 "coffee": "Arabica",
4185 "vinho verde": "Soalheiro",
4186 "vinho tinto": "Redoma 2017"
4204 std::stringstream ss;
4208 vinho verde: Soalheiro
4209 vinho tinto: Redoma 2017
4215 std::stringstream ss;
4219 "vinho verde": "Soalheiro",
4220 "vinho tinto": "Redoma 2017"
4232 ryml::csubstr yml = R
"(- a
4236 - champagne: Dom Perignon
4239 vinho verde: Soalheiro
4240 vinho tinto: Redoma 2017
4256 CHECK(len == yml.len);
4269 - champagne: Dom Perignon
4272 vinho verde: Soalheiro
4273 vinho tinto: Redoma 2017
4286 CHECK(ryml::emitrs_yaml<std::string>(tree[3]["beer"]) == R
"(beer:
4294 CHECK(ryml::emitrs_yaml<std::string>(tree[3]["beer"][0]) ==
"Rochefort 10");
4295 CHECK(ryml::emitrs_yaml<std::string>(tree[3][
"beer"][3]) == R
"(- and so
4311 ryml::csubstr yaml = R
"(block map:
4312 block key: block val
4317 flow map, singleline: {flow key: flow val}
4318 flow seq, singleline: [flow val,flow val]
4319 flow map, multiline: {
4322 flow seq, multiline: [
4330 CHECK(tree[
"block map"].is_key_plain());
4331 CHECK(tree[
"block seq"].is_key_plain());
4332 CHECK(tree[
"flow map, singleline"].is_key_plain());
4333 CHECK(tree[
"flow seq, singleline"].is_key_plain());
4334 CHECK(tree[
"flow map, multiline"].is_key_plain());
4335 CHECK(tree[
"flow seq, multiline"].is_key_plain());
4336 CHECK(tree[
"block map"].is_block());
4337 CHECK(tree[
"block seq"].is_block());
4339 CHECK(tree[
"flow map, singleline"].is_flow_sl());
4340 CHECK(tree[
"flow seq, singleline"].is_flow_sl());
4341 CHECK(tree[
"flow map, multiline"].is_flow_ml());
4342 CHECK(tree[
"flow seq, multiline"].is_flow_ml());
4344 CHECK(tree[
"flow map, singleline"].is_flow());
4345 CHECK(tree[
"flow seq, singleline"].is_flow());
4346 CHECK(tree[
"flow map, multiline"].is_flow());
4347 CHECK(tree[
"flow seq, multiline"].is_flow());
4353 CHECK(tostr(tree) == yaml);
4362 CHECK(tostr(n) ==
"block map:\n block key: block val\n");
4367 CHECK(tostr(n) ==
"'block map': {block key: block val}\n");
4372 CHECK(tostr(n) ==
"block seq:\n - block val 1\n - block val 2\n - 'quoted'\n");
4376 CHECK(tostr(n) ==
"\"block seq\": [\n block val 1,\n block val 2,\n quoted\n ]\n");
4381 CHECK(tostr(n) ==
"flow map, singleline: {flow key: flow val}\n");
4384 CHECK(tostr(n) ==
"flow map, singleline:\n flow key: |-\n flow val\n");
4389 CHECK(tostr(n) ==
"flow map, multiline: {\n flow key: flow val\n }\n");
4391 CHECK(tostr(n) ==
"flow map, multiline:\n flow key: flow val\n");
4396 CHECK(tostr(n) ==
"flow seq, singleline: [flow val,flow val]\n");
4401 CHECK(tostr(n) ==
"? >-\n flow seq, singleline\n:\n - 'flow val'\n - \"flow val\"\n");
4406 CHECK(tostr(n) ==
"flow seq, multiline: [\n flow val,\n flow val\n ]\n");
4408 CHECK(tostr(n) ==
"flow seq, multiline: [flow val,flow val]\n");
4411 CHECK(tostr(tree) != yaml);
4412 CHECK(tostr(tree) ==
4413 R
"('block map': {block key: block val}
4419 flow map, singleline:
4423 flow seq, singleline
4427 flow map, multiline:
4429 flow seq, multiline: [flow val,flow val]
4434 CHECK(tostr(tree) ==
4436 block key: block val
4441 flow map, singleline:
4445 flow seq, singleline
4449 flow map, multiline:
4451 flow seq, multiline: [flow val,flow val]
4460 CHECK(tostr(tree) ==
4462 block key: block val
4467 'flow map, singleline':
4469 'flow seq, singleline':
4472 'flow map, multiline':
4474 'flow seq, multiline':
4485 CHECK(tostr(tree) ==
4487 block key: block val
4492 'flow map, singleline':
4494 'flow seq, singleline':
4497 'flow map, multiline':
4499 'flow seq, multiline':
4524 CHECK(tostr(tree) ==
4526 'block key': "block val"
4527 'block seq': ["block val 1","block val 2","quoted"]
4528 'flow map, singleline':
4529 'flow key': "flow val"
4530 'flow seq, singleline': ["flow val","flow val"]
4531 'flow map, multiline':
4532 'flow key': "flow val"
4533 'flow seq, multiline': ["flow val","flow val"]
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':
4549 'flow map, multiline':
4550 'flow key': "flow val"
4551 'flow seq, multiline': ["flow val","flow val"]
4568 return ryml::emitrs_yaml<std::string>(n, opts);
4570 ryml::csubstr yaml =
"{map: {seq: [0, 1, 2, 3, [40, 41]]}}";
4574 CHECK(tostr(tree, defaults) ==
"{map: {seq: [0,1,2,3,[40,41]]}}");
4581 CHECK(tostr(tree, defaults) ==
4599 CHECK(tostr(tree, noindent) ==
4618 CHECK(tostr(tree, noindent) ==
4634 CHECK(tostr(tree, noindent) ==
4656 ryml::csubstr yaml = R
"({
4671 ryml::csubstr yaml_not_indented = R"({
4690 CHECK(tree[
"map"].is_flow_ml());
4692 CHECK(ryml::emitrs_yaml<std::string>(tree) == yaml);
4699 CHECK(tree[
"map"].is_flow_sl());
4701 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
4702 R
"({map: {seq: [0,1,2,3,[40,41]]}})");
4709 CHECK(tree[
"map"].is_flow_ml());
4710 CHECK(ryml::emitrs_yaml<std::string>(tree, noindent) == yaml_not_indented);
4723 ryml::csubstr json = R
"({
4724 "doe": "a deer, a female deer",
4725 "ray": "a drop of golden sun",
4726 "me": "a name, I call myself",
4727 "far": "a long long way to go"
4738 CHECK(ryml::emitrs_json<std::string>(tree) == json);
4739 CHECK(ryml::emitrs_json<std::string>(json_tree) == json);
4741 std::stringstream ss;
4743 CHECK(ss.str() == json);
4760 std::cout << ryml::emitrs_yaml<std::string>(json_tree);
4761 CHECK(ryml::emitrs_yaml<std::string>(json_tree) == json);
4766 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4767 R
"("doe": "a deer, a female deer"
4768 "ray": "a drop of golden sun"
4769 "me": "a name, I call myself"
4770 "far": "a long long way to go"
4777 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4778 R
"(doe: 'a deer, a female deer'
4779 ray: a drop of golden sun
4780 me: 'a name, I call myself'
4781 far: a long long way to go
4789 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4790 R
"(doe: 'a deer, a female deer'
4791 ray: 'a drop of golden sun'
4792 me: 'a name, I call myself'
4793 far: 'a long long way to go'
4823 std::string unresolved = R
"(base: &base
4824 name: Everyone has same name
4835 city: East Centerville
4838 &keyref key: &valref val
4841 std::string resolved = R"(base:
4842 name: Everyone has same name
4844 name: Everyone has same name
4847 name: Everyone has same name
4853 city: East Centerville
4859 city: East Centerville
4867 CHECK( ! tree[
"base"].has_key_anchor());
4868 CHECK( tree[
"base"].has_val_anchor());
4869 CHECK( tree[
"base"].val_anchor() ==
"base");
4870 CHECK( tree[
"key"].key_anchor() ==
"keyref");
4871 CHECK( tree[
"key"].val_anchor() ==
"valref");
4872 CHECK( tree[
"*valref"].is_key_ref());
4873 CHECK( tree[
"*valref"].is_val_ref());
4874 CHECK( tree[
"*valref"].key_ref() ==
"valref");
4875 CHECK( tree[
"*valref"].val_ref() ==
"keyref");
4882 CHECK( ! tree[
"base"].has_key_anchor());
4883 CHECK( ! tree[
"base"].has_val_anchor());
4884 CHECK( ! tree[
"base"].has_val_anchor());
4885 CHECK( ! tree[
"key"].has_key_anchor());
4886 CHECK( ! tree[
"key"].has_val_anchor());
4887 CHECK( ! tree[
"val"].is_key_ref());
4888 CHECK( ! tree[
"val"].is_val_ref());
4890 CHECK(tree[
"ship_to"][
"city"].val() ==
"East Centerville");
4891 CHECK(tree[
"ship_to"][
"state"].val() ==
"KS");
4909 t[
"nref"] =
"*vanchor";
4910 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(&kanchor kanchor: 2
4917 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(kanchor: 2
4928 orig: &orig {foo: bar, baz: bat}
4936 t[
"notref"][
"<<"] =
"*orig";
4937 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(orig: &orig {foo: bar,baz: bat}
4939 notcopy: {test: *orig,<<: *orig}
4940 notref: {<<: '*orig'}
4943 CHECK(ryml::emitrs_yaml<std::string>(t) == R"(orig: {foo: bar,baz: bat}
4944 copy: {foo: bar,baz: bat}
4945 notcopy: {test: {foo: bar,baz: bat},foo: bar,baz: bat}
4946 notref: {<<: '*orig'}
4953 orig2: &orig2 {baz: bat}
4954 orig3: &orig3 {and: more}
4962 CHECK(ryml::emitrs_yaml<std::string>(t) == R
"(orig1: &orig1 {foo: bar}
4963 orig2: &orig2 {baz: bat}
4964 orig3: &orig3 {and: more}
4965 copy: {<<: [*orig1,*orig2,*orig3]}
4968 CHECK(ryml::emitrs_yaml<std::string>(t) == R"(orig1: {foo: bar}
4971 copy: {foo: bar,baz: bat,and: more}
4981 const std::string yaml = R
"(--- !!map
5007 CHECK(doc.is_doc());
5009 CHECK(root[0].has_val_tag());
5010 CHECK(root[0].val_tag() ==
"!!map");
5011 CHECK(root[1].val_tag() ==
"!map");
5012 CHECK(root[2].val_tag() ==
"!!seq");
5013 CHECK(root[3].val_tag() ==
"!!str");
5014 CHECK(root[4].val_tag() ==
"!!str");
5015 CHECK(root[5][
"a"].has_key_tag());
5016 CHECK(root[5][
"a"].key_tag() ==
"!!str");
5017 CHECK(root[6].val_tag() ==
"!!set");
5018 CHECK(root[7].val_tag() ==
"!!set");
5019 CHECK(root[8].val_tag() ==
"!!seq");
5020 CHECK(root[8][0].val_tag() ==
"!!int");
5021 CHECK(root[8][1].val_tag() ==
"!!str");
5070 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree) == R
"(--- !!map
5093 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree_long) == R
"(--- !<tag:yaml.org,2002:map>
5098 --- !<tag:yaml.org,2002:seq>
5101 --- !<tag:yaml.org,2002:str> a b
5102 --- !<tag:yaml.org,2002:str> 'a: b'
5104 !<tag:yaml.org,2002:str> a: b
5105 --- !<tag:yaml.org,2002:set>
5108 --- !<tag:yaml.org,2002:set>
5110 --- !<tag:yaml.org,2002:seq>
5111 - !<tag:yaml.org,2002:int> 0
5112 - !<tag:yaml.org,2002:str> 1
5121 const std::string yaml = R
"(
5124 !m!light fluorescent
5131 CHECK(ryml::emitrs_yaml<std::string>(tree) == R"(%TAG !m! !my-
5132 --- !m!light fluorescent
5140 CHECK(ryml::emitrs_yaml<std::string>(tree) == R
"(%TAG !m! !my-
5141 --- !<!my-light> fluorescent
5144 --- !<!meta-light> green
5155 std::string yml = R
"(---
5168 CHECK(ryml::emitrs_yaml<std::string>(tree) == yml);
5179 CHECK(doc.is_doc());
5196 CHECK(stream[0].is_doc());
5197 CHECK(stream[0].is_map());
5198 CHECK(stream[0][
"a"].val() ==
"0");
5199 CHECK(stream[0][
"b"].val() ==
"1");
5208 CHECK(stream[1].is_doc());
5209 CHECK(stream[1].is_map());
5210 CHECK(stream[1][
"c"].val() ==
"2");
5211 CHECK(stream[1][
"d"].val() ==
"3");
5220 CHECK(stream[2].is_doc());
5221 CHECK(stream[2].is_seq());
5222 CHECK(stream[2][0].val() ==
"4");
5223 CHECK(stream[2][1].val() ==
"5");
5224 CHECK(stream[2][2].val() ==
"6");
5225 CHECK(stream[2][3].val() ==
"7");
5244 const std::string expected_json[] = {
5245 "{\n \"a\": 0,\n \"b\": 1\n}\n",
5246 "{\n \"c\": 2,\n \"d\": 3\n}\n",
5247 "[\n 4,\n 5,\n 6,\n 7\n]\n",
5256 CHECK(ryml::emitrs_json<std::string>(doc) == expected_json[count++]);
5266 CHECK(ryml::emitrs_json<std::string>(tree, doc_id) == expected_json[count++]);
5304 ryml::Tree tree = ryml::parse_in_arena(
"errorhandler.yml",
"[a: b\n}");
5315 auto cause_basic_error = []{
5323 #ifdef _RYML_WITH_EXCEPTIONS
5327 cause_basic_error();
5334 CHECK(!msg.empty());
5342 ryml::csubstr ymlsrc = R
"({
5346 ryml::csubstr ymlfile = "file.yml";
5347 auto cause_parse_error = [&]{
5371 msg_ctx.append(s.str, s.len);
5373 CHECK(
ryml::to_csubstr(msg_ctx).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5415 CHECK(errh.
saved_msg_full ==
"file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
5428 #ifdef _RYML_WITH_EXCEPTIONS
5432 cause_parse_error();
5449 auto dumpfn = [&full](ryml::csubstr s) { full.append(s.str, s.len); };
5453 CHECK(
ryml::to_csubstr(full).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5473 cause_parse_error();
5480 CHECK(!msg.empty());
5491 ryml::csubstr ymlfile =
"file.yml";
5492 ryml::csubstr ymlsrc =
"float: 123.456";
5499 tree[
"float"] >> intval;
5528 tree[
"float"] >> intval;
5540 #ifdef _RYML_WITH_EXCEPTIONS
5552 tree[
"float"] >> intval;
5561 CHECK(!msg.empty());
5573 tree[
"float"] >> intval;
5580 CHECK(!msg.empty());
5605 ryml::csubstr ymlfile =
"file.yml";
5606 ryml::csubstr ymlsrc = R
"(foo: bar
5613 auto cause_visit_error = [&]{
5615 tree[
"float"] >> intval;
5647 msg.append(s.str, s.len);
5648 }, ymlloc, ymlsrc,
"err", 3);
5691 std::vector<char>
memory_pool = std::vector<char>(10u * 1024u);
5701 uintptr_t uptr = (uintptr_t)ptr;
5702 const uintptr_t align =
alignof(max_align_t);
5705 uintptr_t prev = uptr - (uptr % align);
5706 uintptr_t next = prev + align;
5707 uintptr_t corr = next - uptr;
5708 ptr = (
void*)(((
char*)ptr) + corr);
5712 "out of memory! requested=%zu+%zu available=%zu\n",
5717 void free(
void *mem,
size_t len)
5734 static void*
s_allocate(
size_t len,
void* ,
void *this_)
5738 static void s_free(
void *mem,
size_t len,
void *this_)
5799 parser.reserve_stack(10);
5805 parser.reserve_stack(20);
5810 parse_in_arena(&parser,
"", R
"([a, b, c, d, {foo: bar, money: pennys}])", &tree);
5829 std::vector<char>
memory_pool = std::vector<char>(10u * 1024u);
5853 std::cerr <<
"out of memory! requested=" <<
alloc_size <<
" vs " <<
memory_pool.size() <<
" available" << std::endl;
5859 void free(
void *mem,
size_t len)
5904 ryml::csubstr yml1 =
"{a: b}";
5905 ryml::csubstr yml2 =
"{c: d, e: f, g: [h, i, 0, 1, 2, 3]}";
5939 CHECK(tree["doe"].val() ==
"a deer, a female deer");
5953 ryml::csubstr yaml = R
"({
5955 foo: [one, [two, three]]
5964 CHECK(parser.options().locations());
5977 parser.reserve_locations(50u);
5986 CHECK(parser.location_contents(loc).begins_with(
"{"));
5993 CHECK(parser.location_contents(loc).begins_with(
"aa"));
5998 loc = tree[
"foo"].
location(parser);
5999 CHECK(parser.location_contents(loc).begins_with(
"foo"));
6003 loc = tree[
"foo"][0].
location(parser);
6004 CHECK(parser.location_contents(loc).begins_with(
"one"));
6008 loc = tree[
"foo"][1].
location(parser);
6009 CHECK(parser.location_contents(loc).begins_with(
"["));
6012 loc = tree[
"foo"][1][0].
location(parser);
6013 CHECK(parser.location_contents(loc).begins_with(
"two"));
6017 CHECK(parser.location_contents(loc).begins_with(
"three"));
6031 CHECK(parser.location_contents(loc).begins_with(
"this is a docval"));
6046 - nested first value
6047 - nested second value
6050 nested second: value
6059 CHECK(parser.location_contents(loc).begins_with(
"a new"));
6064 loc = tree2[
"a new"].
location(parser);
6065 CHECK(parser.location_contents(loc).begins_with(
"a new"));
6070 CHECK(parser.location_contents(loc).begins_with(
"to"));
6075 loc = tree2[
"map with key"].
location(parser);
6076 CHECK(parser.location_contents(loc).begins_with(
"map with key"));
6079 loc = tree2[
"map with key"][
"first"].
location(parser);
6080 CHECK(parser.location_contents(loc).begins_with(
"first"));
6083 loc = tree2[
"map with key"][
"second"].
location(parser);
6084 CHECK(parser.location_contents(loc).begins_with(
"second"));
6088 loc = tree2[
"seq with key"].
location(parser);
6089 CHECK(parser.location_contents(loc).begins_with(
"seq with key"));
6092 loc = tree2[
"seq with key"][0].
location(parser);
6093 CHECK(parser.location_contents(loc).begins_with(
"first value"));
6097 CHECK(parser.location_contents(loc).begins_with(
"second value"));
6101 loc = tree2[
"seq with key"][2].
location(parser);
6102 CHECK(parser.location_contents(loc).begins_with(
"- nested first value"));
6105 loc = tree2[
"seq with key"][2][0].
location(parser);
6106 CHECK(parser.location_contents(loc).begins_with(
"nested first value"));
6110 loc = tree2[
"seq with key"][3].
location(parser);
6111 CHECK(parser.location_contents(loc).begins_with(
"nested first: "));
6114 loc = tree2[
"seq with key"][3][0].
location(parser);
6115 CHECK(parser.location_contents(loc).begins_with(
"nested first: "));
6130 static int num_checks = 0;
6131 static int num_failed_checks = 0;
6135 bool report_check(
int line,
const char *predicate,
bool result)
6138 const char *msg = predicate ?
"OK! " :
"OK!";
6141 ++num_failed_checks;
6142 msg = predicate ?
"FAIL: " :
"FAIL";
6144 std::cout << __FILE__ <<
':' << line <<
": " << msg << (predicate ? predicate :
"") << std::endl;
6151 std::cout <<
"Completed " << num_checks <<
" checks." << std::endl;
6152 if(num_failed_checks)
6153 std::cout <<
"ERROR: " << num_failed_checks <<
'/' << num_checks <<
" checks failed." << std::endl;
6155 std::cout <<
"SUCCESS!" << std::endl;
6156 return num_failed_checks;
6162 #ifndef C4_EXCEPTIONS
6193 bool got_error =
false;
6194 #ifdef C4_EXCEPTIONS
6197 std::forward<Fn>(fn)();
6199 catch(std::exception
const&)
6206 std::forward<Fn>(fn)();
6218 [[noreturn]]
void stopexec(std::string
const& s)
6220 #ifdef C4_EXCEPTIONS
6221 throw std::runtime_error(s);
6337 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4996)
6339 template<class CharContainer>
6342 std::FILE *fp = std::fopen(filename,
"rb");
6343 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6344 std::fseek(fp, 0, SEEK_END);
6345 long sz = std::ftell(fp);
6346 v->resize(
static_cast<typename CharContainer::size_type
>(sz));
6350 size_t ret = std::fread(&(*v)[0], 1, v->size(), fp);
6351 if(ret != (
size_t)sz) _RYML_ERR_BASIC(
"{}: failed to read: expect {}B, got {}B", filename, sz, ret);
6358 template<
class CharContainer>
6367 template<
class CharContainer>
6368 void file_put_contents(
const char *filename, CharContainer
const& v,
const char* access)
6374 void file_put_contents(
const char *filename,
const char *buf,
size_t sz,
const char* access)
6376 std::FILE *fp = std::fopen(filename, access);
6377 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6378 std::fwrite(buf, 1, sz, fp);
6381 C4_SUPPRESS_WARNING_MSVC_POP
6387 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
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.
void stopexec(std::string const &s)
interrupt execution
bool check_error_occurs(Fn &&fn)
checking that an error occurs while calling fn
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
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