rapidyaml  0.16.0
parseandemitYAML,anddoitfast
Using csubstr

Functions

void sample_substr ()
 about ryml's string views (from c4core) More...
 

Detailed Description

Function Documentation

void sample_substr ( )

about ryml's string views (from c4core)

demonstrate usage of ryml::substr and ryml::csubstr

These types are imported from the c4core library into the ryml namespace You may have noticed above the use of a csubstr class. This class is defined in another library, c4core, which is imported by ryml. This is a library I use with my projects consisting of multiplatform low-level utilities. One of these is c4::csubstr (the name comes from "constant substring") which is a non-owning read-only string view, with many methods that make it practical to use (I would certainly argue more practical than std::string). In fact, c4::csubstr and its writeable counterpart c4::substr are the workhorses of the ryml parsing and serialization code.

See also
Substring: read/write string views

Definition at line 1146 of file quickstart.cpp.

Referenced by main().

1147 {
1148  // substr is a mutable view: pointer and length to a string in memory.
1149  // csubstr is a const-substr (immutable).
1150 
1151  // construct from explicit args
1152  {
1153  const char foobar_str[] = "foobar";
1154  auto s = ryml::csubstr(foobar_str, strlen(foobar_str));
1155  CHECK(s == "foobar");
1156  CHECK(s.size() == 6);
1157  CHECK(s.data() == foobar_str);
1158  CHECK(s.size() == s.len);
1159  CHECK(s.data() == s.str);
1160  }
1161 
1162  // construct from a string array
1163  {
1164  const char foobar_str[] = "foobar";
1165  ryml::csubstr s = foobar_str;
1166  CHECK(s == "foobar");
1167  CHECK(s != "foobar0");
1168  CHECK(s.size() == 6); // does not include the terminating \0
1169  CHECK(s.data() == foobar_str);
1170  CHECK(s.size() == s.len);
1171  CHECK(s.data() == s.str);
1172  }
1173  // you can also declare directly in-place from an array:
1174  {
1175  ryml::csubstr s = "foobar";
1176  CHECK(s == "foobar");
1177  CHECK(s != "foobar0");
1178  CHECK(s.size() == 6);
1179  CHECK(s.size() == s.len);
1180  CHECK(s.data() == s.str);
1181  }
1182 
1183  // construct from a C-string:
1184  //
1185  // Since the input is only a pointer, the string length can only
1186  // be found with a call to strlen(). To make this cost evident, we
1187  // require calling to_csubstr():
1188  {
1189  const char *foobar_str = "foobar";
1190  ryml::csubstr s = ryml::to_csubstr(foobar_str);
1191  CHECK(s == "foobar");
1192  CHECK(s != "foobar0");
1193  CHECK(s.size() == 6);
1194  CHECK(s.size() == s.len);
1195  CHECK(s.data() == s.str);
1196  }
1197 
1198  // construct from a std::string: same approach as above.
1199  // requires inclusion of the <ryml/std/string.hpp> header
1200  // or of the umbrella header <ryml_std.hpp>.
1201  //
1202  // not including <string> in the default header is a deliberate
1203  // design choice to avoid including the heavy std:: allocation
1204  // machinery
1205  {
1206  std::string foobar_str = "foobar";
1207  ryml::csubstr s = ryml::to_csubstr(foobar_str); // defined in <ryml/std/string.hpp>
1208  CHECK(s == "foobar");
1209  CHECK(s != "foobar0");
1210  CHECK(s.size() == 6);
1211  CHECK(s.size() == s.len);
1212  CHECK(s.data() == s.str);
1213  }
1214 
1215  // convert substr -> csubstr
1216  {
1217  char buf[] = "foo";
1218  ryml::substr foo = buf;
1219  CHECK(foo.len == 3);
1220  CHECK(foo.data() == buf);
1221  ryml::csubstr cfoo = foo;
1222  CHECK(cfoo.data() == buf);
1223  }
1224  // cannot convert csubstr -> substr:
1225  {
1226  // ryml::substr foo2 = cfoo; // compile error: cannot write to csubstr
1227  }
1228 
1229  // construct from char[]/const char[]: mutable vs immutable memory
1230  {
1231  char const foobar_str_ro[] = "foobar"; // ro := read-only
1232  char foobar_str_rw[] = "foobar"; // rw := read-write
1233  static_assert(std::is_array<decltype(foobar_str_ro)>::value, "this is an array");
1234  static_assert(std::is_array<decltype(foobar_str_rw)>::value, "this is an array");
1235  // csubstr <- read-only memory
1236  {
1237  ryml::csubstr foobar = foobar_str_ro;
1238  CHECK(foobar.data() == foobar_str_ro);
1239  CHECK(foobar.size() == strlen(foobar_str_ro));
1240  CHECK(foobar == "foobar"); // AKA strcmp
1241  }
1242  // csubstr <- read-write memory: you can create an immutable csubstr from mutable memory
1243  {
1244  ryml::csubstr foobar = foobar_str_rw;
1245  CHECK(foobar.data() == foobar_str_rw);
1246  CHECK(foobar.size() == strlen(foobar_str_rw));
1247  CHECK(foobar == "foobar"); // AKA strcmp
1248  }
1249  // substr <- read-write memory.
1250  {
1251  ryml::substr foobar = foobar_str_rw;
1252  CHECK(foobar.data() == foobar_str_rw);
1253  CHECK(foobar.size() == strlen(foobar_str_rw));
1254  CHECK(foobar == "foobar"); // AKA strcmp
1255  }
1256  // substr <- ro is impossible.
1257  {
1258  //ryml::substr foobar = foobar_str_ro; // compile error!
1259  }
1260  }
1261 
1262  // construct from char*/const char*: mutable vs immutable memory.
1263  // use to_substr()/to_csubstr()
1264  {
1265  char const* foobar_str_ro = "foobar"; // ro := read-only
1266  char foobar_str_rw_[] = "foobar"; // rw := read-write
1267  char * foobar_str_rw = foobar_str_rw_; // rw := read-write
1268  static_assert(!std::is_array<decltype(foobar_str_ro)>::value, "this is a decayed pointer");
1269  static_assert(!std::is_array<decltype(foobar_str_rw)>::value, "this is a decayed pointer");
1270  // csubstr <- read-only memory
1271  {
1272  //ryml::csubstr foobar = foobar_str_ro; // compile error: length is not known
1273  ryml::csubstr foobar = ryml::to_csubstr(foobar_str_ro);
1274  CHECK(foobar.data() == foobar_str_ro);
1275  CHECK(foobar.size() == strlen(foobar_str_ro));
1276  CHECK(foobar == "foobar"); // AKA strcmp
1277  }
1278  // csubstr <- read-write memory: you can create an immutable csubstr from mutable memory
1279  {
1280  ryml::csubstr foobar = ryml::to_csubstr(foobar_str_rw);
1281  CHECK(foobar.data() == foobar_str_rw);
1282  CHECK(foobar.size() == strlen(foobar_str_rw));
1283  CHECK(foobar == "foobar"); // AKA strcmp
1284  }
1285  // substr <- read-write memory.
1286  {
1287  ryml::substr foobar = ryml::to_substr(foobar_str_rw);
1288  CHECK(foobar.data() == foobar_str_rw);
1289  CHECK(foobar.size() == strlen(foobar_str_rw));
1290  CHECK(foobar == "foobar"); // AKA strcmp
1291  }
1292  // substr <- read-only is impossible.
1293  {
1294  //ryml::substr foobar = ryml::to_substr(foobar_str_ro); // compile error!
1295  }
1296  }
1297 
1298  // substr is mutable, without changing the size:
1299  {
1300  char buf[] = "foobar";
1301  ryml::substr foobar = buf;
1302  CHECK(foobar == "foobar");
1303  foobar[0] = 'F'; CHECK(foobar == "Foobar");
1304  foobar.back() = 'R'; CHECK(foobar == "FoobaR");
1305  foobar.reverse(); CHECK(foobar == "RabooF");
1306  foobar.reverse(); CHECK(foobar == "FoobaR");
1307  foobar.reverse_sub(1, 4); CHECK(foobar == "FabooR");
1308  foobar.reverse_sub(1, 4); CHECK(foobar == "FoobaR");
1309  foobar.reverse_range(2, 5); CHECK(foobar == "FoaboR");
1310  foobar.reverse_range(2, 5); CHECK(foobar == "FoobaR");
1311  foobar.replace('o', '0'); CHECK(foobar == "F00baR");
1312  foobar.replace('a', '_'); CHECK(foobar == "F00b_R");
1313  foobar.replace("_0b", 'a'); CHECK(foobar == "FaaaaR");
1314  foobar.toupper(); CHECK(foobar == "FAAAAR");
1315  foobar.tolower(); CHECK(foobar == "faaaar");
1316  foobar.fill('.'); CHECK(foobar == "......");
1317  // see also:
1318  // - .erase()
1319  // - .replace_all()
1320  }
1321 
1322  // sub-views
1323  {
1324  ryml::csubstr s = "fooFOObarBAR";
1325  CHECK(s.len == 12u);
1326  // sub(): <- first,[num]
1327  CHECK(s.sub(0) == "fooFOObarBAR");
1328  CHECK(s.sub(0, 12) == "fooFOObarBAR");
1329  CHECK(s.sub(0, 3) == "foo" );
1330  CHECK(s.sub(3) == "FOObarBAR");
1331  CHECK(s.sub(3, 3) == "FOO" );
1332  CHECK(s.sub(6) == "barBAR");
1333  CHECK(s.sub(6, 3) == "bar" );
1334  CHECK(s.sub(9) == "BAR");
1335  CHECK(s.sub(9, 3) == "BAR");
1336  // first(): <- length
1337  CHECK(s.first(0) == "" );
1338  CHECK(s.first(1) == "f" );
1339  CHECK(s.first(2) != "f" );
1340  CHECK(s.first(2) == "fo" );
1341  CHECK(s.first(3) == "foo");
1342  // last(): <- length
1343  CHECK(s.last(0) == "");
1344  CHECK(s.last(1) == "R");
1345  CHECK(s.last(2) == "AR");
1346  CHECK(s.last(3) == "BAR");
1347  // range(): <- first, last
1348  CHECK(s.range(0, 12) == "fooFOObarBAR");
1349  CHECK(s.range(1, 12) == "ooFOObarBAR");
1350  CHECK(s.range(1, 11) == "ooFOObarBA" );
1351  CHECK(s.range(2, 10) == "oFOObarB" );
1352  CHECK(s.range(3, 9) == "FOObar" );
1353  // offs(): offset from beginning, end
1354  CHECK(s.offs(0, 0) == "fooFOObarBAR");
1355  CHECK(s.offs(1, 0) == "ooFOObarBAR");
1356  CHECK(s.offs(1, 1) == "ooFOObarBA" );
1357  CHECK(s.offs(2, 1) == "oFOObarBA" );
1358  CHECK(s.offs(2, 2) == "oFOObarB" );
1359  CHECK(s.offs(3, 3) == "FOObar" );
1360  // right_of(): <- pos, include_pos
1361  CHECK(s.right_of(0, true) == "fooFOObarBAR");
1362  CHECK(s.right_of(0, false) == "ooFOObarBAR");
1363  CHECK(s.right_of(1, true) == "ooFOObarBAR");
1364  CHECK(s.right_of(1, false) == "oFOObarBAR");
1365  CHECK(s.right_of(2, true) == "oFOObarBAR");
1366  CHECK(s.right_of(2, false) == "FOObarBAR");
1367  CHECK(s.right_of(3, true) == "FOObarBAR");
1368  CHECK(s.right_of(3, false) == "OObarBAR");
1369  // left_of() <- pos, include_pos
1370  CHECK(s.left_of(12, false) == "fooFOObarBAR");
1371  CHECK(s.left_of(11, true) == "fooFOObarBAR");
1372  CHECK(s.left_of(11, false) == "fooFOObarBA" );
1373  CHECK(s.left_of(10, true) == "fooFOObarBA" );
1374  CHECK(s.left_of(10, false) == "fooFOObarB" );
1375  CHECK(s.left_of( 9, true) == "fooFOObarB" );
1376  CHECK(s.left_of( 9, false) == "fooFOObar" );
1377  // left_of(),right_of() <- substr
1378  ryml::csubstr FOO = s.sub(3, 3);
1379  CHECK(s.is_super(FOO)); // required for the following
1380  CHECK(s.left_of(FOO) == "foo");
1381  CHECK(s.right_of(FOO) == "barBAR");
1382  }
1383 
1384  // printing a substr/csubstr using printf-like
1385  {
1386  ryml::csubstr s = "some substring";
1387  ryml::csubstr some = s.first(4);
1388  CHECK(some == "some");
1389  CHECK(s == "some substring");
1390  // To print a csubstr using printf(), use the %.*s format specifier:
1391  {
1392  char result[32] = {0};
1393  std::snprintf(result, sizeof(result), "%.*s", (int)some.len, some.str);
1394  printf("~~~%s~~~\n", result);
1395  CHECK(ryml::to_csubstr((const char*)result) == "some");
1396  CHECK(ryml::to_csubstr((const char*)result) == some);
1397  }
1398  // But NOTE: because this is a string view type, in general
1399  // the C-string is NOT zero terminated. So NEVER printf it
1400  // directly, or it will overflow past the end of the given
1401  // substr, with a potential unbounded access. For example,
1402  // this is really bad:
1403  {
1404  char result[32] = {0};
1405  std::snprintf(result, sizeof(result), "%s", some.str); // ERROR! do not print the c-string directly
1406  CHECK(ryml::to_csubstr((const char*)result) == "some substring");
1407  CHECK(ryml::to_csubstr((const char*)result) == s);
1408  }
1409  }
1410 
1411  // printing a substr/csubstr using ostreams
1412  {
1413  ryml::csubstr s = "some substring";
1414  ryml::csubstr some = s.first(4);
1415  CHECK(some == "some");
1416  CHECK(s == "some substring");
1417  // simple! just use plain operator<<
1418  {
1419  std::stringstream ss;
1420  ss << s;
1421  CHECK(ss.str() == "some substring"); // as expected
1422  CHECK(ss.str() == s); // as expected
1423  }
1424  // But NOTE: because this is a string view type, in general
1425  // the C-string is NOT zero terminated. So NEVER print it
1426  // directly, or it will overflow past the end of the given
1427  // substr, with a potential unbounded access. For example,
1428  // this is bad:
1429  {
1430  std::stringstream ss;
1431  ss << some.str; // ERROR! do not print the c-string directly
1432  CHECK(ss.str() == "some substring"); // NOT "some"
1433  CHECK(ss.str() == s); // NOT some
1434  }
1435  // this is also bad (the same)
1436  {
1437  std::stringstream ss;
1438  ss << some.data(); // ERROR! do not print the c-string directly
1439  CHECK(ss.str() == "some substring"); // NOT "some"
1440  CHECK(ss.str() == s); // NOT some
1441  }
1442  // this is ok:
1443  {
1444  std::stringstream ss;
1445  ss << some;
1446  CHECK(ss.str() == "some"); // ok
1447  CHECK(ss.str() == some); // ok
1448  }
1449  }
1450 
1451  // is_sub(),is_super()
1452  {
1453  ryml::csubstr foobar = "foobar";
1454  ryml::csubstr foo = foobar.first(3);
1455  CHECK(foo.is_sub(foobar));
1456  CHECK(foo.is_sub(foo));
1457  CHECK(!foo.is_super(foobar));
1458  CHECK(!foobar.is_sub(foo));
1459  // identity comparison is true:
1460  CHECK(foo.is_super(foo));
1461  CHECK(foo.is_sub(foo));
1462  CHECK(foobar.is_sub(foobar));
1463  CHECK(foobar.is_super(foobar));
1464  }
1465 
1466  // overlaps()
1467  {
1468  ryml::csubstr foobar = "foobar";
1469  ryml::csubstr foo = foobar.first(3);
1470  ryml::csubstr oba = foobar.offs(2, 1);
1471  ryml::csubstr abc = "abc";
1472  CHECK(foobar.overlaps(foo));
1473  CHECK(foobar.overlaps(oba));
1474  CHECK(foo.overlaps(foobar));
1475  CHECK(foo.overlaps(oba));
1476  CHECK(!foo.overlaps(abc));
1477  CHECK(!abc.overlaps(foo));
1478  }
1479 
1480  // triml(): trim characters from the left
1481  // trimr(): trim characters from the right
1482  // trim(): trim characters from left AND right
1483  {
1484  CHECK(ryml::csubstr(" \t\n\rcontents without whitespace\t \n\r").trim("\t \n\r") == "contents without whitespace");
1485  ryml::csubstr aaabbb = "aaabbb";
1486  ryml::csubstr aaa___bbb = "aaa___bbb";
1487  // trim a character:
1488  CHECK(aaabbb.triml('a') == aaabbb.last(3)); // bbb
1489  CHECK(aaabbb.trimr('a') == aaabbb);
1490  CHECK(aaabbb.trim ('a') == aaabbb.last(3)); // bbb
1491  CHECK(aaabbb.triml('b') == aaabbb);
1492  CHECK(aaabbb.trimr('b') == aaabbb.first(3)); // aaa
1493  CHECK(aaabbb.trim ('b') == aaabbb.first(3)); // aaa
1494  CHECK(aaabbb.triml('c') == aaabbb);
1495  CHECK(aaabbb.trimr('c') == aaabbb);
1496  CHECK(aaabbb.trim ('c') == aaabbb);
1497  CHECK(aaa___bbb.triml('a') == aaa___bbb.last(6)); // ___bbb
1498  CHECK(aaa___bbb.trimr('a') == aaa___bbb);
1499  CHECK(aaa___bbb.trim ('a') == aaa___bbb.last(6)); // ___bbb
1500  CHECK(aaa___bbb.triml('b') == aaa___bbb);
1501  CHECK(aaa___bbb.trimr('b') == aaa___bbb.first(6)); // aaa___
1502  CHECK(aaa___bbb.trim ('b') == aaa___bbb.first(6)); // aaa___
1503  CHECK(aaa___bbb.triml('c') == aaa___bbb);
1504  CHECK(aaa___bbb.trimr('c') == aaa___bbb);
1505  CHECK(aaa___bbb.trim ('c') == aaa___bbb);
1506  // trim ANY of the characters:
1507  CHECK(aaabbb.triml("ab") == "");
1508  CHECK(aaabbb.trimr("ab") == "");
1509  CHECK(aaabbb.trim ("ab") == "");
1510  CHECK(aaabbb.triml("ba") == "");
1511  CHECK(aaabbb.trimr("ba") == "");
1512  CHECK(aaabbb.trim ("ba") == "");
1513  CHECK(aaabbb.triml("cd") == aaabbb);
1514  CHECK(aaabbb.trimr("cd") == aaabbb);
1515  CHECK(aaabbb.trim ("cd") == aaabbb);
1516  CHECK(aaa___bbb.triml("ab") == aaa___bbb.last(6)); // ___bbb
1517  CHECK(aaa___bbb.triml("ba") == aaa___bbb.last(6)); // ___bbb
1518  CHECK(aaa___bbb.triml("cd") == aaa___bbb);
1519  CHECK(aaa___bbb.trimr("ab") == aaa___bbb.first(6)); // aaa___
1520  CHECK(aaa___bbb.trimr("ba") == aaa___bbb.first(6)); // aaa___
1521  CHECK(aaa___bbb.trimr("cd") == aaa___bbb);
1522  CHECK(aaa___bbb.trim ("ab") == aaa___bbb.range(3, 6)); // ___
1523  CHECK(aaa___bbb.trim ("ba") == aaa___bbb.range(3, 6)); // ___
1524  CHECK(aaa___bbb.trim ("cd") == aaa___bbb);
1525  }
1526 
1527  // unquoted():
1528  {
1529  CHECK(ryml::csubstr( "'this is is single quoted'" ).unquoted() == "this is is single quoted");
1530  CHECK(ryml::csubstr("\"this is is double quoted\"").unquoted() == "this is is double quoted");
1531  }
1532 
1533  // stripl(): remove pattern from the left
1534  // stripr(): remove pattern from the right
1535  {
1536  ryml::csubstr abc___cba = "abc___cba";
1537  ryml::csubstr abc___abc = "abc___abc";
1538  CHECK(abc___cba.stripl("abc") == abc___cba.last(6)); // ___cba
1539  CHECK(abc___cba.stripr("abc") == abc___cba);
1540  CHECK(abc___cba.stripl("ab") == abc___cba.last(7)); // c___cba
1541  CHECK(abc___cba.stripr("ab") == abc___cba);
1542  CHECK(abc___cba.stripl("a") == abc___cba.last(8)); // bc___cba, same as triml('a')
1543  CHECK(abc___cba.stripr("a") == abc___cba.first(8));
1544  CHECK(abc___abc.stripl("abc") == abc___abc.last(6)); // ___abc
1545  CHECK(abc___abc.stripr("abc") == abc___abc.first(6)); // abc___
1546  CHECK(abc___abc.stripl("ab") == abc___abc.last(7)); // c___cba
1547  CHECK(abc___abc.stripr("ab") == abc___abc);
1548  CHECK(abc___abc.stripl("a") == abc___abc.last(8)); // bc___cba, same as triml('a')
1549  CHECK(abc___abc.stripr("a") == abc___abc);
1550  }
1551 
1552  // begins_with()/ends_with()
1553  // begins_with_any()/ends_with_any()
1554  {
1555  ryml::csubstr s = "foobar123";
1556  // char overloads
1557  CHECK(s.begins_with('f'));
1558  CHECK(s.ends_with('3'));
1559  CHECK(!s.ends_with('2'));
1560  CHECK(!s.ends_with('o'));
1561  // char[] overloads
1562  CHECK(s.begins_with("foobar"));
1563  CHECK(s.begins_with("foo"));
1564  CHECK(s.begins_with_any("foo"));
1565  CHECK(!s.begins_with("oof"));
1566  CHECK(s.begins_with_any("oof"));
1567  CHECK(s.ends_with("23"));
1568  CHECK(s.ends_with("123"));
1569  CHECK(s.ends_with_any("123"));
1570  CHECK(!s.ends_with("321"));
1571  CHECK(s.ends_with_any("231"));
1572  }
1573 
1574  // select()
1575  {
1576  ryml::csubstr s = "0123456789";
1577  CHECK(s.select('0') == s.sub(0, 1));
1578  CHECK(s.select('1') == s.sub(1, 1));
1579  CHECK(s.select('2') == s.sub(2, 1));
1580  CHECK(s.select('8') == s.sub(8, 1));
1581  CHECK(s.select('9') == s.sub(9, 1));
1582  CHECK(s.select("0123") == s.range(0, 4));
1583  CHECK(s.select("012" ) == s.range(0, 3));
1584  CHECK(s.select("01" ) == s.range(0, 2));
1585  CHECK(s.select("0" ) == s.range(0, 1));
1586  CHECK(s.select( "123") == s.range(1, 4));
1587  CHECK(s.select( "23") == s.range(2, 4));
1588  CHECK(s.select( "3") == s.range(3, 4));
1589  }
1590 
1591  // find()
1592  {
1593  ryml::csubstr s012345 = "012345";
1594  // find single characters:
1595  CHECK(s012345.find('a') == ryml::npos);
1596  CHECK(s012345.find('0' ) == 0u);
1597  CHECK(s012345.find('0', 1u) == ryml::npos);
1598  CHECK(s012345.find('1' ) == 1u);
1599  CHECK(s012345.find('1', 2u) == ryml::npos);
1600  CHECK(s012345.find('2' ) == 2u);
1601  CHECK(s012345.find('2', 3u) == ryml::npos);
1602  CHECK(s012345.find('3' ) == 3u);
1603  CHECK(s012345.find('3', 4u) == ryml::npos);
1604  // find patterns
1605  CHECK(s012345.find("ab" ) == ryml::npos);
1606  CHECK(s012345.find("01" ) == 0u);
1607  CHECK(s012345.find("01", 1u) == ryml::npos);
1608  CHECK(s012345.find("12" ) == 1u);
1609  CHECK(s012345.find("12", 2u) == ryml::npos);
1610  CHECK(s012345.find("23" ) == 2u);
1611  CHECK(s012345.find("23", 3u) == ryml::npos);
1612  }
1613 
1614  // count(): count the number of occurrences of a character
1615  {
1616  ryml::csubstr buf = "00110022003300440055";
1617  CHECK(buf.count('1' ) == 2u);
1618  CHECK(buf.count('1', 0u) == 2u);
1619  CHECK(buf.count('1', 1u) == 2u);
1620  CHECK(buf.count('1', 2u) == 2u);
1621  CHECK(buf.count('1', 3u) == 1u);
1622  CHECK(buf.count('1', 4u) == 0u);
1623  CHECK(buf.count('1', 5u) == 0u);
1624  CHECK(buf.count('0' ) == 10u);
1625  CHECK(buf.count('0', 0u) == 10u);
1626  CHECK(buf.count('0', 1u) == 9u);
1627  CHECK(buf.count('0', 2u) == 8u);
1628  CHECK(buf.count('0', 3u) == 8u);
1629  CHECK(buf.count('0', 4u) == 8u);
1630  CHECK(buf.count('0', 5u) == 7u);
1631  CHECK(buf.count('0', 6u) == 6u);
1632  CHECK(buf.count('0', 7u) == 6u);
1633  CHECK(buf.count('0', 8u) == 6u);
1634  CHECK(buf.count('0', 9u) == 5u);
1635  CHECK(buf.count('0', 10u) == 4u);
1636  CHECK(buf.count('0', 11u) == 4u);
1637  CHECK(buf.count('0', 12u) == 4u);
1638  CHECK(buf.count('0', 13u) == 3u);
1639  CHECK(buf.count('0', 14u) == 2u);
1640  CHECK(buf.count('0', 15u) == 2u);
1641  CHECK(buf.count('0', 16u) == 2u);
1642  CHECK(buf.count('0', 17u) == 1u);
1643  CHECK(buf.count('0', 18u) == 0u);
1644  CHECK(buf.count('0', 19u) == 0u);
1645  CHECK(buf.count('0', 20u) == 0u);
1646  }
1647 
1648  // first_of(),last_of()
1649  {
1650  ryml::csubstr s012345 = "012345";
1651  CHECK(s012345.first_of('a') == ryml::npos);
1652  CHECK(s012345.first_of("ab") == ryml::npos);
1653  CHECK(s012345.first_of('0') == 0u);
1654  CHECK(s012345.first_of("0") == 0u);
1655  CHECK(s012345.first_of("01") == 0u);
1656  CHECK(s012345.first_of("10") == 0u);
1657  CHECK(s012345.first_of("012") == 0u);
1658  CHECK(s012345.first_of("210") == 0u);
1659  CHECK(s012345.first_of("0123") == 0u);
1660  CHECK(s012345.first_of("3210") == 0u);
1661  CHECK(s012345.first_of("01234") == 0u);
1662  CHECK(s012345.first_of("43210") == 0u);
1663  CHECK(s012345.first_of("012345") == 0u);
1664  CHECK(s012345.first_of("543210") == 0u);
1665  CHECK(s012345.first_of('5') == 5u);
1666  CHECK(s012345.first_of("5") == 5u);
1667  CHECK(s012345.first_of("45") == 4u);
1668  CHECK(s012345.first_of("54") == 4u);
1669  CHECK(s012345.first_of("345") == 3u);
1670  CHECK(s012345.first_of("543") == 3u);
1671  CHECK(s012345.first_of("2345") == 2u);
1672  CHECK(s012345.first_of("5432") == 2u);
1673  CHECK(s012345.first_of("12345") == 1u);
1674  CHECK(s012345.first_of("54321") == 1u);
1675  CHECK(s012345.first_of("012345") == 0u);
1676  CHECK(s012345.first_of("543210") == 0u);
1677  CHECK(s012345.first_of('0', 6u) == ryml::npos);
1678  CHECK(s012345.first_of('5', 6u) == ryml::npos);
1679  CHECK(s012345.first_of("012345", 6u) == ryml::npos);
1680  //
1681  CHECK(s012345.last_of('a') == ryml::npos);
1682  CHECK(s012345.last_of("ab") == ryml::npos);
1683  CHECK(s012345.last_of('0') == 0u);
1684  CHECK(s012345.last_of("0") == 0u);
1685  CHECK(s012345.last_of("01") == 1u);
1686  CHECK(s012345.last_of("10") == 1u);
1687  CHECK(s012345.last_of("012") == 2u);
1688  CHECK(s012345.last_of("210") == 2u);
1689  CHECK(s012345.last_of("0123") == 3u);
1690  CHECK(s012345.last_of("3210") == 3u);
1691  CHECK(s012345.last_of("01234") == 4u);
1692  CHECK(s012345.last_of("43210") == 4u);
1693  CHECK(s012345.last_of("012345") == 5u);
1694  CHECK(s012345.last_of("543210") == 5u);
1695  CHECK(s012345.last_of('5') == 5u);
1696  CHECK(s012345.last_of("5") == 5u);
1697  CHECK(s012345.last_of("45") == 5u);
1698  CHECK(s012345.last_of("54") == 5u);
1699  CHECK(s012345.last_of("345") == 5u);
1700  CHECK(s012345.last_of("543") == 5u);
1701  CHECK(s012345.last_of("2345") == 5u);
1702  CHECK(s012345.last_of("5432") == 5u);
1703  CHECK(s012345.last_of("12345") == 5u);
1704  CHECK(s012345.last_of("54321") == 5u);
1705  CHECK(s012345.last_of("012345") == 5u);
1706  CHECK(s012345.last_of("543210") == 5u);
1707  CHECK(s012345.last_of('0', 6u) == 0u);
1708  CHECK(s012345.last_of('5', 6u) == 5u);
1709  CHECK(s012345.last_of("012345", 6u) == 5u);
1710  }
1711 
1712  // first_not_of(), last_not_of()
1713  {
1714  ryml::csubstr s012345 = "012345";
1715  CHECK(s012345.first_not_of('a') == 0u);
1716  CHECK(s012345.first_not_of("ab") == 0u);
1717  CHECK(s012345.first_not_of('0') == 1u);
1718  CHECK(s012345.first_not_of("0") == 1u);
1719  CHECK(s012345.first_not_of("01") == 2u);
1720  CHECK(s012345.first_not_of("10") == 2u);
1721  CHECK(s012345.first_not_of("012") == 3u);
1722  CHECK(s012345.first_not_of("210") == 3u);
1723  CHECK(s012345.first_not_of("0123") == 4u);
1724  CHECK(s012345.first_not_of("3210") == 4u);
1725  CHECK(s012345.first_not_of("01234") == 5u);
1726  CHECK(s012345.first_not_of("43210") == 5u);
1727  CHECK(s012345.first_not_of("012345") == ryml::npos);
1728  CHECK(s012345.first_not_of("543210") == ryml::npos);
1729  CHECK(s012345.first_not_of('5') == 0u);
1730  CHECK(s012345.first_not_of("5") == 0u);
1731  CHECK(s012345.first_not_of("45") == 0u);
1732  CHECK(s012345.first_not_of("54") == 0u);
1733  CHECK(s012345.first_not_of("345") == 0u);
1734  CHECK(s012345.first_not_of("543") == 0u);
1735  CHECK(s012345.first_not_of("2345") == 0u);
1736  CHECK(s012345.first_not_of("5432") == 0u);
1737  CHECK(s012345.first_not_of("12345") == 0u);
1738  CHECK(s012345.first_not_of("54321") == 0u);
1739  CHECK(s012345.first_not_of("012345") == ryml::npos);
1740  CHECK(s012345.first_not_of("543210") == ryml::npos);
1741  CHECK(s012345.last_not_of('a') == 5u);
1742  CHECK(s012345.last_not_of("ab") == 5u);
1743  CHECK(s012345.last_not_of('5') == 4u);
1744  CHECK(s012345.last_not_of("5") == 4u);
1745  CHECK(s012345.last_not_of("45") == 3u);
1746  CHECK(s012345.last_not_of("54") == 3u);
1747  CHECK(s012345.last_not_of("345") == 2u);
1748  CHECK(s012345.last_not_of("543") == 2u);
1749  CHECK(s012345.last_not_of("2345") == 1u);
1750  CHECK(s012345.last_not_of("5432") == 1u);
1751  CHECK(s012345.last_not_of("12345") == 0u);
1752  CHECK(s012345.last_not_of("54321") == 0u);
1753  CHECK(s012345.last_not_of("012345") == ryml::npos);
1754  CHECK(s012345.last_not_of("543210") == ryml::npos);
1755  CHECK(s012345.last_not_of('0') == 5u);
1756  CHECK(s012345.last_not_of("0") == 5u);
1757  CHECK(s012345.last_not_of("01") == 5u);
1758  CHECK(s012345.last_not_of("10") == 5u);
1759  CHECK(s012345.last_not_of("012") == 5u);
1760  CHECK(s012345.last_not_of("210") == 5u);
1761  CHECK(s012345.last_not_of("0123") == 5u);
1762  CHECK(s012345.last_not_of("3210") == 5u);
1763  CHECK(s012345.last_not_of("01234") == 5u);
1764  CHECK(s012345.last_not_of("43210") == 5u);
1765  CHECK(s012345.last_not_of("012345") == ryml::npos);
1766  CHECK(s012345.last_not_of("543210") == ryml::npos);
1767  }
1768 
1769  // first_non_empty_span()
1770  {
1771  CHECK(ryml::csubstr("foo bar").first_non_empty_span() == "foo");
1772  CHECK(ryml::csubstr(" foo bar").first_non_empty_span() == "foo");
1773  CHECK(ryml::csubstr("\n \r \t foo bar").first_non_empty_span() == "foo");
1774  CHECK(ryml::csubstr("\n \r \t foo\n\r\t bar").first_non_empty_span() == "foo");
1775  CHECK(ryml::csubstr("\n \r \t foo\n\r\t bar").first_non_empty_span() == "foo");
1776  CHECK(ryml::csubstr(",\n \r \t foo\n\r\t bar").first_non_empty_span() == ",");
1777  }
1778  // first_uint_span()
1779  {
1780  CHECK(ryml::csubstr("1234 asdkjh").first_uint_span() == "1234");
1781  CHECK(ryml::csubstr("1234\rasdkjh").first_uint_span() == "1234");
1782  CHECK(ryml::csubstr("1234\tasdkjh").first_uint_span() == "1234");
1783  CHECK(ryml::csubstr("1234\nasdkjh").first_uint_span() == "1234");
1784  CHECK(ryml::csubstr("1234]asdkjh").first_uint_span() == "1234");
1785  CHECK(ryml::csubstr("1234)asdkjh").first_uint_span() == "1234");
1786  CHECK(ryml::csubstr("1234gasdkjh").first_uint_span() == "");
1787  }
1788  // first_int_span()
1789  {
1790  CHECK(ryml::csubstr("-1234 asdkjh").first_int_span() == "-1234");
1791  CHECK(ryml::csubstr("-1234\rasdkjh").first_int_span() == "-1234");
1792  CHECK(ryml::csubstr("-1234\tasdkjh").first_int_span() == "-1234");
1793  CHECK(ryml::csubstr("-1234\nasdkjh").first_int_span() == "-1234");
1794  CHECK(ryml::csubstr("-1234]asdkjh").first_int_span() == "-1234");
1795  CHECK(ryml::csubstr("-1234)asdkjh").first_int_span() == "-1234");
1796  CHECK(ryml::csubstr("-1234gasdkjh").first_int_span() == "");
1797  }
1798  // first_real_span()
1799  {
1800  CHECK(ryml::csubstr("-1234 asdkjh").first_real_span() == "-1234");
1801  CHECK(ryml::csubstr("-1234\rasdkjh").first_real_span() == "-1234");
1802  CHECK(ryml::csubstr("-1234\tasdkjh").first_real_span() == "-1234");
1803  CHECK(ryml::csubstr("-1234\nasdkjh").first_real_span() == "-1234");
1804  CHECK(ryml::csubstr("-1234]asdkjh").first_real_span() == "-1234");
1805  CHECK(ryml::csubstr("-1234)asdkjh").first_real_span() == "-1234");
1806  CHECK(ryml::csubstr("-1234gasdkjh").first_real_span() == "");
1807  CHECK(ryml::csubstr("1.234 asdkjh").first_real_span() == "1.234");
1808  CHECK(ryml::csubstr("1.234e+5 asdkjh").first_real_span() == "1.234e+5");
1809  CHECK(ryml::csubstr("1.234e-5 asdkjh").first_real_span() == "1.234e-5");
1810  CHECK(ryml::csubstr("1.234 asdkjh").first_real_span() == "1.234");
1811  CHECK(ryml::csubstr("1.234e+5 asdkjh").first_real_span() == "1.234e+5");
1812  CHECK(ryml::csubstr("1.234e-5 asdkjh").first_real_span() == "1.234e-5");
1813  CHECK(ryml::csubstr("-1.234 asdkjh").first_real_span() == "-1.234");
1814  CHECK(ryml::csubstr("-1.234e+5 asdkjh").first_real_span() == "-1.234e+5");
1815  CHECK(ryml::csubstr("-1.234e-5 asdkjh").first_real_span() == "-1.234e-5");
1816  // hexadecimal real numbers
1817  CHECK(ryml::csubstr("0x1.e8480p+19 asdkjh").first_real_span() == "0x1.e8480p+19");
1818  CHECK(ryml::csubstr("0x1.e8480p-19 asdkjh").first_real_span() == "0x1.e8480p-19");
1819  CHECK(ryml::csubstr("-0x1.e8480p+19 asdkjh").first_real_span() == "-0x1.e8480p+19");
1820  CHECK(ryml::csubstr("-0x1.e8480p-19 asdkjh").first_real_span() == "-0x1.e8480p-19");
1821  CHECK(ryml::csubstr("+0x1.e8480p+19 asdkjh").first_real_span() == "+0x1.e8480p+19");
1822  CHECK(ryml::csubstr("+0x1.e8480p-19 asdkjh").first_real_span() == "+0x1.e8480p-19");
1823  // binary real numbers
1824  CHECK(ryml::csubstr("0b101.011p+19 asdkjh").first_real_span() == "0b101.011p+19");
1825  CHECK(ryml::csubstr("0b101.011p-19 asdkjh").first_real_span() == "0b101.011p-19");
1826  CHECK(ryml::csubstr("-0b101.011p+19 asdkjh").first_real_span() == "-0b101.011p+19");
1827  CHECK(ryml::csubstr("-0b101.011p-19 asdkjh").first_real_span() == "-0b101.011p-19");
1828  CHECK(ryml::csubstr("+0b101.011p+19 asdkjh").first_real_span() == "+0b101.011p+19");
1829  CHECK(ryml::csubstr("+0b101.011p-19 asdkjh").first_real_span() == "+0b101.011p-19");
1830  // octal real numbers
1831  CHECK(ryml::csubstr("0o173.045p+19 asdkjh").first_real_span() == "0o173.045p+19");
1832  CHECK(ryml::csubstr("0o173.045p-19 asdkjh").first_real_span() == "0o173.045p-19");
1833  CHECK(ryml::csubstr("-0o173.045p+19 asdkjh").first_real_span() == "-0o173.045p+19");
1834  CHECK(ryml::csubstr("-0o173.045p-19 asdkjh").first_real_span() == "-0o173.045p-19");
1835  CHECK(ryml::csubstr("+0o173.045p+19 asdkjh").first_real_span() == "+0o173.045p+19");
1836  CHECK(ryml::csubstr("+0o173.045p-19 asdkjh").first_real_span() == "+0o173.045p-19");
1837  }
1838  // see also is_number()
1839 
1840  // basename(), dirname(), extshort(), extlong()
1841  {
1842  CHECK(ryml::csubstr("/path/to/file.tar.gz").basename() == "file.tar.gz");
1843  CHECK(ryml::csubstr("/path/to/file.tar.gz").dirname() == "/path/to/");
1844  CHECK(ryml::csubstr("C:\\path\\to\\file.tar.gz").basename('\\') == "file.tar.gz");
1845  CHECK(ryml::csubstr("C:\\path\\to\\file.tar.gz").dirname('\\') == "C:\\path\\to\\");
1846  CHECK(ryml::csubstr("/path/to/file.tar.gz").extshort() == "gz");
1847  CHECK(ryml::csubstr("/path/to/file.tar.gz").extlong() == "tar.gz");
1848  CHECK(ryml::csubstr("/path/to/file.tar.gz").name_wo_extshort() == "/path/to/file.tar");
1849  CHECK(ryml::csubstr("/path/to/file.tar.gz").name_wo_extlong() == "/path/to/file");
1850  }
1851 
1852  // split()
1853  {
1854  using namespace ryml;
1855  csubstr parts[] = {"aa", "bb", "cc", "dd", "ee", "ff"};
1856  {
1857  size_t count = 0;
1858  for(csubstr part : csubstr("aa/bb/cc/dd/ee/ff").split('/'))
1859  CHECK(part == parts[count++]);
1860  CHECK(count == 6u);
1861  }
1862  {
1863  size_t count = 0;
1864  for(csubstr part : csubstr("aa.bb.cc.dd.ee.ff").split('.'))
1865  CHECK(part == parts[count++]);
1866  CHECK(count == 6u);
1867  }
1868  {
1869  size_t count = 0;
1870  for(csubstr part : csubstr("aa-bb-cc-dd-ee-ff").split('-'))
1871  CHECK(part == parts[count++]);
1872  CHECK(count == 6u);
1873  }
1874  // see also next_split()
1875  }
1876 
1877  // pop_left(), pop_right() --- non-greedy version
1878  // gpop_left(), gpop_right() --- greedy version
1879  {
1880  const bool skip_empty = true;
1881  // pop_left(): pop the last element from the left
1882  CHECK(ryml::csubstr( "0/1/2" ). pop_left('/' ) == "0" );
1883  CHECK(ryml::csubstr( "/0/1/2" ). pop_left('/' ) == "" );
1884  CHECK(ryml::csubstr("//0/1/2" ). pop_left('/' ) == "" );
1885  CHECK(ryml::csubstr( "0/1/2" ). pop_left('/', skip_empty) == "0" );
1886  CHECK(ryml::csubstr( "/0/1/2" ). pop_left('/', skip_empty) == "/0" );
1887  CHECK(ryml::csubstr("//0/1/2" ). pop_left('/', skip_empty) == "//0" );
1888  // gpop_left(): pop all but the first element (greedy pop)
1889  CHECK(ryml::csubstr( "0/1/2" ).gpop_left('/' ) == "0/1" );
1890  CHECK(ryml::csubstr( "/0/1/2" ).gpop_left('/' ) == "/0/1" );
1891  CHECK(ryml::csubstr("//0/1/2" ).gpop_left('/' ) == "//0/1" );
1892  CHECK(ryml::csubstr( "0/1/2/" ).gpop_left('/' ) == "0/1/2");
1893  CHECK(ryml::csubstr( "/0/1/2/" ).gpop_left('/' ) == "/0/1/2");
1894  CHECK(ryml::csubstr("//0/1/2/" ).gpop_left('/' ) == "//0/1/2");
1895  CHECK(ryml::csubstr( "0/1/2//" ).gpop_left('/' ) == "0/1/2/");
1896  CHECK(ryml::csubstr( "/0/1/2//" ).gpop_left('/' ) == "/0/1/2/");
1897  CHECK(ryml::csubstr("//0/1/2//" ).gpop_left('/' ) == "//0/1/2/");
1898  CHECK(ryml::csubstr( "0/1/2" ).gpop_left('/', skip_empty) == "0/1" );
1899  CHECK(ryml::csubstr( "/0/1/2" ).gpop_left('/', skip_empty) == "/0/1" );
1900  CHECK(ryml::csubstr("//0/1/2" ).gpop_left('/', skip_empty) == "//0/1" );
1901  CHECK(ryml::csubstr( "0/1/2/" ).gpop_left('/', skip_empty) == "0/1" );
1902  CHECK(ryml::csubstr( "/0/1/2/" ).gpop_left('/', skip_empty) == "/0/1" );
1903  CHECK(ryml::csubstr("//0/1/2/" ).gpop_left('/', skip_empty) == "//0/1" );
1904  CHECK(ryml::csubstr( "0/1/2//" ).gpop_left('/', skip_empty) == "0/1" );
1905  CHECK(ryml::csubstr( "/0/1/2//" ).gpop_left('/', skip_empty) == "/0/1" );
1906  CHECK(ryml::csubstr("//0/1/2//" ).gpop_left('/', skip_empty) == "//0/1" );
1907  // pop_right(): pop the last element from the right
1908  CHECK(ryml::csubstr( "0/1/2" ). pop_right('/' ) == "2" );
1909  CHECK(ryml::csubstr( "0/1/2/" ). pop_right('/' ) == "" );
1910  CHECK(ryml::csubstr( "0/1/2//" ). pop_right('/' ) == "" );
1911  CHECK(ryml::csubstr( "0/1/2" ). pop_right('/', skip_empty) == "2" );
1912  CHECK(ryml::csubstr( "0/1/2/" ). pop_right('/', skip_empty) == "2/" );
1913  CHECK(ryml::csubstr( "0/1/2//" ). pop_right('/', skip_empty) == "2//" );
1914  // gpop_right(): pop all but the first element (greedy pop)
1915  CHECK(ryml::csubstr( "0/1/2" ).gpop_right('/' ) == "1/2" );
1916  CHECK(ryml::csubstr( "0/1/2/" ).gpop_right('/' ) == "1/2/" );
1917  CHECK(ryml::csubstr( "0/1/2//" ).gpop_right('/' ) == "1/2//");
1918  CHECK(ryml::csubstr( "/0/1/2" ).gpop_right('/' ) == "0/1/2" );
1919  CHECK(ryml::csubstr( "/0/1/2/" ).gpop_right('/' ) == "0/1/2/" );
1920  CHECK(ryml::csubstr( "/0/1/2//" ).gpop_right('/' ) == "0/1/2//");
1921  CHECK(ryml::csubstr("//0/1/2" ).gpop_right('/' ) == "/0/1/2" );
1922  CHECK(ryml::csubstr("//0/1/2/" ).gpop_right('/' ) == "/0/1/2/" );
1923  CHECK(ryml::csubstr("//0/1/2//" ).gpop_right('/' ) == "/0/1/2//");
1924  CHECK(ryml::csubstr( "0/1/2" ).gpop_right('/', skip_empty) == "1/2" );
1925  CHECK(ryml::csubstr( "0/1/2/" ).gpop_right('/', skip_empty) == "1/2/" );
1926  CHECK(ryml::csubstr( "0/1/2//" ).gpop_right('/', skip_empty) == "1/2//");
1927  CHECK(ryml::csubstr( "/0/1/2" ).gpop_right('/', skip_empty) == "1/2" );
1928  CHECK(ryml::csubstr( "/0/1/2/" ).gpop_right('/', skip_empty) == "1/2/" );
1929  CHECK(ryml::csubstr( "/0/1/2//" ).gpop_right('/', skip_empty) == "1/2//");
1930  CHECK(ryml::csubstr("//0/1/2" ).gpop_right('/', skip_empty) == "1/2" );
1931  CHECK(ryml::csubstr("//0/1/2/" ).gpop_right('/', skip_empty) == "1/2/" );
1932  CHECK(ryml::csubstr("//0/1/2//" ).gpop_right('/', skip_empty) == "1/2//");
1933  }
1934 }
basic_substring trimr(const C c) const
trim the character c from the right
Definition: substr.hpp:653
bool begins_with_any(ro_substr chars) const noexcept
true if the first character of the string is any of the given chars
Definition: substr.hpp:883
basic_substring trim(const C c) const
trim the character c left and right
Definition: substr.hpp:677
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
Definition: substr.hpp:484
basic_substring stripr(ro_substr pattern) const
remove a pattern from the right
Definition: substr.hpp:699
bool overlaps(ro_substr const that) const noexcept
true if there is overlap of at least one element between that and *this
Definition: substr.hpp:493
C * str
a restricted pointer to the first character of the substring
Definition: substr.hpp:216
size_t first_of(const C c, size_t start=0) const
Definition: substr.hpp:934
auto fill(C val) -> typename std::enable_if< !std::is_const< U >::value, void >::type
fill the entire contents with the given val
Definition: substr.hpp:2153
bool ends_with(const C c) const noexcept
true if the last character of the string is c
Definition: substr.hpp:894
substr to_substr(char(&s)[N]) noexcept
Definition: substr.hpp:2376
basic_substring right_of(size_t pos) const noexcept
return [pos+1, len[
Definition: substr.hpp:574
auto replace(C value, C repl, size_t pos=0) -> typename std::enable_if< !std::is_const< U >::value, size_t >::type
replace every occurrence of character value with the character repl
Definition: substr.hpp:2272
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
Definition: substr.hpp:529
C * data() noexcept
Definition: substr.hpp:366
size_t last_not_of(const C c) const
Definition: substr.hpp:1014
size_t last_of(const C c, size_t start=npos) const
Definition: substr.hpp:946
size_t size() const noexcept
Definition: substr.hpp:358
basic_substring stripl(ro_substr pattern) const
remove a pattern from the left
Definition: substr.hpp:690
auto reverse() -> typename std::enable_if< !std::is_const< U >::value, void >::type
reverse in place
Definition: substr.hpp:2199
size_t count(const C c, size_t pos=0) const
count the number of occurrences of c
Definition: substr.hpp:744
auto reverse_sub(size_t ifirst, size_t num) -> typename std::enable_if< !std::is_const< U >::value, void >::type
revert a subpart in place
Definition: substr.hpp:2209
basic_substring sub(size_t first) const noexcept
return [first,len[
Definition: substr.hpp:502
csubstr to_csubstr(const char(&s)[N]) noexcept
Definition: substr.hpp:2380
a null string position
Definition: common.hpp:138
basic_substring< const char > csubstr
an immutable string view
Definition: substr.hpp:2356
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
basic_substring offs(size_t left, size_t right) const noexcept
offset from the ends: return [left,len-right[ ; ie, trim a number of characters from the left and rig...
Definition: substr.hpp:547
auto toupper() -> typename std::enable_if< !std::is_const< U >::value, void >::type
convert the string to upper-case
Definition: substr.hpp:2127
Definition: ryml.hpp:6
basic_substring range(size_t first, size_t last=npos) const noexcept
return [first,last[.
Definition: substr.hpp:519
basic_substring triml(const C c) const
trim left
Definition: substr.hpp:629
auto reverse_range(size_t ifirst, size_t ilast) -> typename std::enable_if< !std::is_const< U >::value, void >::type
revert a range in place
Definition: substr.hpp:2221
size_t len
the length of the substring
Definition: substr.hpp:218
basic_substring select(const C c, size_t pos=0) const
get the substr consisting of the first occurrence of c after pos, or an empty substr if none occurs ...
Definition: substr.hpp:772
auto tolower() -> typename std::enable_if< !std::is_const< U >::value, void >::type
convert the string to lower-case
Definition: substr.hpp:2139
basic_substring last(size_t num) const noexcept
return the last num elements: [len-num,len[
Definition: substr.hpp:536
size_t find(const C c, size_t start_pos=0) const
Definition: substr.hpp:713
size_t first_not_of(const C c) const
Definition: substr.hpp:993
bool begins_with(const C c) const noexcept
true if the first character of the string is c
Definition: substr.hpp:850
C & back() noexcept
Definition: substr.hpp:375
bool ends_with_any(ro_substr chars) const noexcept
true if the last character of the string is any of the given chars
Definition: substr.hpp:922
basic_substring left_of(size_t pos) const noexcept
return [0, pos[ .
Definition: substr.hpp:556
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
Definition: substr.hpp:478