85 #if defined(RYML_SINGLE_HEADER)
86 #define RYML_SINGLE_HDR_DEFINE_NOW
87 #include <ryml_all.hpp>
88 #elif defined(RYML_SINGLE_HEADER_LIB)
89 #include <ryml_all.hpp>
168 int main(
int argc,
const char* argv[])
224 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
225 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wcast-qual")
226 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
227 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
246 template<
class Fn>
bool check_error_occurs(Fn &&fn);
247 template<
class Fn>
bool check_assertion_occurs(Fn &&fn);
248 void check_enabled()
const;
249 void check_disabled()
const;
258 [[noreturn]]
static void s_error_basic(ryml::csubstr msg,
ryml::ErrorDataBasic const& errdata,
void *this_);
259 [[noreturn]]
static void s_error_parse(ryml::csubstr msg,
ryml::ErrorDataParse const& errdata,
void *this_);
260 [[noreturn]]
static void s_error_visit(ryml::csubstr msg,
ryml::ErrorDataVisit const& errdata,
void *this_);
298 template<
class CharContainer> CharContainer
file_get_contents(
const char *filename);
299 template<
class CharContainer>
size_t file_get_contents(
const char *filename, CharContainer *v);
300 template<
class CharContainer>
void file_put_contents(
const char *filename, CharContainer
const& v,
const char* access=
"wb");
301 void file_put_contents(
const char *filename,
const char *buf,
size_t sz,
const char* access);
304 bool report_check(
int line,
const char *predicate,
bool result);
307 #if defined(__DOXYGEN__) || defined(_DOXYGEN_)
309 # define CHECK(predicate) assert(predicate)
311 # if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
313 # define CHECK(predicate) do { if(!report_check(__LINE__, #predicate, (predicate))) { RYML_DEBUG_BREAK(); } } while(0)
315 # define CHECK CheckPredicate{__FILE__, __LINE__}
316 struct CheckPredicate
320 void operator() (
bool result)
const
343 char yml_buf[] =
"{foo: 1, bar: [2, 3], john: doe}";
348 CHECK(bar[0].val() ==
"2");
349 CHECK(bar[1].val() ==
"3");
350 CHECK(bar[0].val().str == yml_buf + 15);
351 CHECK(bar[1].val().str == yml_buf + 18);
354 int bar0 = 0, bar1 = 0;
363 CHECK(bar[0].val() ==
"10");
364 CHECK(bar[1].val() ==
"11");
368 CHECK(bar[2].val() ==
"12");
371 std::string expected =
"{foo: 1,bar: [10,11,12],john: doe}";
373 CHECK(ryml::emitrs_yaml<std::string>(tree) == expected);
377 std::cout << tree <<
"\n";
381 expected =
"foo: 1\n";
383 CHECK(ryml::emitrs_yaml<std::string>(foo) == expected);
466 CHECK(tree[
"foo"].is_keyval());
467 CHECK(tree[
"foo"].val() ==
"1");
469 CHECK(tree[
"bar"].is_seq());
470 CHECK(tree[
"bar"].has_key());
473 CHECK(tree[
"bar"][0].val() ==
"2");
474 CHECK(tree[
"bar"][1].val() ==
"3");
475 CHECK(tree[
"john"].val() ==
"doe");
479 CHECK(tree[0].
id() == tree[
"foo"].
id());
480 CHECK(tree[1].
id() == tree[
"bar"].
id());
481 CHECK(tree[2].
id() == tree[
"john"].
id());
483 CHECK(tree[0].
id() == tree[
"foo"].
id());
484 CHECK(tree[1].
id() == tree[
"bar"].
id());
485 CHECK(tree[2].
id() == tree[
"john"].
id());
487 CHECK(bar[0].val() ==
"2");
488 CHECK(bar[1].val() ==
"3");
495 CHECK(tree[
"john"].
key() ==
"john");
500 CHECK(root[
"foo"].
id() == root[0].
id());
501 CHECK(root[
"bar"].
id() == root[1].
id());
502 CHECK(root[
"john"].
id() == root[2].
id());
556 ryml::csubstr expected_keys[] = {
"foo",
"bar",
"john"};
561 CHECK(child.key() == expected_keys[count++]);
567 CHECK(child.key() == expected_keys[count++]);
573 CHECK(tree.
key(child_id) == expected_keys[count++]);
582 CHECK(tree.
key(child_id) == expected_keys[count++]);
642 int foo = 0, bar0 = 0, bar1 = 0;
643 std::string john_str;
646 root[
"bar"][0] >> bar0;
647 root[
"bar"][1] >> bar1;
648 root[
"john"] >> john_str;
653 CHECK(john_str ==
"doe");
654 CHECK(bar_str ==
"bar");
671 wroot[
"foo"] =
"says you";
672 wroot[
"bar"][0] =
"-2";
673 wroot[
"bar"][1] =
"-3";
674 wroot[
"john"] =
"ron";
678 CHECK(root[
"foo"].val() ==
"says you");
679 CHECK(root[
"bar"][0].val() ==
"-2");
680 CHECK(root[
"bar"][1].val() ==
"-3");
681 CHECK(root[
"john"].val() ==
"ron");
696 wroot[
"foo"] <<
"says who";
697 wroot[
"bar"][0] << 20;
698 wroot[
"bar"][1] << 30;
699 wroot[
"john"] <<
"deere";
700 CHECK(root[
"foo"].val() ==
"says who");
701 CHECK(root[
"bar"][0].val() ==
"20");
702 CHECK(root[
"bar"][1].val() ==
"30");
703 CHECK(root[
"john"].val() ==
"deere");
707 std::string ok(
"in_scope");
711 CHECK(root[
"john"].val() ==
"in_scope");
713 wroot[
"float"] << 2.4f;
717 CHECK(tree.
arena() ==
"says who2030deerein_scope2.42.400000");
725 wroot[
"newkeyval"] =
"shiny and new";
728 CHECK(root[
"newkeyval"].
key() ==
"newkeyval");
729 CHECK(root[
"newkeyval"].val() ==
"shiny and new");
730 CHECK(root[
"newkeyval (serialized)"].
key() ==
"newkeyval (serialized)");
731 CHECK(root[
"newkeyval (serialized)"].val() ==
"shiny and new (serialized)");
737 CHECK(root[
"bar"].num_children() == 2);
738 wroot[
"bar"][2] =
"oh so nice";
739 wroot[
"bar"][3] <<
"oh so nice (serialized)";
740 CHECK(root[
"bar"].num_children() == 4);
741 CHECK(root[
"bar"][2].val() ==
"oh so nice");
742 CHECK(root[
"bar"][3].val() ==
"oh so nice (serialized)");
748 CHECK(root[
"newseq"].num_children() == 0);
749 CHECK(root[
"newseq"].is_seq());
750 CHECK(root[
"newseq (serialized)"].num_children() == 0);
751 CHECK(root[
"newseq (serialized)"].is_seq());
757 CHECK(root[
"newmap"].num_children() == 0);
758 CHECK(root[
"newmap"].is_map());
759 CHECK(root[
"newmap (serialized)"].num_children() == 0);
760 CHECK(root[
"newmap (serialized)"].is_map());
793 nothing = wroot[
"I am nothing"];
808 something =
"indeed";
810 CHECK(root[
"I am something"].val() ==
"indeed");
841 CHECK(wbar[0].readable() && wbar[0].val() ==
"20");
842 CHECK( ! wbar[100].readable());
843 CHECK( ! wbar[100].readable() || wbar[100].val() ==
"100");
845 CHECK( ! wbar[0].is_seed() && wbar[0].val() ==
"20");
846 CHECK(wbar[100].is_seed() || wbar[100].val() ==
"100");
874 return seed_node.at(
"is").at(
"an").at(
"invalid").at(
"operation");
881 return seed_node[
"is"][
"an"][
"invalid"][
"operation"];
891 ryml::csubstr expected_result =
893 "bar: [20,30,oh so nice,oh so nice (serialized)]" "\n"
894 "john: in_scope" "\n"
896 "digits: 2.400000" "\n"
897 "newkeyval: shiny and new" "\n"
898 "newkeyval (serialized): shiny and new (serialized)" "\n"
900 "newseq (serialized): []" "\n"
902 "newmap (serialized): {}" "\n"
903 "I am something: indeed" "\n"
912 std::stringstream ss;
914 std::string stream_result = ss.str();
916 std::string str_result = ryml::emitrs_yaml<std::string>(tree);
921 CHECK(buf_result == expected_result);
922 CHECK(str_result == expected_result);
923 CHECK(stream_result == expected_result);
939 CHECK(tree[
"bar"][0].val() ==
"21");
941 CHECK(tree[
"bar"][0].val() ==
"22");
947 constnoderef = noderef;
953 noderef = tree[
"bar"][0];
954 constnoderef = consttree[
"bar"][0];
958 CHECK(constnoderef == noderef);
959 CHECK(!(constnoderef != noderef));
984 "# UTF8/16/32 can be placed directly in any scalar:" "\n"
986 "en: Planet (Gas)" "\n"
987 "fr: Planète (Gazeuse)" "\n"
988 "ru: Планета (Газ)" "\n"
992 "# UTF8 decoding only happens in double-quoted strings," "\n"
993 "# as per the YAML standard" "\n"
995 "decode this: \"\\u263A c\\x61f\\xE9\"" "\n"
996 "and this as well: \"\\u2705 \\U0001D11E\"" "\n"
997 "not decoded: '\\u263A \\xE2\\x98\\xBA'" "\n"
998 "neither this: '\\u2705 \\U0001D11E'" "\n");
1000 CHECK(langs[
"en"].val() ==
"Planet (Gas)");
1001 CHECK(langs[
"fr"].val() ==
"Planète (Gazeuse)");
1002 CHECK(langs[
"ru"].val() ==
"Планета (Газ)");
1003 CHECK(langs[
"ja"].val() ==
"惑星(ガス)");
1004 CHECK(langs[
"zh"].val() ==
"行星(气体)");
1008 CHECK(langs[
"decode this"].val() ==
"☺ café");
1009 CHECK(langs[
"and this as well"].val() ==
"✅ 𝄞");
1010 CHECK(langs[
"not decoded"].val() ==
"\\u263A \\xE2\\x98\\xBA");
1011 CHECK(langs[
"neither this"].val() ==
"\\u2705 \\U0001D11E");
1039 const char foobar_str[] =
"foobar";
1040 auto s = ryml::csubstr(foobar_str, strlen(foobar_str));
1041 CHECK(s ==
"foobar");
1042 CHECK(s.size() == 6);
1043 CHECK(s.data() == foobar_str);
1044 CHECK(s.size() == s.len);
1045 CHECK(s.data() == s.str);
1050 const char foobar_str[] =
"foobar";
1051 ryml::csubstr s = foobar_str;
1052 CHECK(s ==
"foobar");
1053 CHECK(s !=
"foobar0");
1054 CHECK(s.size() == 6);
1055 CHECK(s.data() == foobar_str);
1056 CHECK(s.size() == s.len);
1057 CHECK(s.data() == s.str);
1061 ryml::csubstr s =
"foobar";
1062 CHECK(s ==
"foobar");
1063 CHECK(s !=
"foobar0");
1064 CHECK(s.size() == 6);
1065 CHECK(s.size() == s.len);
1066 CHECK(s.data() == s.str);
1075 const char *foobar_str =
"foobar";
1077 CHECK(s ==
"foobar");
1078 CHECK(s !=
"foobar0");
1079 CHECK(s.size() == 6);
1080 CHECK(s.size() == s.len);
1081 CHECK(s.data() == s.str);
1092 std::string foobar_str =
"foobar";
1094 CHECK(s ==
"foobar");
1095 CHECK(s !=
"foobar0");
1096 CHECK(s.size() == 6);
1097 CHECK(s.size() == s.len);
1098 CHECK(s.data() == s.str);
1104 ryml::substr foo = buf;
1105 CHECK(foo.len == 3);
1106 CHECK(foo.data() == buf);
1107 ryml::csubstr cfoo = foo;
1108 CHECK(cfoo.data() == buf);
1117 char const foobar_str_ro[] =
"foobar";
1118 char foobar_str_rw[] =
"foobar";
1119 static_assert(std::is_array<decltype(foobar_str_ro)>::value,
"this is an array");
1120 static_assert(std::is_array<decltype(foobar_str_rw)>::value,
"this is an array");
1123 ryml::csubstr foobar = foobar_str_ro;
1124 CHECK(foobar.data() == foobar_str_ro);
1125 CHECK(foobar.size() == strlen(foobar_str_ro));
1126 CHECK(foobar ==
"foobar");
1130 ryml::csubstr foobar = foobar_str_rw;
1131 CHECK(foobar.data() == foobar_str_rw);
1132 CHECK(foobar.size() == strlen(foobar_str_rw));
1133 CHECK(foobar ==
"foobar");
1137 ryml::substr foobar = foobar_str_rw;
1138 CHECK(foobar.data() == foobar_str_rw);
1139 CHECK(foobar.size() == strlen(foobar_str_rw));
1140 CHECK(foobar ==
"foobar");
1151 char const* foobar_str_ro =
"foobar";
1152 char foobar_str_rw_[] =
"foobar";
1153 char * foobar_str_rw = foobar_str_rw_;
1154 static_assert(!std::is_array<decltype(foobar_str_ro)>::value,
"this is a decayed pointer");
1155 static_assert(!std::is_array<decltype(foobar_str_rw)>::value,
"this is a decayed pointer");
1160 CHECK(foobar.data() == foobar_str_ro);
1161 CHECK(foobar.size() == strlen(foobar_str_ro));
1162 CHECK(foobar ==
"foobar");
1167 CHECK(foobar.data() == foobar_str_rw);
1168 CHECK(foobar.size() == strlen(foobar_str_rw));
1169 CHECK(foobar ==
"foobar");
1174 CHECK(foobar.data() == foobar_str_rw);
1175 CHECK(foobar.size() == strlen(foobar_str_rw));
1176 CHECK(foobar ==
"foobar");
1186 char buf[] =
"foobar";
1187 ryml::substr foobar = buf;
1188 CHECK(foobar ==
"foobar");
1189 foobar[0] =
'F';
CHECK(foobar ==
"Foobar");
1190 foobar.back() =
'R';
CHECK(foobar ==
"FoobaR");
1191 foobar.reverse();
CHECK(foobar ==
"RabooF");
1192 foobar.reverse();
CHECK(foobar ==
"FoobaR");
1193 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FabooR");
1194 foobar.reverse_sub(1, 4);
CHECK(foobar ==
"FoobaR");
1195 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoaboR");
1196 foobar.reverse_range(2, 5);
CHECK(foobar ==
"FoobaR");
1197 foobar.replace(
'o',
'0');
CHECK(foobar ==
"F00baR");
1198 foobar.replace(
'a',
'_');
CHECK(foobar ==
"F00b_R");
1199 foobar.replace(
"_0b",
'a');
CHECK(foobar ==
"FaaaaR");
1200 foobar.toupper();
CHECK(foobar ==
"FAAAAR");
1201 foobar.tolower();
CHECK(foobar ==
"faaaar");
1202 foobar.fill(
'.');
CHECK(foobar ==
"......");
1210 ryml::csubstr s =
"fooFOObarBAR";
1211 CHECK(s.len == 12u);
1213 CHECK(s.sub(0) ==
"fooFOObarBAR");
1214 CHECK(s.sub(0, 12) ==
"fooFOObarBAR");
1215 CHECK(s.sub(0, 3) ==
"foo" );
1216 CHECK(s.sub(3) ==
"FOObarBAR");
1217 CHECK(s.sub(3, 3) ==
"FOO" );
1218 CHECK(s.sub(6) ==
"barBAR");
1219 CHECK(s.sub(6, 3) ==
"bar" );
1220 CHECK(s.sub(9) ==
"BAR");
1221 CHECK(s.sub(9, 3) ==
"BAR");
1223 CHECK(s.first(0) ==
"" );
1224 CHECK(s.first(1) ==
"f" );
1225 CHECK(s.first(2) !=
"f" );
1226 CHECK(s.first(2) ==
"fo" );
1227 CHECK(s.first(3) ==
"foo");
1229 CHECK(s.last(0) ==
"");
1230 CHECK(s.last(1) ==
"R");
1231 CHECK(s.last(2) ==
"AR");
1232 CHECK(s.last(3) ==
"BAR");
1234 CHECK(s.range(0, 12) ==
"fooFOObarBAR");
1235 CHECK(s.range(1, 12) ==
"ooFOObarBAR");
1236 CHECK(s.range(1, 11) ==
"ooFOObarBA" );
1237 CHECK(s.range(2, 10) ==
"oFOObarB" );
1238 CHECK(s.range(3, 9) ==
"FOObar" );
1240 CHECK(s.offs(0, 0) ==
"fooFOObarBAR");
1241 CHECK(s.offs(1, 0) ==
"ooFOObarBAR");
1242 CHECK(s.offs(1, 1) ==
"ooFOObarBA" );
1243 CHECK(s.offs(2, 1) ==
"oFOObarBA" );
1244 CHECK(s.offs(2, 2) ==
"oFOObarB" );
1245 CHECK(s.offs(3, 3) ==
"FOObar" );
1247 CHECK(s.right_of(0,
true) ==
"fooFOObarBAR");
1248 CHECK(s.right_of(0,
false) ==
"ooFOObarBAR");
1249 CHECK(s.right_of(1,
true) ==
"ooFOObarBAR");
1250 CHECK(s.right_of(1,
false) ==
"oFOObarBAR");
1251 CHECK(s.right_of(2,
true) ==
"oFOObarBAR");
1252 CHECK(s.right_of(2,
false) ==
"FOObarBAR");
1253 CHECK(s.right_of(3,
true) ==
"FOObarBAR");
1254 CHECK(s.right_of(3,
false) ==
"OObarBAR");
1256 CHECK(s.left_of(12,
false) ==
"fooFOObarBAR");
1257 CHECK(s.left_of(11,
true) ==
"fooFOObarBAR");
1258 CHECK(s.left_of(11,
false) ==
"fooFOObarBA" );
1259 CHECK(s.left_of(10,
true) ==
"fooFOObarBA" );
1260 CHECK(s.left_of(10,
false) ==
"fooFOObarB" );
1261 CHECK(s.left_of( 9,
true) ==
"fooFOObarB" );
1262 CHECK(s.left_of( 9,
false) ==
"fooFOObar" );
1264 ryml::csubstr FOO = s.sub(3, 3);
1265 CHECK(s.is_super(FOO));
1266 CHECK(s.left_of(FOO) ==
"foo");
1267 CHECK(s.right_of(FOO) ==
"barBAR");
1272 ryml::csubstr s =
"some substring";
1273 ryml::csubstr some = s.first(4);
1274 CHECK(some ==
"some");
1275 CHECK(s ==
"some substring");
1278 char result[32] = {0};
1279 std::snprintf(result,
sizeof(result),
"%.*s", (
int)some.len, some.str);
1280 printf(
"~~~%s~~~\n", result);
1290 char result[32] = {0};
1291 std::snprintf(result,
sizeof(result),
"%s", some.str);
1299 ryml::csubstr s =
"some substring";
1300 ryml::csubstr some = s.first(4);
1301 CHECK(some ==
"some");
1302 CHECK(s ==
"some substring");
1305 std::stringstream ss;
1307 CHECK(ss.str() ==
"some substring");
1308 CHECK(ss.str() == s);
1316 std::stringstream ss;
1318 CHECK(ss.str() ==
"some substring");
1319 CHECK(ss.str() == s);
1323 std::stringstream ss;
1325 CHECK(ss.str() ==
"some substring");
1326 CHECK(ss.str() == s);
1330 std::stringstream ss;
1332 CHECK(ss.str() ==
"some");
1333 CHECK(ss.str() == some);
1339 ryml::csubstr foobar =
"foobar";
1340 ryml::csubstr foo = foobar.first(3);
1341 CHECK(foo.is_sub(foobar));
1342 CHECK(foo.is_sub(foo));
1343 CHECK(!foo.is_super(foobar));
1344 CHECK(!foobar.is_sub(foo));
1346 CHECK(foo.is_super(foo));
1347 CHECK(foo.is_sub(foo));
1348 CHECK(foobar.is_sub(foobar));
1349 CHECK(foobar.is_super(foobar));
1354 ryml::csubstr foobar =
"foobar";
1355 ryml::csubstr foo = foobar.first(3);
1356 ryml::csubstr oba = foobar.offs(2, 1);
1357 ryml::csubstr abc =
"abc";
1358 CHECK(foobar.overlaps(foo));
1359 CHECK(foobar.overlaps(oba));
1360 CHECK(foo.overlaps(foobar));
1361 CHECK(foo.overlaps(oba));
1362 CHECK(!foo.overlaps(abc));
1363 CHECK(!abc.overlaps(foo));
1370 CHECK(ryml::csubstr(
" \t\n\rcontents without whitespace\t \n\r").trim(
"\t \n\r") ==
"contents without whitespace");
1371 ryml::csubstr aaabbb =
"aaabbb";
1372 ryml::csubstr aaa___bbb =
"aaa___bbb";
1374 CHECK(aaabbb.triml(
'a') == aaabbb.last(3));
1375 CHECK(aaabbb.trimr(
'a') == aaabbb);
1376 CHECK(aaabbb.trim (
'a') == aaabbb.last(3));
1377 CHECK(aaabbb.triml(
'b') == aaabbb);
1378 CHECK(aaabbb.trimr(
'b') == aaabbb.first(3));
1379 CHECK(aaabbb.trim (
'b') == aaabbb.first(3));
1380 CHECK(aaabbb.triml(
'c') == aaabbb);
1381 CHECK(aaabbb.trimr(
'c') == aaabbb);
1382 CHECK(aaabbb.trim (
'c') == aaabbb);
1383 CHECK(aaa___bbb.triml(
'a') == aaa___bbb.last(6));
1384 CHECK(aaa___bbb.trimr(
'a') == aaa___bbb);
1385 CHECK(aaa___bbb.trim (
'a') == aaa___bbb.last(6));
1386 CHECK(aaa___bbb.triml(
'b') == aaa___bbb);
1387 CHECK(aaa___bbb.trimr(
'b') == aaa___bbb.first(6));
1388 CHECK(aaa___bbb.trim (
'b') == aaa___bbb.first(6));
1389 CHECK(aaa___bbb.triml(
'c') == aaa___bbb);
1390 CHECK(aaa___bbb.trimr(
'c') == aaa___bbb);
1391 CHECK(aaa___bbb.trim (
'c') == aaa___bbb);
1393 CHECK(aaabbb.triml(
"ab") ==
"");
1394 CHECK(aaabbb.trimr(
"ab") ==
"");
1395 CHECK(aaabbb.trim (
"ab") ==
"");
1396 CHECK(aaabbb.triml(
"ba") ==
"");
1397 CHECK(aaabbb.trimr(
"ba") ==
"");
1398 CHECK(aaabbb.trim (
"ba") ==
"");
1399 CHECK(aaabbb.triml(
"cd") == aaabbb);
1400 CHECK(aaabbb.trimr(
"cd") == aaabbb);
1401 CHECK(aaabbb.trim (
"cd") == aaabbb);
1402 CHECK(aaa___bbb.triml(
"ab") == aaa___bbb.last(6));
1403 CHECK(aaa___bbb.triml(
"ba") == aaa___bbb.last(6));
1404 CHECK(aaa___bbb.triml(
"cd") == aaa___bbb);
1405 CHECK(aaa___bbb.trimr(
"ab") == aaa___bbb.first(6));
1406 CHECK(aaa___bbb.trimr(
"ba") == aaa___bbb.first(6));
1407 CHECK(aaa___bbb.trimr(
"cd") == aaa___bbb);
1408 CHECK(aaa___bbb.trim (
"ab") == aaa___bbb.range(3, 6));
1409 CHECK(aaa___bbb.trim (
"ba") == aaa___bbb.range(3, 6));
1410 CHECK(aaa___bbb.trim (
"cd") == aaa___bbb);
1415 CHECK(ryml::csubstr(
"'this is is single quoted'" ).unquoted() ==
"this is is single quoted");
1416 CHECK(ryml::csubstr(
"\"this is is double quoted\"").unquoted() ==
"this is is double quoted");
1422 ryml::csubstr abc___cba =
"abc___cba";
1423 ryml::csubstr abc___abc =
"abc___abc";
1424 CHECK(abc___cba.stripl(
"abc") == abc___cba.last(6));
1425 CHECK(abc___cba.stripr(
"abc") == abc___cba);
1426 CHECK(abc___cba.stripl(
"ab") == abc___cba.last(7));
1427 CHECK(abc___cba.stripr(
"ab") == abc___cba);
1428 CHECK(abc___cba.stripl(
"a") == abc___cba.last(8));
1429 CHECK(abc___cba.stripr(
"a") == abc___cba.first(8));
1430 CHECK(abc___abc.stripl(
"abc") == abc___abc.last(6));
1431 CHECK(abc___abc.stripr(
"abc") == abc___abc.first(6));
1432 CHECK(abc___abc.stripl(
"ab") == abc___abc.last(7));
1433 CHECK(abc___abc.stripr(
"ab") == abc___abc);
1434 CHECK(abc___abc.stripl(
"a") == abc___abc.last(8));
1435 CHECK(abc___abc.stripr(
"a") == abc___abc);
1441 ryml::csubstr s =
"foobar123";
1443 CHECK(s.begins_with(
'f'));
1444 CHECK(s.ends_with(
'3'));
1445 CHECK(!s.ends_with(
'2'));
1446 CHECK(!s.ends_with(
'o'));
1448 CHECK(s.begins_with(
"foobar"));
1449 CHECK(s.begins_with(
"foo"));
1450 CHECK(s.begins_with_any(
"foo"));
1451 CHECK(!s.begins_with(
"oof"));
1452 CHECK(s.begins_with_any(
"oof"));
1453 CHECK(s.ends_with(
"23"));
1454 CHECK(s.ends_with(
"123"));
1455 CHECK(s.ends_with_any(
"123"));
1456 CHECK(!s.ends_with(
"321"));
1457 CHECK(s.ends_with_any(
"231"));
1462 ryml::csubstr s =
"0123456789";
1463 CHECK(s.select(
'0') == s.sub(0, 1));
1464 CHECK(s.select(
'1') == s.sub(1, 1));
1465 CHECK(s.select(
'2') == s.sub(2, 1));
1466 CHECK(s.select(
'8') == s.sub(8, 1));
1467 CHECK(s.select(
'9') == s.sub(9, 1));
1468 CHECK(s.select(
"0123") == s.range(0, 4));
1469 CHECK(s.select(
"012" ) == s.range(0, 3));
1470 CHECK(s.select(
"01" ) == s.range(0, 2));
1471 CHECK(s.select(
"0" ) == s.range(0, 1));
1472 CHECK(s.select(
"123") == s.range(1, 4));
1473 CHECK(s.select(
"23") == s.range(2, 4));
1474 CHECK(s.select(
"3") == s.range(3, 4));
1479 ryml::csubstr s012345 =
"012345";
1482 CHECK(s012345.find(
'0' ) == 0u);
1484 CHECK(s012345.find(
'1' ) == 1u);
1486 CHECK(s012345.find(
'2' ) == 2u);
1488 CHECK(s012345.find(
'3' ) == 3u);
1492 CHECK(s012345.find(
"01" ) == 0u);
1494 CHECK(s012345.find(
"12" ) == 1u);
1496 CHECK(s012345.find(
"23" ) == 2u);
1502 ryml::csubstr buf =
"00110022003300440055";
1503 CHECK(buf.count(
'1' ) == 2u);
1504 CHECK(buf.count(
'1', 0u) == 2u);
1505 CHECK(buf.count(
'1', 1u) == 2u);
1506 CHECK(buf.count(
'1', 2u) == 2u);
1507 CHECK(buf.count(
'1', 3u) == 1u);
1508 CHECK(buf.count(
'1', 4u) == 0u);
1509 CHECK(buf.count(
'1', 5u) == 0u);
1510 CHECK(buf.count(
'0' ) == 10u);
1511 CHECK(buf.count(
'0', 0u) == 10u);
1512 CHECK(buf.count(
'0', 1u) == 9u);
1513 CHECK(buf.count(
'0', 2u) == 8u);
1514 CHECK(buf.count(
'0', 3u) == 8u);
1515 CHECK(buf.count(
'0', 4u) == 8u);
1516 CHECK(buf.count(
'0', 5u) == 7u);
1517 CHECK(buf.count(
'0', 6u) == 6u);
1518 CHECK(buf.count(
'0', 7u) == 6u);
1519 CHECK(buf.count(
'0', 8u) == 6u);
1520 CHECK(buf.count(
'0', 9u) == 5u);
1521 CHECK(buf.count(
'0', 10u) == 4u);
1522 CHECK(buf.count(
'0', 11u) == 4u);
1523 CHECK(buf.count(
'0', 12u) == 4u);
1524 CHECK(buf.count(
'0', 13u) == 3u);
1525 CHECK(buf.count(
'0', 14u) == 2u);
1526 CHECK(buf.count(
'0', 15u) == 2u);
1527 CHECK(buf.count(
'0', 16u) == 2u);
1528 CHECK(buf.count(
'0', 17u) == 1u);
1529 CHECK(buf.count(
'0', 18u) == 0u);
1530 CHECK(buf.count(
'0', 19u) == 0u);
1531 CHECK(buf.count(
'0', 20u) == 0u);
1536 ryml::csubstr s012345 =
"012345";
1539 CHECK(s012345.first_of(
'0') == 0u);
1540 CHECK(s012345.first_of(
"0") == 0u);
1541 CHECK(s012345.first_of(
"01") == 0u);
1542 CHECK(s012345.first_of(
"10") == 0u);
1543 CHECK(s012345.first_of(
"012") == 0u);
1544 CHECK(s012345.first_of(
"210") == 0u);
1545 CHECK(s012345.first_of(
"0123") == 0u);
1546 CHECK(s012345.first_of(
"3210") == 0u);
1547 CHECK(s012345.first_of(
"01234") == 0u);
1548 CHECK(s012345.first_of(
"43210") == 0u);
1549 CHECK(s012345.first_of(
"012345") == 0u);
1550 CHECK(s012345.first_of(
"543210") == 0u);
1551 CHECK(s012345.first_of(
'5') == 5u);
1552 CHECK(s012345.first_of(
"5") == 5u);
1553 CHECK(s012345.first_of(
"45") == 4u);
1554 CHECK(s012345.first_of(
"54") == 4u);
1555 CHECK(s012345.first_of(
"345") == 3u);
1556 CHECK(s012345.first_of(
"543") == 3u);
1557 CHECK(s012345.first_of(
"2345") == 2u);
1558 CHECK(s012345.first_of(
"5432") == 2u);
1559 CHECK(s012345.first_of(
"12345") == 1u);
1560 CHECK(s012345.first_of(
"54321") == 1u);
1561 CHECK(s012345.first_of(
"012345") == 0u);
1562 CHECK(s012345.first_of(
"543210") == 0u);
1569 CHECK(s012345.last_of(
'0') == 0u);
1570 CHECK(s012345.last_of(
"0") == 0u);
1571 CHECK(s012345.last_of(
"01") == 1u);
1572 CHECK(s012345.last_of(
"10") == 1u);
1573 CHECK(s012345.last_of(
"012") == 2u);
1574 CHECK(s012345.last_of(
"210") == 2u);
1575 CHECK(s012345.last_of(
"0123") == 3u);
1576 CHECK(s012345.last_of(
"3210") == 3u);
1577 CHECK(s012345.last_of(
"01234") == 4u);
1578 CHECK(s012345.last_of(
"43210") == 4u);
1579 CHECK(s012345.last_of(
"012345") == 5u);
1580 CHECK(s012345.last_of(
"543210") == 5u);
1581 CHECK(s012345.last_of(
'5') == 5u);
1582 CHECK(s012345.last_of(
"5") == 5u);
1583 CHECK(s012345.last_of(
"45") == 5u);
1584 CHECK(s012345.last_of(
"54") == 5u);
1585 CHECK(s012345.last_of(
"345") == 5u);
1586 CHECK(s012345.last_of(
"543") == 5u);
1587 CHECK(s012345.last_of(
"2345") == 5u);
1588 CHECK(s012345.last_of(
"5432") == 5u);
1589 CHECK(s012345.last_of(
"12345") == 5u);
1590 CHECK(s012345.last_of(
"54321") == 5u);
1591 CHECK(s012345.last_of(
"012345") == 5u);
1592 CHECK(s012345.last_of(
"543210") == 5u);
1593 CHECK(s012345.last_of(
'0', 6u) == 0u);
1594 CHECK(s012345.last_of(
'5', 6u) == 5u);
1595 CHECK(s012345.last_of(
"012345", 6u) == 5u);
1600 ryml::csubstr s012345 =
"012345";
1601 CHECK(s012345.first_not_of(
'a') == 0u);
1602 CHECK(s012345.first_not_of(
"ab") == 0u);
1603 CHECK(s012345.first_not_of(
'0') == 1u);
1604 CHECK(s012345.first_not_of(
"0") == 1u);
1605 CHECK(s012345.first_not_of(
"01") == 2u);
1606 CHECK(s012345.first_not_of(
"10") == 2u);
1607 CHECK(s012345.first_not_of(
"012") == 3u);
1608 CHECK(s012345.first_not_of(
"210") == 3u);
1609 CHECK(s012345.first_not_of(
"0123") == 4u);
1610 CHECK(s012345.first_not_of(
"3210") == 4u);
1611 CHECK(s012345.first_not_of(
"01234") == 5u);
1612 CHECK(s012345.first_not_of(
"43210") == 5u);
1615 CHECK(s012345.first_not_of(
'5') == 0u);
1616 CHECK(s012345.first_not_of(
"5") == 0u);
1617 CHECK(s012345.first_not_of(
"45") == 0u);
1618 CHECK(s012345.first_not_of(
"54") == 0u);
1619 CHECK(s012345.first_not_of(
"345") == 0u);
1620 CHECK(s012345.first_not_of(
"543") == 0u);
1621 CHECK(s012345.first_not_of(
"2345") == 0u);
1622 CHECK(s012345.first_not_of(
"5432") == 0u);
1623 CHECK(s012345.first_not_of(
"12345") == 0u);
1624 CHECK(s012345.first_not_of(
"54321") == 0u);
1627 CHECK(s012345.last_not_of(
'a') == 5u);
1628 CHECK(s012345.last_not_of(
"ab") == 5u);
1629 CHECK(s012345.last_not_of(
'5') == 4u);
1630 CHECK(s012345.last_not_of(
"5") == 4u);
1631 CHECK(s012345.last_not_of(
"45") == 3u);
1632 CHECK(s012345.last_not_of(
"54") == 3u);
1633 CHECK(s012345.last_not_of(
"345") == 2u);
1634 CHECK(s012345.last_not_of(
"543") == 2u);
1635 CHECK(s012345.last_not_of(
"2345") == 1u);
1636 CHECK(s012345.last_not_of(
"5432") == 1u);
1637 CHECK(s012345.last_not_of(
"12345") == 0u);
1638 CHECK(s012345.last_not_of(
"54321") == 0u);
1641 CHECK(s012345.last_not_of(
'0') == 5u);
1642 CHECK(s012345.last_not_of(
"0") == 5u);
1643 CHECK(s012345.last_not_of(
"01") == 5u);
1644 CHECK(s012345.last_not_of(
"10") == 5u);
1645 CHECK(s012345.last_not_of(
"012") == 5u);
1646 CHECK(s012345.last_not_of(
"210") == 5u);
1647 CHECK(s012345.last_not_of(
"0123") == 5u);
1648 CHECK(s012345.last_not_of(
"3210") == 5u);
1649 CHECK(s012345.last_not_of(
"01234") == 5u);
1650 CHECK(s012345.last_not_of(
"43210") == 5u);
1657 CHECK(ryml::csubstr(
"foo bar").first_non_empty_span() ==
"foo");
1658 CHECK(ryml::csubstr(
" foo bar").first_non_empty_span() ==
"foo");
1659 CHECK(ryml::csubstr(
"\n \r \t foo bar").first_non_empty_span() ==
"foo");
1660 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1661 CHECK(ryml::csubstr(
"\n \r \t foo\n\r\t bar").first_non_empty_span() ==
"foo");
1662 CHECK(ryml::csubstr(
",\n \r \t foo\n\r\t bar").first_non_empty_span() ==
",");
1666 CHECK(ryml::csubstr(
"1234 asdkjh").first_uint_span() ==
"1234");
1667 CHECK(ryml::csubstr(
"1234\rasdkjh").first_uint_span() ==
"1234");
1668 CHECK(ryml::csubstr(
"1234\tasdkjh").first_uint_span() ==
"1234");
1669 CHECK(ryml::csubstr(
"1234\nasdkjh").first_uint_span() ==
"1234");
1670 CHECK(ryml::csubstr(
"1234]asdkjh").first_uint_span() ==
"1234");
1671 CHECK(ryml::csubstr(
"1234)asdkjh").first_uint_span() ==
"1234");
1672 CHECK(ryml::csubstr(
"1234gasdkjh").first_uint_span() ==
"");
1676 CHECK(ryml::csubstr(
"-1234 asdkjh").first_int_span() ==
"-1234");
1677 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_int_span() ==
"-1234");
1678 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_int_span() ==
"-1234");
1679 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_int_span() ==
"-1234");
1680 CHECK(ryml::csubstr(
"-1234]asdkjh").first_int_span() ==
"-1234");
1681 CHECK(ryml::csubstr(
"-1234)asdkjh").first_int_span() ==
"-1234");
1682 CHECK(ryml::csubstr(
"-1234gasdkjh").first_int_span() ==
"");
1686 CHECK(ryml::csubstr(
"-1234 asdkjh").first_real_span() ==
"-1234");
1687 CHECK(ryml::csubstr(
"-1234\rasdkjh").first_real_span() ==
"-1234");
1688 CHECK(ryml::csubstr(
"-1234\tasdkjh").first_real_span() ==
"-1234");
1689 CHECK(ryml::csubstr(
"-1234\nasdkjh").first_real_span() ==
"-1234");
1690 CHECK(ryml::csubstr(
"-1234]asdkjh").first_real_span() ==
"-1234");
1691 CHECK(ryml::csubstr(
"-1234)asdkjh").first_real_span() ==
"-1234");
1692 CHECK(ryml::csubstr(
"-1234gasdkjh").first_real_span() ==
"");
1693 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1694 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1695 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1696 CHECK(ryml::csubstr(
"1.234 asdkjh").first_real_span() ==
"1.234");
1697 CHECK(ryml::csubstr(
"1.234e+5 asdkjh").first_real_span() ==
"1.234e+5");
1698 CHECK(ryml::csubstr(
"1.234e-5 asdkjh").first_real_span() ==
"1.234e-5");
1699 CHECK(ryml::csubstr(
"-1.234 asdkjh").first_real_span() ==
"-1.234");
1700 CHECK(ryml::csubstr(
"-1.234e+5 asdkjh").first_real_span() ==
"-1.234e+5");
1701 CHECK(ryml::csubstr(
"-1.234e-5 asdkjh").first_real_span() ==
"-1.234e-5");
1703 CHECK(ryml::csubstr(
"0x1.e8480p+19 asdkjh").first_real_span() ==
"0x1.e8480p+19");
1704 CHECK(ryml::csubstr(
"0x1.e8480p-19 asdkjh").first_real_span() ==
"0x1.e8480p-19");
1705 CHECK(ryml::csubstr(
"-0x1.e8480p+19 asdkjh").first_real_span() ==
"-0x1.e8480p+19");
1706 CHECK(ryml::csubstr(
"-0x1.e8480p-19 asdkjh").first_real_span() ==
"-0x1.e8480p-19");
1707 CHECK(ryml::csubstr(
"+0x1.e8480p+19 asdkjh").first_real_span() ==
"+0x1.e8480p+19");
1708 CHECK(ryml::csubstr(
"+0x1.e8480p-19 asdkjh").first_real_span() ==
"+0x1.e8480p-19");
1710 CHECK(ryml::csubstr(
"0b101.011p+19 asdkjh").first_real_span() ==
"0b101.011p+19");
1711 CHECK(ryml::csubstr(
"0b101.011p-19 asdkjh").first_real_span() ==
"0b101.011p-19");
1712 CHECK(ryml::csubstr(
"-0b101.011p+19 asdkjh").first_real_span() ==
"-0b101.011p+19");
1713 CHECK(ryml::csubstr(
"-0b101.011p-19 asdkjh").first_real_span() ==
"-0b101.011p-19");
1714 CHECK(ryml::csubstr(
"+0b101.011p+19 asdkjh").first_real_span() ==
"+0b101.011p+19");
1715 CHECK(ryml::csubstr(
"+0b101.011p-19 asdkjh").first_real_span() ==
"+0b101.011p-19");
1717 CHECK(ryml::csubstr(
"0o173.045p+19 asdkjh").first_real_span() ==
"0o173.045p+19");
1718 CHECK(ryml::csubstr(
"0o173.045p-19 asdkjh").first_real_span() ==
"0o173.045p-19");
1719 CHECK(ryml::csubstr(
"-0o173.045p+19 asdkjh").first_real_span() ==
"-0o173.045p+19");
1720 CHECK(ryml::csubstr(
"-0o173.045p-19 asdkjh").first_real_span() ==
"-0o173.045p-19");
1721 CHECK(ryml::csubstr(
"+0o173.045p+19 asdkjh").first_real_span() ==
"+0o173.045p+19");
1722 CHECK(ryml::csubstr(
"+0o173.045p-19 asdkjh").first_real_span() ==
"+0o173.045p-19");
1728 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").basename() ==
"file.tar.gz");
1729 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").dirname() ==
"/path/to/");
1730 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").basename(
'\\') ==
"file.tar.gz");
1731 CHECK(ryml::csubstr(
"C:\\path\\to\\file.tar.gz").dirname(
'\\') ==
"C:\\path\\to\\");
1732 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extshort() ==
"gz");
1733 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").extlong() ==
"tar.gz");
1734 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extshort() ==
"/path/to/file.tar");
1735 CHECK(ryml::csubstr(
"/path/to/file.tar.gz").name_wo_extlong() ==
"/path/to/file");
1740 using namespace ryml;
1741 csubstr parts[] = {
"aa",
"bb",
"cc",
"dd",
"ee",
"ff"};
1744 for(csubstr part : csubstr(
"aa/bb/cc/dd/ee/ff").split(
'/'))
1745 CHECK(part == parts[count++]);
1750 for(csubstr part : csubstr(
"aa.bb.cc.dd.ee.ff").split(
'.'))
1751 CHECK(part == parts[count++]);
1756 for(csubstr part : csubstr(
"aa-bb-cc-dd-ee-ff").split(
'-'))
1757 CHECK(part == parts[count++]);
1766 const bool skip_empty =
true;
1768 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/' ) ==
"0" );
1769 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/' ) ==
"" );
1770 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/' ) ==
"" );
1771 CHECK(ryml::csubstr(
"0/1/2" ). pop_left(
'/', skip_empty) ==
"0" );
1772 CHECK(ryml::csubstr(
"/0/1/2" ). pop_left(
'/', skip_empty) ==
"/0" );
1773 CHECK(ryml::csubstr(
"//0/1/2" ). pop_left(
'/', skip_empty) ==
"//0" );
1775 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/' ) ==
"0/1" );
1776 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/' ) ==
"/0/1" );
1777 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/' ) ==
"//0/1" );
1778 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/' ) ==
"0/1/2");
1779 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/' ) ==
"/0/1/2");
1780 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/' ) ==
"//0/1/2");
1781 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/' ) ==
"0/1/2/");
1782 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/' ) ==
"/0/1/2/");
1783 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/' ) ==
"//0/1/2/");
1784 CHECK(ryml::csubstr(
"0/1/2" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1785 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1786 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1787 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1788 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1789 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1790 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_left(
'/', skip_empty) ==
"0/1" );
1791 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_left(
'/', skip_empty) ==
"/0/1" );
1792 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_left(
'/', skip_empty) ==
"//0/1" );
1794 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/' ) ==
"2" );
1795 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/' ) ==
"" );
1796 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/' ) ==
"" );
1797 CHECK(ryml::csubstr(
"0/1/2" ). pop_right(
'/', skip_empty) ==
"2" );
1798 CHECK(ryml::csubstr(
"0/1/2/" ). pop_right(
'/', skip_empty) ==
"2/" );
1799 CHECK(ryml::csubstr(
"0/1/2//" ). pop_right(
'/', skip_empty) ==
"2//" );
1801 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/' ) ==
"1/2" );
1802 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/' ) ==
"1/2/" );
1803 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/' ) ==
"1/2//");
1804 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/' ) ==
"0/1/2" );
1805 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/' ) ==
"0/1/2/" );
1806 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/' ) ==
"0/1/2//");
1807 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/' ) ==
"/0/1/2" );
1808 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/' ) ==
"/0/1/2/" );
1809 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/' ) ==
"/0/1/2//");
1810 CHECK(ryml::csubstr(
"0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2" );
1811 CHECK(ryml::csubstr(
"0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1812 CHECK(ryml::csubstr(
"0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//");
1813 CHECK(ryml::csubstr(
"/0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2" );
1814 CHECK(ryml::csubstr(
"/0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1815 CHECK(ryml::csubstr(
"/0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//");
1816 CHECK(ryml::csubstr(
"//0/1/2" ).gpop_right(
'/', skip_empty) ==
"1/2" );
1817 CHECK(ryml::csubstr(
"//0/1/2/" ).gpop_right(
'/', skip_empty) ==
"1/2/" );
1818 CHECK(ryml::csubstr(
"//0/1/2//" ).gpop_right(
'/', skip_empty) ==
"1/2//");
1841 const char filename[] =
"ryml_example.yml";
1842 ryml::csubstr yaml =
""
1854 std::string contents = file_get_contents<std::string>(filename);
1856 CHECK(tree[
"foo"].val() ==
"1");
1857 CHECK(tree[
"bar"][0].val() ==
"2");
1858 CHECK(tree[
"bar"][1].val() ==
"3");
1863 std::vector<char> contents = file_get_contents<std::vector<char>>(filename);
1865 CHECK(tree[
"foo"].val() ==
"1");
1866 CHECK(tree[
"bar"][0].val() ==
"2");
1867 CHECK(tree[
"bar"][1].val() ==
"3");
1888 char src[] =
"{foo: 1, bar: [2, 3]}";
1889 ryml::substr srcview = src;
1894 CHECK(root[
"foo"].is_keyval());
1896 CHECK(root[
"foo"].val() ==
"1");
1897 CHECK(root[
"bar"].is_seq());
1898 CHECK(root[
"bar"].has_key());
1900 CHECK(root[
"bar"][0].val() ==
"2");
1901 CHECK(root[
"bar"][1].val() ==
"3");
1904 int foo = 0, bar0 = 0, bar1 = 0;
1906 root[
"bar"][0] >> bar0;
1907 root[
"bar"][1] >> bar1;
1913 CHECK(root[
"foo"].val().data() == src + strlen(
"{foo: "));
1914 CHECK(root[
"foo"].val().begin() == src + strlen(
"{foo: "));
1915 CHECK(root[
"foo"].val().end() == src + strlen(
"{foo: 1"));
1916 CHECK(root[
"foo"].val().is_sub(srcview));
1917 CHECK(root[
"bar"][0].val().data() == src + strlen(
"{foo: 1, bar: ["));
1918 CHECK(root[
"bar"][0].val().begin() == src + strlen(
"{foo: 1, bar: ["));
1919 CHECK(root[
"bar"][0].val().end() == src + strlen(
"{foo: 1, bar: [2"));
1920 CHECK(root[
"bar"][0].val().is_sub(srcview));
1921 CHECK(root[
"bar"][1].val().data() == src + strlen(
"{foo: 1, bar: [2, "));
1922 CHECK(root[
"bar"][1].val().begin() == src + strlen(
"{foo: 1, bar: [2, "));
1923 CHECK(root[
"bar"][1].val().end() == src + strlen(
"{foo: 1, bar: [2, 3"));
1924 CHECK(root[
"bar"][1].val().is_sub(srcview));
1928 ryml::csubstr csrcview = srcview;
1946 CHECK(root[
"foo"].is_keyval());
1948 CHECK(root[
"foo"].val() ==
"1");
1949 CHECK(root[
"bar"].is_seq());
1950 CHECK(root[
"bar"].has_key());
1952 CHECK(root[
"bar"][0].val() ==
"2");
1953 CHECK(root[
"bar"][1].val() ==
"3");
1956 int foo = 0, bar0 = 0, bar1 = 0;
1958 root[
"bar"][0] >> bar0;
1959 root[
"bar"][1] >> bar1;
1967 char src[] =
"{foo: is it really true}";
1968 ryml::substr srcview = src;
1974 ryml::csubstr csrcview = srcview;
1976 CHECK(tree[
"foo"].val() ==
"is it really true");
1995 ryml::csubstr yaml =
""
2004 CHECK(root[
"foo"].is_keyval());
2006 CHECK(root[
"foo"].val() ==
"1");
2007 CHECK(root[
"bar"].is_seq());
2008 CHECK(root[
"bar"].has_key());
2010 CHECK(root[
"bar"][0].val() ==
"2");
2011 CHECK(root[
"bar"][1].val() ==
"3");
2012 CHECK(ryml::emitrs_yaml<std::string>(tree) == yaml);
2016 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2020 "bar2: [22,32]" "\n"
2023 CHECK(root[
"foo2"].is_keyval());
2024 CHECK(root[
"foo2"].
key() ==
"foo2");
2025 CHECK(root[
"foo2"].val() ==
"12");
2026 CHECK(root[
"bar2"].is_seq());
2027 CHECK(root[
"bar2"].has_key());
2028 CHECK(root[
"bar2"].
key() ==
"bar2");
2029 CHECK(root[
"bar2"][0].val() ==
"22");
2030 CHECK(root[
"bar2"][1].val() ==
"32");
2037 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
"- a\n- b\n- {x0: 1,x1: 2}\n");
2039 CHECK(root[0].val() ==
"a");
2040 CHECK(root[1].val() ==
"b");
2041 CHECK(root[2].is_map());
2042 CHECK(root[2][
"x0"].val() ==
"1");
2043 CHECK(root[2][
"x1"].val() ==
"2");
2048 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2051 "- {x0: 1,x1: 2}" "\n"
2052 "- champagne: Dom Perignon" "\n"
2053 " coffee: Arabica" "\n"
2056 CHECK(root[0].val() ==
"a");
2057 CHECK(root[1].val() ==
"b");
2058 CHECK(root[2].is_map());
2059 CHECK(root[2][
"x0"].val() ==
"1");
2060 CHECK(root[2][
"x1"].val() ==
"2");
2061 CHECK(root[3].is_map());
2062 CHECK(root[3][
"champagne"].val() ==
"Dom Perignon");
2063 CHECK(root[3][
"coffee"].val() ==
"Arabica");
2073 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2076 "- {x0: 1,x1: 2}" "\n"
2077 "- champagne: Dom Perignon" "\n"
2078 " coffee: Arabica" "\n"
2081 " vinho verde: Soalheiro" "\n"
2082 " vinho tinto: Redoma 2017" "\n"
2084 " - Rochefort 10" "\n"
2086 " - Leffe Rituel" "\n"
2087 " always: lots of water" "\n"
2092 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2095 "- {x0: 1,x1: 2}" "\n"
2096 "- champagne: Dom Perignon" "\n"
2097 " coffee: Arabica" "\n"
2099 " vinho verde: Soalheiro" "\n"
2100 " vinho tinto: Redoma 2017" "\n"
2102 " - Rochefort 10" "\n"
2104 " - Leffe Rituel" "\n"
2105 " always: lots of water" "\n"
2115 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
2118 "- {x0: 1,x1: 2}" "\n"
2119 "- champagne: Dom Perignon" "\n"
2120 " coffee: Arabica" "\n"
2122 " vinho verde: Soalheiro" "\n"
2123 " vinho tinto: Redoma 2017" "\n"
2125 " - Rochefort 10" "\n"
2127 " - Leffe Rituel" "\n"
2128 " - Kasteel Donker" "\n"
2129 " always: lots of water" "\n"
2157 ryml::csubstr yaml =
"[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]";
2159 CHECK(ryml::emitrs_yaml<std::string>(champagnes) == yaml);
2161 yaml =
"[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]";
2163 CHECK(ryml::emitrs_yaml<std::string>(beers) == yaml);
2193 ryml::csubstr champagnes =
""
2195 "- Gosset Grande Reserve\n"
2196 "- Jacquesson 742\n"
2198 ryml::csubstr beers =
""
2202 "- Kasteel Donker\n"
2204 ryml::csubstr wines =
""
2206 "- Niepoort Redoma 2017\n"
2207 "- Vina Esmeralda\n"
2211 CHECK(ryml::emitrs_yaml<std::string>(tree) == champagnes);
2215 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2217 "- Gosset Grande Reserve\n"
2218 "- Jacquesson 742\n"
2222 "- Kasteel Donker\n"
2228 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2230 "- Niepoort Redoma 2017\n"
2231 "- Vina Esmeralda\n"
2245 "doe: a deer, a female deer" "\n"
2246 "ray: a drop of golden sun" "\n"
2249 "french-hens: 3" "\n"
2250 "calling-birds:" "\n"
2255 "xmas-fifth-day:" "\n"
2256 " calling-birds: four" "\n"
2257 " french-hens: 3" "\n"
2258 " golden-rings: 5" "\n"
2261 " location: a pear tree" "\n"
2262 " turtle-doves: two" "\n"
2269 std::vector<ryml::csubstr> keys, vals;
2272 keys.emplace_back(n.key());
2273 vals.emplace_back(n.has_val() ? n.val() : ryml::csubstr{});
2275 CHECK(keys.size() >= 6);
2276 CHECK(vals.size() >= 6);
2277 if(keys.size() >= 6 && vals.size() >= 6)
2279 CHECK(keys[0] ==
"doe");
2280 CHECK(vals[0] ==
"a deer, a female deer");
2281 CHECK(keys[1] ==
"ray");
2282 CHECK(vals[1] ==
"a drop of golden sun");
2283 CHECK(keys[2] ==
"pi");
2284 CHECK(vals[2] ==
"3.14159");
2285 CHECK(keys[3] ==
"xmas");
2286 CHECK(vals[3] ==
"true");
2287 CHECK(root[5].has_key());
2288 CHECK(root[5].is_seq());
2289 CHECK(root[5].
key() ==
"calling-birds");
2290 CHECK(!root[5].has_val());
2292 CHECK(keys[5] ==
"calling-birds");
2293 CHECK(vals[5] ==
"");
2300 ryml::csubstr calling_birds[] = {
"huey",
"dewey",
"louie",
"fred"};
2302 CHECK(n.val() == calling_birds[count++]);
2327 const char a_deer[] =
"a deer, a female deer";
2336 std::string a_drop =
"a drop of golden sun";
2339 root[
"ray"] << a_drop;
2345 CHECK(root[
"ray"].val() ==
"a drop of golden sun");
2350 root[
"french-hens"] << 3;
2359 xmas5[
"calling-birds"] =
"four";
2360 xmas5[
"french-hens"] << 3;
2361 xmas5[
"golden-rings"] << 5;
2363 xmas5[
"partridges"][
"count"] << 1;
2364 xmas5[
"partridges"][
"location"] =
"a pear tree";
2365 xmas5[
"turtle-doves"] =
"two";
2366 root[
"cars"] =
"GTO";
2368 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2369 "doe: a deer, a female deer" "\n"
2370 "ray: a drop of golden sun" "\n"
2373 "french-hens: 3" "\n"
2374 "calling-birds:" "\n"
2379 "xmas-fifth-day:" "\n"
2380 " calling-birds: four" "\n"
2381 " french-hens: 3" "\n"
2382 " golden-rings: 5" "\n"
2385 " location: a pear tree" "\n"
2386 " turtle-doves: two" "\n"
2400 char buf[] =
"[a, b, c, d]";
2401 ryml::substr yml = buf;
2407 CHECK(root[0].val().is_sub(yml));
2408 CHECK(root[1].val().is_sub(yml));
2409 CHECK(root[2].val().is_sub(yml));
2410 CHECK(root[3].val().is_sub(yml));
2411 CHECK(yml.is_super(root[0].
val()));
2412 CHECK(yml.is_super(root[1].
val()));
2413 CHECK(yml.is_super(root[2].
val()));
2414 CHECK(yml.is_super(root[3].
val()));
2421 ryml::csubstr yml =
"[a, b, c, d]";
2429 ryml::csubstr arena = tree.
arena();
2430 CHECK(root[0].val().is_sub(arena));
2431 CHECK(root[1].val().is_sub(arena));
2432 CHECK(root[2].val().is_sub(arena));
2433 CHECK(root[3].val().is_sub(arena));
2434 CHECK(arena.is_super(root[0].
val()));
2435 CHECK(arena.is_super(root[1].
val()));
2436 CHECK(arena.is_super(root[2].
val()));
2437 CHECK(arena.is_super(root[3].
val()));
2443 char buf[] =
"[a, b, c, d]";
2444 ryml::substr yml = buf;
2451 CHECK(root[2].val() ==
"c");
2452 CHECK(root[2].val().is_sub(yml));
2454 CHECK(root[2].val() ==
"12345");
2460 CHECK(root[3].val() ==
"d");
2461 CHECK(root[3].val().is_sub(yml));
2463 CHECK(root[3].val() ==
"67890");
2471 ryml::csubstr yml =
"[a, b, c, d]";
2479 CHECK(root[2].val() ==
"c");
2481 CHECK(root[2].val() ==
"12345");
2490 CHECK(root[3].val() ==
"67890");
2494 CHECK(tree.
arena() ==
"[a, b, c, d]1234567890");
2501 ryml::csubstr c10 = tree.
to_arena(10101010);
2502 CHECK(c10 ==
"10101010");
2512 CHECK(root[
"a"].val() ==
"2222");
2519 ryml::csubstr mystr =
"Gosset Grande Reserve";
2521 CHECK(!copied.overlaps(mystr));
2522 CHECK(copied == mystr);
2523 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2529 ryml::csubstr mystr =
"Gosset Grande Reserve";
2530 ryml::substr copied = tree.
alloc_arena(mystr.size());
2531 CHECK(!copied.overlaps(mystr));
2532 memcpy(copied.str, mystr.str, mystr.len);
2533 CHECK(copied == mystr);
2534 CHECK(tree.
arena() ==
"{a: b}Gosset Grande Reserve");
2540 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2543 CHECK(tree.
arena().size() == strlen(
"{a: b}"));
2545 CHECK(tree.
arena().first(12) ==
"{a: b}123456");
2583 CHECK(tree.
to_arena(
double(0.234)) ==
"0.234");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.234");
2593 const float fnan = std::numeric_limits<float >::quiet_NaN();
2594 const double dnan = std::numeric_limits<double>::quiet_NaN();
2595 const float finf = std::numeric_limits<float >::infinity();
2596 const double dinf = std::numeric_limits<double>::infinity();
2597 CHECK(tree.
to_arena( finf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf");
2598 CHECK(tree.
to_arena( dinf) ==
".inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf");
2599 CHECK(tree.
to_arena(-finf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf");
2600 CHECK(tree.
to_arena(-dinf) ==
"-.inf");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf");
2601 CHECK(tree.
to_arena( fnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan");
2602 CHECK(tree.
to_arena( dnan) ==
".nan");
CHECK(tree.
arena() ==
"abcde0101234-45-56-67-70x10.1240.23410truefalse.inf.inf-.inf-.inf.nan.nan");
2606 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
2612 tree[
"ninf"] >> f;
CHECK(f == -finf);
2613 tree[
"ninf"] >> d;
CHECK(d == -dinf);
2614 tree[
"pinf"] >> f;
CHECK(f == finf);
2615 tree[
"pinf"] >> d;
CHECK(d == dinf);
2616 tree[
"nan" ] >> f;
CHECK(std::isnan(f));
2617 tree[
"nan" ] >> d;
CHECK(std::isnan(d));
2618 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2631 t[
"val"] >> valu8;
CHECK(valu8 == 2);
2632 t[
"val"] >> vali8;
CHECK(vali8 == 2);
2634 CHECK(ryml::overflows<uint8_t>(t[
"val"].val()));
2635 CHECK(ryml::overflows<int8_t>(t[
"val"].val()));
2636 CHECK( ! ryml::overflows<int16_t>(t[
"val"].val()));
2639 auto checku8 = ryml::fmt::overflow_checked(valu8);
2640 t[
"val"] >> checku8;
2643 auto checki8 = ryml::fmt::overflow_checked(vali8);
2644 t[
"val"] >> checki8;
2660 "dquoted: \"\"" "\n"
2663 "all_null: [~, null, Null, NULL]" "\n"
2664 "non_null: [nULL, non_null, non null, null it is not]" "\n"
2668 CHECK(tree[
"plain"].has_val());
2669 CHECK(tree[
"squoted"].has_val());
2670 CHECK(tree[
"dquoted"].has_val());
2671 CHECK(tree[
"literal"].has_val());
2672 CHECK(tree[
"folded"].has_val());
2673 CHECK( ! tree[
"all_null"].has_val());
2674 CHECK( ! tree[
"non_null"].has_val());
2676 CHECK( ! tree[
"plain"].is_container());
2677 CHECK( ! tree[
"squoted"].is_container());
2678 CHECK( ! tree[
"dquoted"].is_container());
2679 CHECK( ! tree[
"literal"].is_container());
2680 CHECK( ! tree[
"folded"].is_container());
2681 CHECK(tree[
"all_null"].is_container());
2682 CHECK(tree[
"non_null"].is_container());
2687 CHECK(tree[
"plain"].val().len == 0);
2688 CHECK(tree[
"squoted"].val().len == 0);
2689 CHECK(tree[
"dquoted"].val().len == 0);
2690 CHECK(tree[
"literal"].val().len == 0);
2691 CHECK(tree[
"folded"].val().len == 0);
2693 CHECK(tree[
"plain"].val().str ==
nullptr);
2694 CHECK(tree[
"squoted"].val().str !=
nullptr);
2695 CHECK(tree[
"dquoted"].val().str !=
nullptr);
2696 CHECK(tree[
"literal"].val().str !=
nullptr);
2697 CHECK(tree[
"folded"].val().str !=
nullptr);
2701 CHECK(tree[
"plain"].val() ==
nullptr);
2702 CHECK(tree[
"squoted"].val() !=
nullptr);
2703 CHECK(tree[
"dquoted"].val() !=
nullptr);
2704 CHECK(tree[
"literal"].val() !=
nullptr);
2705 CHECK(tree[
"folded"].val() !=
nullptr);
2710 CHECK(tree[
"plain"].val_is_null());
2711 CHECK( ! tree[
"squoted"].val_is_null());
2712 CHECK( ! tree[
"dquoted"].val_is_null());
2713 CHECK( ! tree[
"literal"].val_is_null());
2714 CHECK( ! tree[
"folded"].val_is_null());
2719 CHECK(child.val() !=
nullptr);
2720 CHECK(child.val_is_null());
2724 CHECK(child.val() !=
nullptr);
2725 CHECK( ! child.val_is_null());
2736 ryml::csubstr
null = {};
2737 ryml::csubstr nonnull =
"";
2738 ryml::csubstr strnull =
"null";
2739 ryml::csubstr tilde =
"~";
2740 CHECK(
null .len == 0);
CHECK(
null .str ==
nullptr);
CHECK(
null ==
nullptr);
2741 CHECK(nonnull.len == 0);
CHECK(nonnull.str !=
nullptr);
CHECK(nonnull !=
nullptr);
2742 CHECK(strnull.len != 0);
CHECK(strnull.str !=
nullptr);
CHECK(strnull !=
nullptr);
2743 CHECK(tilde .len != 0);
CHECK(tilde .str !=
nullptr);
CHECK(tilde !=
nullptr);
2748 tree[
"empty_null"] <<
null;
CHECK(tree.
arena() ==
"");
2750 tree[
"empty_nonnull"] << nonnull;
CHECK(tree.
arena() ==
"");
2752 tree[
"str_null"] << strnull;
CHECK(tree.
arena() ==
"null");
2754 tree[
"str_tilde"] << tilde;
CHECK(tree.
arena() ==
"null~");
2756 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2758 "empty_nonnull: ''" "\n"
2759 "str_null: null" "\n"
2767 auto null_if_nullptr = [](ryml::csubstr s) {
2768 return s.str ==
nullptr ?
"null" : s;
2770 tree[
"empty_null"] << null_if_nullptr(
null);
2771 tree[
"empty_nonnull"] << null_if_nullptr(nonnull);
2772 tree[
"str_null"] << null_if_nullptr(strnull);
2773 tree[
"str_tilde"] << null_if_nullptr(tilde);
2775 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2776 "empty_null: null" "\n"
2777 "empty_nonnull: ''" "\n"
2778 "str_null: null" "\n"
2784 auto null_if_predicate = [](ryml::csubstr s) {
2787 tree[
"empty_null"] << null_if_predicate(
null);
2788 tree[
"empty_nonnull"] << null_if_predicate(nonnull);
2789 tree[
"str_null"] << null_if_predicate(strnull);
2790 tree[
"str_tilde"] << null_if_predicate(tilde);
2792 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2793 "empty_null: null" "\n"
2794 "empty_nonnull: ''" "\n"
2795 "str_null: null" "\n"
2796 "str_tilde: null" "\n"
2801 auto tilde_if_predicate = [](ryml::csubstr s) {
2804 tree[
"empty_null"] << tilde_if_predicate(
null);
2805 tree[
"empty_nonnull"] << tilde_if_predicate(nonnull);
2806 tree[
"str_null"] << tilde_if_predicate(strnull);
2807 tree[
"str_tilde"] << tilde_if_predicate(tilde);
2809 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
2810 "empty_null: ~" "\n"
2811 "empty_nonnull: ''" "\n"
2829 char buf_[256] = {};
2830 ryml::substr buf = buf_;
2831 size_t size =
ryml::format(buf,
"a={} foo {} {} bar {}", 0.1, 10, 11, 12);
2832 CHECK(size == strlen(
"a=0.1 foo 10 11 bar 12"));
2833 CHECK(buf.first(size) ==
"a=0.1 foo 10 11 bar 12");
2836 size =
ryml::format({} ,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12);
2837 CHECK(size ==
ryml::format(buf,
"a={} foo {} {} bar {}",
"this_is_a", 10, 11, 12));
2838 CHECK(size == strlen(
"a=this_is_a foo 10 11 bar 12"));
2840 char smallbuf[8] = {};
2841 size =
ryml::format(smallbuf,
"{} is too large {}",
"this",
"for the buffer");
2842 CHECK(size == strlen(
"this is too large for the buffer"));
2844 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2848 CHECK(result ==
"b=1, damn it.");
2849 CHECK(result.is_sub(buf));
2867 CHECK(sbuf ==
"and c=2 seems about right");
2868 std::vector<char> vbuf;
2870 CHECK(sbuf ==
"and c=2 seems about right");
2873 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2880 int a = 0, b = 1, c = 2;
2881 ryml::csubstr result =
ryml::format_sub(buf_,
"{} and {} and {}", a, b, c);
2882 CHECK(result ==
"0 and 1 and 2");
2883 int aa = -1, bb = -2, cc = -3;
2884 size_t num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2886 CHECK(num_characters == result.size());
2892 CHECK(result ==
"10 and 20 and 30");
2893 num_characters =
ryml::unformat(result,
"{} and {} and {}", aa, bb, cc);
2895 CHECK(num_characters == result.size());
2903 char buf_[256] = {};
2904 ryml::substr buf = buf_;
2905 size_t size =
ryml::cat(buf,
"a=", 0.1,
"foo", 10, 11,
"bar", 12);
2906 CHECK(size == strlen(
"a=0.1foo1011bar12"));
2907 CHECK(buf.first(size) ==
"a=0.1foo1011bar12");
2912 char smallbuf[8] = {};
2913 size =
ryml::cat(smallbuf,
"this",
" is too large ",
"for the buffer");
2914 CHECK(size == strlen(
"this is too large for the buffer"));
2916 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"this is\0");
2919 ryml::csubstr result =
ryml::cat_sub(buf,
"b=", 1,
", damn it.");
2920 CHECK(result ==
"b=1, damn it.");
2921 CHECK(result.is_sub(buf));
2938 ryml::catrs(&sbuf,
"and c=", 2,
" seems about right");
2939 CHECK(sbuf ==
"and c=2 seems about right");
2940 std::vector<char> vbuf;
2941 ryml::catrs(&vbuf,
"and c=", 2,
" seems about right");
2942 CHECK(sbuf ==
"and c=2 seems about right");
2945 CHECK(sbuf ==
"and c=2 seems about right, and finally d=3 - done");
2952 int a = 0, b = 1, c = 2;
2953 ryml::csubstr result =
ryml::cat_sub(buf_, a,
' ', b,
' ', c);
2954 CHECK(result ==
"0 1 2");
2955 int aa = -1, bb = -2, cc = -3;
2956 char sep1 =
'a', sep2 =
'b';
2957 size_t num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2958 CHECK(num_characters == result.size());
2966 CHECK(result ==
"10 20 30");
2967 num_characters =
ryml::uncat(result, aa, sep1, bb, sep2, cc);
2968 CHECK(num_characters == result.size());
2978 char buf_[256] = {};
2979 ryml::substr buf = buf_;
2981 size_t size =
ryml::catsep(buf,
' ',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2982 CHECK(buf.first(size) ==
"a= 0 b= 1 c= 2 45 67");
2985 size =
ryml::catsep(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
2986 CHECK(buf.first(size) ==
"a=0 and b=1 and c=2 and 45 and 67");
2988 size =
ryml::catsep(buf,
" ... ",
"a=0",
"b=1",
"c=2", 45, 67);
2989 CHECK(buf.first(size) ==
"a=0 ... b=1 ... c=2 ... 45 ... 67");
2991 size =
ryml::catsep(buf,
'/',
"a=", 0,
"b=", 1,
"c=", 2, 45, 67);
2992 CHECK(buf.first(size) ==
"a=/0/b=/1/c=/2/45/67");
2994 size =
ryml::catsep(buf, 888,
"a=0",
"b=1",
"c=2", 45, 67);
2995 CHECK(buf.first(size) ==
"a=0888b=1888c=28884588867");
3001 char smallbuf[8] = {};
3003 CHECK(size == strlen(
"a=0888b=1888c=28884588867"));
3005 CHECK(ryml::substr(smallbuf,
sizeof(smallbuf)) ==
"a=0888b\0");
3008 ryml::csubstr result =
ryml::catsep_sub(buf,
" and ",
"a=0",
"b=1",
"c=2", 45, 67);
3009 CHECK(result ==
"a=0 and b=1 and c=2 and 45 and 67");
3010 CHECK(result.is_sub(buf));
3028 CHECK(sbuf ==
"a=0 and b=1 and c=2 and 45 and 67");
3029 std::vector<char> vbuf;
3035 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");
3040 char buf_[256] = {};
3042 int a = 0, b = 1, c = 2;
3044 CHECK(result ==
"0 1 2");
3045 int aa = -1, bb = -2, cc = -3;
3047 CHECK(num_characters == result.size());
3053 CHECK(result ==
"10--20--30");
3055 CHECK(num_characters == result.size());
3063 using namespace ryml;
3064 char buf_[256] = {};
3083 CHECK(
"3735928559" ==
cat_sub(buf, UINT32_C(0xdeadbeef)));
3207 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wcast-align")
3208 const uint32_t payload[] = {10, 20, 30, 40, UINT32_C(0xdeadbeef)};
3210 csubstr expected = csubstr((
const char *)payload,
sizeof(payload));
3212 CHECK(!actual.overlaps(expected));
3213 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3215 for(
const uint32_t value : payload)
3218 expected = csubstr((
const char *)&value,
sizeof(value));
3220 CHECK(actual.size() ==
sizeof(uint32_t));
3221 CHECK(!actual.overlaps(expected));
3222 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3225 CHECK(actual.size() ==
sizeof(uint32_t));
3226 CHECK(!actual.overlaps(expected));
3227 CHECK(0 == memcmp(expected.str, actual.str, expected.len));
3230 uint32_t result = 0;
3235 CHECK(result == value);
3237 C4_SUPPRESS_WARNING_GCC_CLANG_POP
3255 struct text_and_base64 { ryml::csubstr text,
base64; };
3256 text_and_base64 cases[] = {
3257 {{
"Hello, World!"}, {
"SGVsbG8sIFdvcmxkIQ=="}},
3258 {{
"Brevity is the soul of wit."}, {
"QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu"}},
3259 {{
"All that glitters is not gold."}, {
"QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu"}},
3262 for(text_and_base64 c : cases)
3265 CHECK(tree[c.text].
val() == c.base64);
3268 for(text_and_base64 c : cases)
3271 CHECK(tree[c.base64].
val() == c.text);
3273 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
3274 "Hello, World!: SGVsbG8sIFdvcmxkIQ==" "\n"
3275 "Brevity is the soul of wit.: QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu" "\n"
3276 "All that glitters is not gold.: QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu" "\n"
3277 "SGVsbG8sIFdvcmxkIQ==: Hello, World!" "\n"
3278 "QnJldml0eSBpcyB0aGUgc291bCBvZiB3aXQu: Brevity is the soul of wit." "\n"
3279 "QWxsIHRoYXQgZ2xpdHRlcnMgaXMgbm90IGdvbGQu: All that glitters is not gold." "\n"
3281 char buf1_[128], buf2_[128];
3282 ryml::substr buf1 = buf1_;
3283 ryml::substr buf2 = buf2_;
3284 std::string result = {};
3286 for(
const text_and_base64 c : cases)
3291 CHECK(len <= buf1.len);
3292 CHECK(len <= buf2.len);
3293 CHECK(c.text.len == len);
3294 CHECK(buf1.first(len) == c.text);
3295 CHECK(buf2.first(len) == c.text);
3300 if(len > result.size())
3306 CHECK(result == c.text);
3310 ryml::blob strblob(&result[0], result.size());
3311 CHECK(strblob.buf == result.data());
3312 CHECK(strblob.len == result.size());
3314 if(len > result.size())
3317 strblob = {&result[0], result.
size()};
3318 CHECK(strblob.buf == result.data());
3319 CHECK(strblob.len == result.size());
3323 CHECK(result == c.text);
3328 ryml::csubstr encoded = tree[c.text].
val();
3329 CHECK(encoded == c.base64);
3330 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3331 if(len > result.size())
3334 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3337 CHECK(result == c.text);
3340 for(
const text_and_base64 c : cases)
3345 CHECK(len <= buf1.len);
3346 CHECK(len <= buf2.len);
3347 CHECK(c.text.len == len);
3348 CHECK(buf1.first(len) == c.text);
3349 CHECK(buf2.first(len) == c.text);
3353 if(len > result.size())
3359 CHECK(result == c.text);
3363 ryml::blob strblob = {&result[0], result.size()};
3364 CHECK(strblob.buf == result.data());
3365 CHECK(strblob.len == result.size());
3367 if(len > result.size())
3370 strblob = {&result[0], result.
size()};
3371 CHECK(strblob.buf == result.data());
3372 CHECK(strblob.len == result.size());
3376 CHECK(result == c.text);
3381 ryml::csubstr encoded = tree[c.base64].
key();
3382 CHECK(encoded == c.base64);
3383 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3384 if(len > result.size())
3387 len =
base64_decode(encoded, ryml::blob{&result[0], result.size()});
3390 CHECK(result == c.text);
3394 const uint64_t valin = UINT64_C(0xdeadbeef);
3395 uint64_t valout = 0;
3398 CHECK(len <=
sizeof(valout));
3399 CHECK(valout == UINT64_C(0xdeadbeef));
3403 const uint32_t data_in[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xdeadbeef};
3404 uint32_t data_out[11] = {};
3405 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) != 0);
3408 CHECK(len <=
sizeof(data_out));
3409 CHECK(memcmp(data_in, data_out,
sizeof(data_in)) == 0);
3644 CHECK(v2in.x == v2out.x);
3645 CHECK(v2in.y == v2out.y);
3650 CHECK(v3in.x == v3out.x);
3651 CHECK(v3in.y == v3out.y);
3652 CHECK(v3in.z == v3out.z);
3657 CHECK(v4in.x == v4out.x);
3658 CHECK(v4in.y == v4out.y);
3659 CHECK(v4in.z == v4out.z);
3660 CHECK(v4in.w == v4out.w);
3661 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
3663 "v3: (100,101,102)" "\n"
3664 "v4: (1000,1001,1002,1003)" "\n"
3674 CHECK(eov2in.x == pov2out.x);
3675 CHECK(eov2in.y == pov2out.y);
3680 CHECK(eov3in.x == pov3out.x);
3681 CHECK(eov3in.y == pov3out.y);
3682 CHECK(eov3in.z == pov3out.z);
3687 CHECK(eov4in.x == pov4out.x);
3688 CHECK(eov4in.y == pov4out.y);
3689 CHECK(eov4in.z == pov4out.z);
3690 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
3692 "v3: (30,31,32)" "\n"
3693 "v4: (40,41,42,43)" "\n"
3745 template<
class K,
class V>
3770 template<
class K,
class V>
3798 template<
class K,
class V>
3803 for(
auto const ch : n)
3806 map->
map_member.emplace(std::make_pair(std::move(k), std::move(v)));
3817 n[
"seq"] >> val->
seq;
3818 n[
"map"] >> val->
map;
3837 {{101, 102, 103, 104, 105, 106, 107}},
3838 {{{1001, 2001}, {1002, 2002}, {1003, 2003}}},
3854 CHECK(mt_in.seq.seq_member.size() > 0);
3856 for(
size_t i = 0; i < mt_in.seq.seq_member.size(); ++i)
3860 CHECK(mt_in.map.map_member.size() > 0);
3862 for(
auto const& kv : mt_in.map.map_member)
3867 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
3869 "v3: (30,31,32)" "\n"
3870 "v4: (40,41,42,43)" "\n"
3895 std::string yml_std_string =
""
3896 "- v2: (20,21)" "\n"
3897 " v3: (30,31,32)" "\n"
3898 " v4: (40,41,42,43)" "\n"
3911 "- v2: (120,121)" "\n"
3912 " v3: (130,131,132)" "\n"
3913 " v4: (140,141,142,143)" "\n"
3923 " 11001: 12001" "\n"
3924 " 11002: 12002" "\n"
3925 " 11003: 12003" "\n"
3926 "- v2: (220,221)" "\n"
3927 " v3: (230,231,232)" "\n"
3928 " v4: (240,241,242,243)" "\n"
3938 " 21001: 22001" "\n"
3939 " 21002: 22002" "\n"
3940 " 21003: 22003" "\n"
3946 std::vector<my_type> vmt;
3948 CHECK(vmt.size() == 3);
3951 CHECK(ryml::emitrs_yaml<std::string>(tree_out) == yml_std_string);
3960 std::vector<double> reference{1.23234412342131234, 2.12323123143434237, 3.67847983572591234};
3964 const double precision_safe = 1.e-14;
3965 const size_t num_digits_safe = 14;
3966 const size_t num_digits_original = 17;
3967 auto get_num_digits = [](ryml::csubstr number){
return number.len - 2u; };
3973 std::vector<double> output;
3975 CHECK(output.size() == reference.size());
3976 for(
size_t i = 0; i < reference.size(); ++i)
3979 CHECK(fabs(output[i] - reference[i]) < precision_safe);
3988 serialized.
rootref() << reference;
3989 std::cout << serialized;
3991 #if (!C4CORE_HAVE_STD_TOCHARS)
3992 CHECK((ryml::emitrs_yaml<std::string>(serialized) ==
""
3996 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
3997 C4_UNUSED(num_digits_safe);
4000 CHECK((ryml::emitrs_yaml<std::string>(serialized) ==
""
4001 "- 1.2323441234213124" "\n"
4002 "- 2.1232312314343424" "\n"
4003 "- 3.6784798357259123" "\n"
4004 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
4008 CHECK(get_num_digits(child.val()) >= num_digits_safe);
4011 CHECK(fabs(out - reference[pos++]) < precision_safe);
4042 auto check_precision = [&](
ryml::Tree const& serialized){
4043 std::cout << serialized;
4045 CHECK((ryml::emitrs_yaml<std::string>(serialized) ==
""
4046 "- 1.23234412342131239" "\n"
4047 "- 2.12323123143434245" "\n"
4048 "- 3.67847983572591231" "\n"
4049 "") || (
bool)
"this is indicative; the exact results will vary from platform to platform.");
4053 CHECK(get_num_digits(child.val()) == num_digits_original);
4056 CHECK(fabs(out - reference[pos++]) < precision_safe);
4065 for(
const double v : reference)
4067 check_precision(serialized);
4076 for(
const double v : reference)
4081 (void)snprintf(tmp,
sizeof(tmp),
"%.18g", v);
4087 check_precision(serialized);
4098 ryml::csubstr ymla =
4102 ryml::csubstr ymlb =
4107 "- champagne: Dom Perignon" "\n"
4108 " coffee: Arabica" "\n"
4110 " vinho verde: Soalheiro" "\n"
4111 " vinho tinto: Redoma 2017" "\n"
4113 " - Rochefort 10" "\n"
4115 " - Leffe Rituel" "\n"
4132 CHECK(output.str ==
nullptr);
4133 CHECK(output.len > 0);
4134 size_t num_needed_chars = output.len;
4135 std::vector<char> buf(num_needed_chars);
4138 CHECK(output == ymla);
4143 CHECK(output.str ==
nullptr);
4144 CHECK(output.len > 0);
4145 CHECK(output.len == ymlb.len);
4146 num_needed_chars = output.len;
4147 buf.resize(num_needed_chars);
4150 CHECK(output == ymlb);
4155 CHECK(output == ymlb);
4159 std::vector<char> another = ryml::emitrs_yaml<std::vector<char>>(treeb);
4163 another = ryml::emitrs_yaml<std::vector<char>>(treeb[3][2]);
4166 " vinho verde: Soalheiro" "\n"
4167 " vinho tinto: Redoma 2017" "\n"
4178 CHECK(output.str ==
nullptr);
4179 CHECK(output.len > 0);
4180 size_t num_needed_chars = output.len;
4182 buf.resize(num_needed_chars);
4185 CHECK(output == ymla);
4190 CHECK(output.str ==
nullptr);
4191 CHECK(output.len > 0);
4192 CHECK(output.len == ymlb.len);
4193 num_needed_chars = output.len;
4194 buf.resize(num_needed_chars);
4197 CHECK(output == ymlb);
4202 CHECK(output == ymlb);
4206 std::string another = ryml::emitrs_yaml<std::string>(treeb);
4210 another = ryml::emitrs_yaml<std::string>(treeb[3][2]);
4213 " vinho verde: Soalheiro" "\n"
4214 " vinho tinto: Redoma 2017" "\n"
4225 ryml::csubstr ymlb =
4230 "- champagne: Dom Perignon" "\n"
4231 " coffee: Arabica" "\n"
4233 " vinho verde: Soalheiro" "\n"
4234 " vinho tinto: Redoma 2017" "\n"
4236 " - Rochefort 10" "\n"
4238 " - Leffe Rituel" "\n"
4250 std::stringstream ss;
4258 std::stringstream ss;
4270 " \"champagne\": \"Dom Perignon\"," "\n"
4271 " \"coffee\": \"Arabica\"," "\n"
4273 " \"vinho verde\": \"Soalheiro\"," "\n"
4274 " \"vinho tinto\": \"Redoma 2017\"" "\n"
4277 " \"Rochefort 10\"," "\n"
4279 " \"Leffe Rituel\"" "\n"
4292 std::stringstream ss;
4297 " vinho verde: Soalheiro" "\n"
4298 " vinho tinto: Redoma 2017" "\n"
4304 std::stringstream ss;
4309 " \"vinho verde\": \"Soalheiro\"," "\n"
4310 " \"vinho tinto\": \"Redoma 2017\"" "\n"
4322 ryml::csubstr yml =
""
4327 "- champagne: Dom Perignon" "\n"
4328 " coffee: Arabica" "\n"
4330 " vinho verde: Soalheiro" "\n"
4331 " vinho tinto: Redoma 2017" "\n"
4333 " - Rochefort 10" "\n"
4335 " - Leffe Rituel" "\n"
4347 CHECK(len == yml.len);
4361 "- champagne: Dom Perignon" "\n"
4362 " coffee: Arabica" "\n"
4364 " vinho verde: Soalheiro" "\n"
4365 " vinho tinto: Redoma 2017" "\n"
4367 " - Rochefort 10" "\n"
4369 " - Leffe Rituel" "\n"
4371 " - many other" "\n"
4372 " - wonderful beers" "\n"
4378 CHECK(ryml::emitrs_yaml<std::string>(tree[3][
"beer"]) ==
""
4380 " - Rochefort 10" "\n"
4382 " - Leffe Rituel" "\n"
4384 " - many other" "\n"
4385 " - wonderful beers" "\n"
4387 CHECK(ryml::emitrs_yaml<std::string>(tree[3][
"beer"][0]) ==
"Rochefort 10");
4388 CHECK(ryml::emitrs_yaml<std::string>(tree[3][
"beer"][3]) ==
""
4391 "- wonderful beers" "\n"
4405 ryml::csubstr yaml =
""
4407 " block key: block val" "\n"
4409 " - block val 1" "\n"
4410 " - block val 2" "\n"
4412 "flow map, singleline: {flow key: flow val}" "\n"
4413 "flow seq, singleline: [flow val,flow val]" "\n"
4414 "flow map, multiline: {" "\n"
4415 " flow key: flow val" "\n"
4417 "flow seq, multiline: [" "\n"
4425 CHECK(tree[
"block map"].is_key_plain());
4426 CHECK(tree[
"block seq"].is_key_plain());
4427 CHECK(tree[
"flow map, singleline"].is_key_plain());
4428 CHECK(tree[
"flow seq, singleline"].is_key_plain());
4429 CHECK(tree[
"flow map, multiline"].is_key_plain());
4430 CHECK(tree[
"flow seq, multiline"].is_key_plain());
4431 CHECK(tree[
"block map"].is_block());
4432 CHECK(tree[
"block seq"].is_block());
4434 CHECK(tree[
"flow map, singleline"].is_flow_sl());
4435 CHECK(tree[
"flow seq, singleline"].is_flow_sl());
4436 CHECK(tree[
"flow map, multiline"].is_flow_ml());
4437 CHECK(tree[
"flow seq, multiline"].is_flow_ml());
4439 CHECK(tree[
"flow map, singleline"].is_flow());
4440 CHECK(tree[
"flow seq, singleline"].is_flow());
4441 CHECK(tree[
"flow map, multiline"].is_flow());
4442 CHECK(tree[
"flow seq, multiline"].is_flow());
4448 CHECK(tostr(tree) == yaml);
4459 " block key: block val\n"
4466 "'block map': {block key: block val}\n"
4472 CHECK(tostr(n) ==
""
4481 CHECK(tostr(n) ==
""
4482 "\"block seq\": [\n"
4491 CHECK(tostr(n) ==
"flow map, singleline: {flow key: flow val}\n");
4494 CHECK(tostr(n) ==
""
4495 "flow map, singleline:\n"
4503 CHECK(tostr(n) ==
""
4504 "flow map, multiline: {\n"
4505 " flow key: flow val\n"
4509 CHECK(tostr(n) ==
""
4510 "flow map, multiline:\n"
4511 " flow key: flow val\n"
4517 CHECK(tostr(n) ==
"flow seq, singleline: [flow val,flow val]\n");
4522 CHECK(tostr(n) ==
""
4524 " flow seq, singleline\n"
4533 CHECK(tostr(n) ==
""
4534 "flow seq, multiline: [\n"
4540 CHECK(tostr(n) ==
"flow seq, multiline: [flow val,flow val]\n");
4543 CHECK(tostr(tree) != yaml);
4544 CHECK(tostr(tree) ==
4545 "'block map': {block key: block val}" "\n"
4546 "\"block seq\": [" "\n"
4547 " block val 1," "\n"
4548 " block val 2," "\n"
4551 "flow map, singleline:" "\n"
4552 " flow key: |-" "\n"
4555 " flow seq, singleline" "\n"
4557 " - 'flow val'" "\n"
4558 " - \"flow val\"" "\n"
4559 "flow map, multiline:" "\n"
4560 " flow key: flow val" "\n"
4561 "flow seq, multiline: [flow val,flow val]" "\n"
4566 CHECK(tostr(tree) ==
4568 " block key: block val" "\n"
4570 " - block val 1" "\n"
4571 " - block val 2" "\n"
4573 "flow map, singleline:" "\n"
4574 " flow key: |-" "\n"
4577 " flow seq, singleline" "\n"
4579 " - 'flow val'" "\n"
4580 " - \"flow val\"" "\n"
4581 "flow map, multiline:" "\n"
4582 " flow key: flow val" "\n"
4583 "flow seq, multiline: [flow val,flow val]" "\n"
4592 CHECK(tostr(tree) ==
4594 " block key: block val" "\n"
4596 " - block val 1" "\n"
4597 " - block val 2" "\n"
4599 "flow map, singleline:" "\n"
4600 " flow key: flow val" "\n"
4601 "flow seq, singleline:" "\n"
4604 "flow map, multiline:" "\n"
4605 " flow key: flow val" "\n"
4606 "flow seq, multiline:" "\n"
4617 CHECK(tostr(tree) ==
4619 " block key: block val" "\n"
4621 " - block val 1" "\n"
4622 " - block val 2" "\n"
4624 "flow map, singleline:" "\n"
4625 " flow key: flow val" "\n"
4626 "flow seq, singleline:" "\n"
4629 "flow map, multiline:" "\n"
4630 " flow key: flow val" "\n"
4631 "flow seq, multiline:" "\n"
4656 CHECK(tostr(tree) ==
""
4658 " 'block key': \"block val\"" "\n"
4659 "'block seq': [\"block val 1\",\"block val 2\",\"quoted\"]" "\n"
4660 "'flow map, singleline':" "\n"
4661 " 'flow key': \"flow val\"" "\n"
4662 "'flow seq, singleline': [\"flow val\",\"flow val\"]" "\n"
4663 "'flow map, multiline':" "\n"
4664 " 'flow key': \"flow val\"" "\n"
4665 "'flow seq, multiline': [\"flow val\",\"flow val\"]" "\n"
4672 CHECK(tostr(tree) ==
""
4674 " 'block key': \"block val\"" "\n"
4675 "'block seq': [\"block val 1\",\"block val 2\",\"quoted\"]" "\n"
4676 "'flow map, singleline':" "\n"
4677 " 'flow key': \"flow val\"" "\n"
4678 "'flow seq, singleline':" "\n"
4679 " - \"flow val\"" "\n"
4680 " - \"flow val\"" "\n"
4681 "'flow map, multiline':" "\n"
4682 " 'flow key': \"flow val\"" "\n"
4683 "'flow seq, multiline': [\"flow val\",\"flow val\"]" "\n"
4700 return ryml::emitrs_yaml<std::string>(n, opts);
4702 ryml::csubstr yaml =
"{map: {seq: [0, 1, 2, 3, [40, 41]]}}";
4706 CHECK(tostr(tree, defaults) ==
"{map: {seq: [0,1,2,3,[40,41]]}}");
4713 CHECK(tostr(tree, defaults) ==
4731 CHECK(tostr(tree, noindent) ==
4750 CHECK(tostr(tree, noindent) ==
""
4766 CHECK(tostr(tree, noindent) ==
4788 ryml::csubstr yaml =
""
4804 ryml::csubstr yaml_not_indented =
""
4824 CHECK(tree[
"map"].is_flow_ml());
4826 CHECK(ryml::emitrs_yaml<std::string>(tree) == yaml);
4833 CHECK(tree[
"map"].is_flow_sl());
4835 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
4836 R
"({map: {seq: [0,1,2,3,[40,41]]}})");
4843 CHECK(tree[
"map"].is_flow_ml());
4844 CHECK(ryml::emitrs_yaml<std::string>(tree, noindent) == yaml_not_indented);
4857 ryml::csubstr json =
""
4859 " \"doe\": \"a deer, a female deer\"," "\n"
4860 " \"ray\": \"a drop of golden sun\"," "\n"
4861 " \"me\": \"a name, I call myself\"," "\n"
4862 " \"far\": \"a long long way to go\"" "\n"
4873 CHECK(ryml::emitrs_json<std::string>(tree) == json);
4874 CHECK(ryml::emitrs_json<std::string>(json_tree) == json);
4876 std::stringstream ss;
4878 CHECK(ss.str() == json);
4895 std::cout << ryml::emitrs_yaml<std::string>(json_tree);
4896 CHECK(ryml::emitrs_yaml<std::string>(json_tree) == json);
4901 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
""
4902 "\"doe\": \"a deer, a female deer\"" "\n"
4903 "\"ray\": \"a drop of golden sun\"" "\n"
4904 "\"me\": \"a name, I call myself\"" "\n"
4905 "\"far\": \"a long long way to go\"" "\n"
4912 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
""
4913 "doe: a deer, a female deer" "\n"
4914 "ray: a drop of golden sun" "\n"
4915 "me: a name, I call myself" "\n"
4916 "far: a long long way to go" "\n"
4924 CHECK(ryml::emitrs_yaml<std::string>(json_tree) ==
4925 "doe: 'a deer, a female deer'" "\n"
4926 "ray: 'a drop of golden sun'" "\n"
4927 "me: 'a name, I call myself'" "\n"
4928 "far: 'a long long way to go'" "\n"
4958 std::string unresolved =
""
4960 " name: Everyone has same name" "\n"
4967 "bill_to: &id001" "\n"
4969 " 123 Tornado Alley" "\n"
4971 " city: East Centerville" "\n"
4973 "ship_to: *id001" "\n"
4974 "&keyref key: &valref val" "\n"
4975 "*valref : *keyref" "\n"
4977 std::string resolved =
""
4979 " name: Everyone has same name" "\n"
4981 " name: Everyone has same name" "\n"
4984 " name: Everyone has same name" "\n"
4988 " 123 Tornado Alley" "\n"
4990 " city: East Centerville" "\n"
4994 " 123 Tornado Alley" "\n"
4996 " city: East Centerville" "\n"
5004 CHECK( ! tree[
"base"].has_key_anchor());
5005 CHECK( tree[
"base"].has_val_anchor());
5006 CHECK( tree[
"base"].val_anchor() ==
"base");
5007 CHECK( tree[
"key"].key_anchor() ==
"keyref");
5008 CHECK( tree[
"key"].val_anchor() ==
"valref");
5009 CHECK( tree[
"*valref"].is_key_ref());
5010 CHECK( tree[
"*valref"].is_val_ref());
5011 CHECK( tree[
"*valref"].key_ref() ==
"valref");
5012 CHECK( tree[
"*valref"].val_ref() ==
"keyref");
5019 CHECK( ! tree[
"base"].has_key_anchor());
5020 CHECK( ! tree[
"base"].has_val_anchor());
5021 CHECK( ! tree[
"base"].has_val_anchor());
5022 CHECK( ! tree[
"key"].has_key_anchor());
5023 CHECK( ! tree[
"key"].has_val_anchor());
5024 CHECK( ! tree[
"val"].is_key_ref());
5025 CHECK( ! tree[
"val"].is_val_ref());
5027 CHECK(tree[
"ship_to"][
"city"].val() ==
"East Centerville");
5028 CHECK(tree[
"ship_to"][
"state"].val() ==
"KS");
5046 t[
"nref"] =
"*vanchor";
5047 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5048 "&kanchor kanchor: 2" "\n"
5049 "vanchor: &vanchor 3" "\n"
5050 "kref: *kanchor" "\n"
5051 "vref: *vanchor" "\n"
5054 "nref: '*vanchor'" "\n"
5057 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5060 "kref: kanchor" "\n"
5063 "nref: '*vanchor'" "\n"
5070 "orig: &orig {foo: bar, baz: bat}" "\n"
5078 t[
"notref"][
"<<"] =
"*orig";
5079 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5080 "orig: &orig {foo: bar,baz: bat}" "\n"
5081 "copy: {<<: *orig}" "\n"
5082 "notcopy: {test: *orig,<<: *orig}" "\n"
5083 "notref: {<<: '*orig'}" "\n"
5086 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5087 "orig: {foo: bar,baz: bat}" "\n"
5088 "copy: {foo: bar,baz: bat}" "\n"
5089 "notcopy: {test: {foo: bar,baz: bat},foo: bar,baz: bat}" "\n"
5090 "notref: {<<: '*orig'}" "\n"
5097 "orig1: &orig1 {foo: bar}" "\n"
5098 "orig2: &orig2 {baz: bat}" "\n"
5099 "orig3: &orig3 {and: more}" "\n"
5107 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5108 "orig1: &orig1 {foo: bar}" "\n"
5109 "orig2: &orig2 {baz: bat}" "\n"
5110 "orig3: &orig3 {and: more}" "\n"
5111 "copy: {<<: [*orig1,*orig2,*orig3]}" "\n"
5114 CHECK(ryml::emitrs_yaml<std::string>(t) ==
""
5115 "orig1: {foo: bar}" "\n"
5116 "orig2: {baz: bat}" "\n"
5117 "orig3: {and: more}" "\n"
5118 "copy: {foo: bar,baz: bat,and: more}" "\n");
5127 const std::string yaml =
""
5136 "--- !!str a b" "\n"
5137 "--- !!str 'a: b'" "\n"
5154 CHECK(doc.is_doc());
5156 CHECK(root[0].has_val_tag());
5157 CHECK(root[0].val_tag() ==
"!!map");
5158 CHECK(root[1].val_tag() ==
"!map");
5159 CHECK(root[2].val_tag() ==
"!!seq");
5160 CHECK(root[3].val_tag() ==
"!!str");
5161 CHECK(root[4].val_tag() ==
"!!str");
5162 CHECK(root[5][
"a"].has_key_tag());
5163 CHECK(root[5][
"a"].key_tag() ==
"!!str");
5164 CHECK(root[6].val_tag() ==
"!!set");
5165 CHECK(root[7].val_tag() ==
"!!set");
5166 CHECK(root[8].val_tag() ==
"!!seq");
5167 CHECK(root[8][0].val_tag() ==
"!!int");
5168 CHECK(root[8][1].val_tag() ==
"!!str");
5217 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree) ==
""
5226 "--- !!str a b" "\n"
5227 "--- !!str 'a: b'" "\n"
5241 CHECK(ryml::emitrs_yaml<std::string>(normalized_tree_long) ==
""
5242 "--- !<tag:yaml.org,2002:map>" "\n"
5247 "--- !<tag:yaml.org,2002:seq>" "\n"
5250 "--- !<tag:yaml.org,2002:str> a b" "\n"
5251 "--- !<tag:yaml.org,2002:str> 'a: b'" "\n"
5253 "!<tag:yaml.org,2002:str> a: b" "\n"
5254 "--- !<tag:yaml.org,2002:set>" "\n"
5257 "--- !<tag:yaml.org,2002:set>" "\n"
5259 "--- !<tag:yaml.org,2002:seq>" "\n"
5260 "- !<tag:yaml.org,2002:int> 0" "\n"
5261 "- !<tag:yaml.org,2002:str> 1" "\n"
5270 const std::string yaml =
""
5271 "%TAG !m! !my-" "\n"
5272 "--- # Bulb here" "\n"
5273 "!m!light fluorescent" "\n"
5275 "%TAG !m! !meta-" "\n"
5276 "--- # Color here" "\n"
5277 "!m!light green" "\n"
5281 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
5282 "%TAG !m! !my-" "\n"
5283 "--- !m!light fluorescent" "\n"
5285 "%TAG !m! !meta-" "\n"
5286 "--- !m!light green" "\n"
5292 CHECK(ryml::emitrs_yaml<std::string>(tree) ==
""
5293 "%TAG !m! !my-" "\n"
5294 "--- !<!my-light> fluorescent" "\n"
5296 "%TAG !m! !meta-" "\n"
5297 "--- !<!meta-light> green" "\n"
5303 CHECK(ryml::emitrs_yaml<std::string>(resolved_tree) ==
""
5304 "%TAG !m! !my-" "\n"
5305 "--- !<!my-light> fluorescent" "\n"
5307 "%TAG !m! !meta-" "\n"
5308 "--- !<!meta-light> green" "\n"
5319 std::string yml =
""
5333 CHECK(ryml::emitrs_yaml<std::string>(tree) == yml);
5344 CHECK(doc.is_doc());
5363 CHECK(stream[0].is_doc());
5364 CHECK(stream[0].is_map());
5365 CHECK(stream[0][
"a"].val() ==
"0");
5366 CHECK(stream[0][
"b"].val() ==
"1");
5375 CHECK(stream[1].is_doc());
5376 CHECK(stream[1].is_map());
5377 CHECK(stream[1][
"c"].val() ==
"2");
5378 CHECK(stream[1][
"d"].val() ==
"3");
5387 CHECK(stream[2].is_doc());
5388 CHECK(stream[2].is_seq());
5389 CHECK(stream[2][0].val() ==
"4");
5390 CHECK(stream[2][1].val() ==
"5");
5391 CHECK(stream[2][2].val() ==
"6");
5392 CHECK(stream[2][3].val() ==
"7");
5411 const std::string expected_json[] = {
5437 CHECK(ryml::emitrs_json<std::string>(doc) == expected_json[count++]);
5449 CHECK(ryml::emitrs_json<std::string>(tree, doc_id) == expected_json[count++]);
5488 ryml::Tree tree = ryml::parse_in_arena(
"errorhandler.yml",
"[a: b\n}");
5499 auto cause_basic_error = []{
5501 ryml::csubstr tag_handle = {}, tag_prefix = {};
5508 #ifdef _RYML_WITH_EXCEPTIONS
5512 cause_basic_error();
5519 CHECK(!msg.empty());
5528 ryml::csubstr ymlsrc =
""
5533 ryml::csubstr ymlfile =
"file.yml";
5534 auto cause_parse_error = [&]{
5558 msg_ctx.append(s.str, s.len);
5560 CHECK(
ryml::to_csubstr(msg_ctx).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5562 "file.yml:3: col=4 (12B): err:" "\n"
5568 "err: see region:" "\n"
5603 CHECK(errh.
saved_msg_full ==
"file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
5616 #ifdef _RYML_WITH_EXCEPTIONS
5620 cause_parse_error();
5632 CHECK(msg ==
"invalid character: '['");
5637 auto dumpfn = [&full](ryml::csubstr s) { full.append(s.str, s.len); };
5641 CHECK(
ryml::to_csubstr(full).begins_with(
"file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
5643 "file.yml:3: col=4 (12B): err:" "\n"
5649 "err: see region:" "\n"
5662 cause_parse_error();
5669 CHECK(!msg.empty());
5680 ryml::csubstr ymlfile =
"file.yml";
5681 ryml::csubstr ymlsrc =
"float: 123.456";
5688 tree[
"float"] >> intval;
5717 tree[
"float"] >> intval;
5729 #ifdef _RYML_WITH_EXCEPTIONS
5741 tree[
"float"] >> intval;
5750 CHECK(!msg.empty());
5762 tree[
"float"] >> intval;
5769 CHECK(!msg.empty());
5794 ryml::csubstr ymlfile =
"file.yml";
5795 ryml::csubstr ymlsrc =
""
5799 "float: 123.456" "\n"
5803 auto cause_visit_error = [&]{
5805 tree[
"float"] >> intval;
5837 msg.append(s.str, s.len);
5838 }, ymlloc, ymlsrc,
"err", 3);
5840 "file.yml:3: col=0 (24B): err:" "\n"
5842 "err: float: 123.456" "\n"
5846 "err: see region:" "\n"
5848 "err: foo: bar" "\n"
5851 "err: float: 123.456" "\n"
5892 uintptr_t uptr = (uintptr_t)ptr;
5893 const uintptr_t align =
alignof(max_align_t);
5896 uintptr_t prev = uptr - (uptr % align);
5897 uintptr_t next = prev + align;
5898 uintptr_t corr = next - uptr;
5899 ptr = (
void*)(((
char*)ptr) + corr);
5903 "out of memory! requested=%zu+%zu available=%zu\n",
5929 static void s_free(
void *mem,
size_t len,
void *this_)
6001 parse_in_arena(&parser,
"", R
"([a, b, c, d, {foo: bar, money: pennys}])", &tree);
6044 std::cerr <<
"out of memory! requested=" <<
alloc_size <<
" vs " <<
memory_pool.size() <<
" available" << std::endl;
6095 ryml::csubstr yml1 =
"{a: b}";
6096 ryml::csubstr yml2 =
"{c: d, e: f, g: [h, i, 0, 1, 2, 3]}";
6130 CHECK(tree["doe"].val() ==
"a deer, a female deer");
6144 ryml::csubstr yaml =
""
6146 "aa: contents," "\n"
6147 "foo: [one, [two, three]]" "\n"
6191 loc = tree[
"foo"].
location(parser);
6196 loc = tree[
"foo"][0].
location(parser);
6201 loc = tree[
"foo"][1].
location(parser);
6205 loc = tree[
"foo"][1][0].
location(parser);
6209 loc = tree[
"foo"][1][1].
location(parser);
6231 "a new: buffer" "\n"
6232 "to: be parsed" "\n"
6233 "map with key:" "\n"
6234 " first: value" "\n"
6235 " second: value" "\n"
6236 "seq with key:" "\n"
6237 " - first value" "\n"
6238 " - second value" "\n"
6240 " - nested first value" "\n"
6241 " - nested second value" "\n"
6243 " nested first: value" "\n"
6244 " nested second: value" "\n"
6258 loc = tree2[
"a new"].
location(parser);
6263 loc = tree2[
"to"].
location(parser);
6269 loc = tree2[
"map with key"].
location(parser);
6273 loc = tree2[
"map with key"][
"first"].
location(parser);
6277 loc = tree2[
"map with key"][
"second"].
location(parser);
6282 loc = tree2[
"seq with key"].
location(parser);
6286 loc = tree2[
"seq with key"][0].
location(parser);
6290 loc = tree2[
"seq with key"][1].
location(parser);
6295 loc = tree2[
"seq with key"][2].
location(parser);
6299 loc = tree2[
"seq with key"][2][0].
location(parser);
6304 loc = tree2[
"seq with key"][3].
location(parser);
6308 loc = tree2[
"seq with key"][3][0].
location(parser);
6324 static int num_checks = 0;
6325 static int num_failed_checks = 0;
6326 static bool quiet_mode =
false;
6331 auto arg_matches = [](
const char *arg,
const char *shortform,
const char *longform) {
6332 return (0 == strcmp(arg, shortform) || 0 == strcmp(arg, longform));
6334 for(
int i = 1; i < argc; ++i)
6335 if(arg_matches(argv[i],
"-q",
"--quiet"))
6342 const char *msg = predicate ?
"OK! " :
"OK!";
6345 ++num_failed_checks;
6346 msg = predicate ?
"FAIL: " :
"FAIL";
6348 if(!result || !quiet_mode)
6350 std::cout << __FILE__ <<
':' << line <<
": " << msg << (predicate ? predicate :
"") << std::endl;
6358 std::cout <<
"Completed " << num_checks <<
" checks." << std::endl;
6359 if(num_failed_checks)
6360 std::cout <<
"ERROR: " << num_failed_checks <<
'/' << num_checks <<
" checks failed." << std::endl;
6362 std::cout <<
"SUCCESS!" << std::endl;
6363 return num_failed_checks;
6375 void errdump(ryml::csubstr s)
6378 fwrite(s.str, 1, s.len, stderr);
6384 fputc(
'\n', stderr);
6399 .set_free([](
void* mem,
size_t,
void *){
6435 #ifdef RYML_NO_DEFAULT_CALLBACKS
6444 #ifndef C4_EXCEPTIONS
6475 bool got_error =
false;
6476 #ifdef C4_EXCEPTIONS
6479 std::forward<Fn>(fn)();
6481 catch(std::exception
const&)
6488 std::forward<Fn>(fn)();
6501 [[noreturn]]
void stopexec(std::string
const& s)
6503 #ifdef C4_EXCEPTIONS
6504 throw std::runtime_error(s);
6628 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4996)
6629 C4_SUPPRESS_WARNING_CLANG_WITH_PUSH("-Wdeprecated-declarations")
6631 template<class CharContainer>
6634 std::FILE *fp = std::fopen(filename,
"rb");
6635 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6636 std::fseek(fp, 0, SEEK_END);
6637 long sz = std::ftell(fp);
6638 v->resize(
static_cast<typename CharContainer::size_type
>(sz));
6642 size_t ret = std::fread(&(*v)[0], 1, v->size(), fp);
6643 if(ret != (
size_t)sz) _RYML_ERR_BASIC(
"{}: failed to read: expect {}B, got {}B", filename, sz, ret);
6650 template<
class CharContainer>
6659 template<
class CharContainer>
6668 std::FILE *fp = std::fopen(filename, access);
6669 if(fp ==
nullptr) _RYML_ERR_BASIC(
"{}: could not open file", filename);
6670 std::fwrite(buf, 1, sz, fp);
6673 C4_SUPPRESS_WARNING_CLANG_POP
6674 C4_SUPPRESS_WARNING_MSVC_POP
6679 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.
ParserOptions const & options() const
Get the options used to build this parser object.
Callbacks const & callbacks() const
Get the current callbacks in the parser.
void reserve_locations(size_t num_source_lines)
Reserve a certain capacity for the array used to track node locations in the source buffer.
void clear()
clear the tree and zero every node
id_type first_child(id_type node) const
bool is_stream(id_type node) const
void set_val_ref(id_type node, csubstr ref)
id_type root_id() const
Get the id of the root node. The tree must not be empty.
NodeRef rootref()
Get the root as a NodeRef.
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as "!!str" -> "<tag:yaml.org,2002:str>", "!foo" -> "<!...
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
ensure the tree's internal string arena is at least the given capacity
bool is_map(id_type node) const
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
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.
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
id_type first_sibling(id_type node) const
substr copy_to_arena(csubstr s)
copy the given string to the tree's arena, growing the arena by the required size.
id_type num_children(id_type node) const
O(num_children)
csubstr arena() const
get the current arena
id_type child(id_type node, id_type pos) const
void set_key_anchor(id_type node, csubstr anchor)
Definitions of error utilities used by ryml.
left_< T > left(T val, size_t width, char padchar=' ')
tag type to mark an argument to be aligned left.
right_< T > right(T val, size_t width, char padchar=' ')
tag function to 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_ boolalpha(T const &val=false)
tag function to mark a variable to be written as an alphabetic boolean, ie as either true or false
void set_callbacks(Callbacks const &c)
set the global callbacks for the library; after a call to this function, these callbacks will be used...
Callbacks const & get_callbacks()
get the global callbacks
csubstr catrs_append(CharOwningContainer *cont, Args const &...args)
cat+resize+append: like c4::cat(), but receives a container, and appends to it instead of overwriting...
size_t cat(substr buf, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer.
void catrs(CharOwningContainer *cont, Args const &...args)
cat+resize: like c4::cat(), but receives a container, and resizes it as needed to contain the result.
substr cat_sub(substr buf, Args const &...args)
like c4::cat() but return a substr instead of a size
csubstr catseprs_append(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize+append: like c4::catsep(), but receives a container, and appends the arguments,...
void catseprs(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize: like c4::catsep(), but receives a container, and resizes it as needed to contain the r...
size_t catsep(substr buf, Sep const &sep, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer, using a separator between...
substr catsep_sub(substr buf, Args &&...args)
like c4::catsep() but return a substr instead of a size
@ FTOA_FLEX
print the real number in flexible format (like g)
@ FTOA_SCIENT
print the real number in scientific format (like e)
@ FTOA_FLOAT
print the real number in floating point format (like f)
@ FTOA_HEXA
print the real number in hexadecimal format (like a)
bool indent_flow_ml() const noexcept
substr emitrs_yaml(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit YAML to the given std::string/std::vector-like container, resizing it as needed...
size_t emit_yaml(Tree const &t, id_type id, EmitOptions const &opts, FILE *f)
(1) emit YAML to the given file, starting at the given node.
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const &errdata)
Given an error message and associated visit error data, format it fully as a visit error message.
void location_format_with_context(DumpFn &&dumpfn, Location const &location, csubstr source_buffer, csubstr call, size_t num_lines_before, size_t num_lines_after, size_t first_col_highlight, size_t last_col_highlight, size_t maxlen)
Generic formatting of a location, printing the source code buffer region around the location.
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const &errdata)
Given an error message and associated basic error data, format it fully as a basic error message.
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const &errdata)
Given an error message and associated parse error data, format it fully as a parse error message.
integral_< intptr_t > hex(std::nullptr_t)
format null as an hexadecimal value
integral_< intptr_t > bin(std::nullptr_t)
format null as a binary 0-1 value
integral_< intptr_t > oct(std::nullptr_t)
format null as an octal value
bool scalar_is_null(csubstr s) noexcept
YAML-sense query of nullity.
@ KEY_DQUO
mark key scalar as double quoted "
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
@ FLOW_ML
mark container with multi-line flow style (seqs as '[ val1, val2 ], maps as '{ key: val,...
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
@ VAL_SQUO
mark val scalar as single quoted '
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
@ VAL_DQUO
mark val scalar as double quoted "
@ KEY_SQUO
mark key scalar as single quoted '
@ VAL_LITERAL
mark val scalar as multiline, block literal |
@ KEY_FOLDED
mark key scalar as multiline, block folded >
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id)
(1) parse JSON into an existing tree node. The filename will be used in any error messages arising du...
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id)
(1) parse YAML into an existing tree node.
void sample_anchors_and_aliases()
demonstrates usage with anchors and alias references.
void sample_emit_to_file()
demonstrates how to emit to a FILE*
void sample_formatting()
ryml provides facilities for formatting/deformatting (imported from c4core into the ryml namespace).
void sample_quick_overview()
a brief tour over most features
void sample_style_flow_ml_indent()
[experimental] control the indentation of emitted FLOW_ML containers
void sample_per_tree_allocator()
void sample_lightning_overview()
a lightning tour over most features see sample_quick_overview
void sample_user_container_types()
shows how to serialize/deserialize container types.
void sample_empty_null_values()
Shows how to deal with empty/null values.
void sample_global_allocator()
demonstrates how to set the global allocator for ryml
void sample_base64()
demonstrates how to read and write base64-encoded blobs.
void sample_error_visit()
Visit errors happen when an error is triggered while reading from a node.
void sample_static_trees()
shows how to work around the static initialization order fiasco when using a static-duration ryml tre...
void sample_parse_file()
demonstrate how to load a YAML file from disk to parse with ryml.
void sample_style_flow_ml_filter()
[experimental] set the parser to pick FLOW_SL even if the container being parsed is FLOW_ML
void sample_json()
shows how to parse and emit JSON.
void sample_error_parse()
void sample_parse_in_arena()
demonstrate parsing of a read-only YAML source buffer
void sample_emit_nested_node()
just like parsing into a nested node, you can also emit from a nested node.
void sample_style()
[experimental] query/set/modify node style to control formatting of emitted YAML code.
void sample_location_tracking()
demonstrates how to obtain the (zero-based) location of a node from a recently parsed tree
void sample_parse_reuse_parser()
Demonstrates reuse of an existing parser.
void sample_iterate_trees()
shows how to programatically iterate through trees
void sample_create_trees()
shows how to programatically create trees
void sample_parse_reuse_tree_and_parser()
for ultimate speed when parsing multiple times, reuse both the tree and parser
void sample_emit_to_container()
demonstrates how to emit to a linear container of char
void sample_parse_in_place()
demonstrate in-place parsing of a mutable YAML source buffer.
void sample_fundamental_types()
ryml provides facilities for serializing and deserializing the C++ fundamental types,...
void sample_std_types()
demonstrates usage with the std implementations provided by ryml in the ryml_std.hpp header
void sample_float_precision()
control precision of serialized floats
void sample_anchors_and_aliases_create()
demonstrates how to use the API to programatically create anchors and aliases
void sample_user_scalar_types()
to add scalar types (ie leaf types converting to/from string), define the functions above for those t...
void sample_error_visit_location()
It is possible to obtain the YAML location from a visit error: when the tree is obtained from parsing...
void sample_error_basic()
void sample_tag_directives()
void sample_error_handler()
demonstrates how to set a custom error handler for ryml
void sample_emit_to_stream()
demonstrates how to emit to a stream-like structure
void sample_tree_arena()
demonstrates explicit and implicit interaction with the tree's string arena.
void sample_parse_reuse_tree()
demonstrate reuse/modification of tree when parsing
void sample_substr()
demonstrate usage of ryml::substr and ryml::csubstr
const_raw_wrapper raw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
const_raw_wrapper craw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
real_< T > real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT)
void write(ryml::NodeRef *n, my_seq_type< T > const &seq)
bool read(ryml::ConstNodeRef const &n, my_seq_type< T > *seq)
bool from_chars(ryml::csubstr buf, vec2< T > *v)
static void s_error_basic(ryml::csubstr msg, ryml::ErrorDataBasic const &errdata, void *this_)
trampoline function to call the object's method
bool report_check(int line, const char *predicate, bool result)
static void s_error_parse(ryml::csubstr msg, ryml::ErrorDataParse const &errdata, void *this_)
trampoline function to call the object's method
bool check_assertion_occurs(Fn &&fn)
checking that an assertion occurs while calling fn.
void on_error_visit(ryml::csubstr msg, ryml::ErrorDataVisit const &errdata)
this is where the callback implementation goes.
static std::string s_jmp_msg
void file_put_contents(const char *filename, CharContainer const &v, const char *access="wb")
save a buffer into a file
void ensure_callbacks()
set up default callbacks when ryml does not provide them (ie when RYML_NO_DEFAULT_CALLBACKS is define...
static void s_error_visit(ryml::csubstr msg, ryml::ErrorDataVisit const &errdata, void *this_)
trampoline function to call the object's method
void on_error_parse(ryml::csubstr msg, ryml::ErrorDataParse const &errdata)
this is where the callback implementation goes.
bool check_error_occurs(Fn &&fn)
checking that an error occurs while calling fn
ryml::Callbacks default_callbacks()
a bare-bones implementation of the callbacks
void check_disabled() const
test that this handler is currently not set
CharContainer file_get_contents(const char *filename)
load a file from disk and return a newly created CharContainer
#define CHECK(predicate)
a quick'n'dirty assertion to verify a predicate
ryml::Callbacks callbacks()
a helper to create the Callbacks object for the custom error handler
void on_error_basic(ryml::csubstr msg, ryml::ErrorDataBasic const &errdata)
this is where the callback implementation goes.
static std::jmp_buf s_jmp_env
void check_enabled() const
test that this handler is currently set
void handle_args(int argc, const char *argv[])
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, csubstr sep, Arg &a, Args &...more)
deserialize the arguments from the given buffer, using a separator.
integral_padded_< T > zpad(T val, size_t num_digits)
pad the argument with zeroes on the left, with decimal radix
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
@ npos
a null string position
int main(int, const char *[])
an example error handler, required for some of the quickstart examples.
ryml::Location saved_basic_loc
ryml::Callbacks original_callbacks
std::string saved_msg_full
ryml::id_type saved_visit_id
std::string saved_msg_short
ryml::Tree const * saved_visit_tree
ryml::Location saved_parse_loc
std::string saved_msg_full_with_context
void free(void *mem, size_t len)
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 & resolve_tags(bool enabled) noexcept
enable/disable resolution of YAML tags during parsing.
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.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
mark a tree or node to be emitted as yaml when using operator<<, with options.
auto first_child() RYML_NOEXCEPT -> Impl
Forward to Tree::first_child().
auto children() RYML_NOEXCEPT -> children_view
get an iterable view over children.
bool is_val() const RYML_NOEXCEPT
Forward to Tree::is_val().
bool is_root() const RYML_NOEXCEPT
Forward to Tree::is_root().
auto last_child() RYML_NOEXCEPT -> Impl
Forward to Tree::last_child().
bool is_stream() const RYML_NOEXCEPT
Forward to Tree::is_stream().
auto parent() RYML_NOEXCEPT -> Impl
Forward to Tree::parent().
bool has_child(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_child().
auto next_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::next_sibling().
auto last_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::last_sibling().
bool is_map() const RYML_NOEXCEPT
Forward to Tree::is_map().
id_type num_siblings() const RYML_NOEXCEPT
O(num_children).
bool has_key() const RYML_NOEXCEPT
Forward to Tree::has_key().
csubstr key() const RYML_NOEXCEPT
Forward to Tree::key().
auto first_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::first_sibling().
csubstr val() const RYML_NOEXCEPT
Forward to Tree::val().
bool is_doc() const RYML_NOEXCEPT
Forward to Tree::is_doc().
id_type num_children() const RYML_NOEXCEPT
O(num_children).
auto child(id_type pos) RYML_NOEXCEPT -> Impl
Forward to Tree::child().
bool is_block() const RYML_NOEXCEPT
Forward to Tree::is_block().
Location location(Parser const &parser) const
bool is_seq() const RYML_NOEXCEPT
Forward to Tree::is_seq().
bool has_val() const RYML_NOEXCEPT
Forward to Tree::has_val().
auto prev_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::prev_sibling().
example scalar type, serialized only
example scalar type, serialized only
example scalar type, serialized only
example user container type: map-like
std::map< K, V > map_member
example user container type: seq-like
std::vector< T > seq_member
example user container type with nested container members.
my_map_type< int, int > map
example scalar type, deserialized only
example scalar type, deserialized only
example scalar type, deserialized only
example scalar type, serialized and deserialized
example scalar type, serialized and deserialized
example scalar type, serialized and deserialized