Skip to content

Commit 033d504

Browse files
committed
Improved partitioning API
1 parent f0d5907 commit 033d504

File tree

3 files changed

+106
-44
lines changed

3 files changed

+106
-44
lines changed

lib/inc/sys_string/impl/misc.h

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -423,48 +423,81 @@ auto sysstr::sys_string_t<Storage>::replace(const StringOrChar1 & old, const Str
423423

424424
template<class Storage>
425425
template<class StringOrChar>
426-
auto sysstr::sys_string_t<Storage>::tailAfterFirst(const StringOrChar & divider) const ->
427-
std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>
426+
auto sysstr::sys_string_t<Storage>::suffix_after_first(const StringOrChar & divider) const ->
427+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>
428428
{
429429
sys_string_t<Storage>::char_access my_access(*this);
430430
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
431431
auto it = std::search(my_access.begin(), my_access.end(), divider_access.begin(), divider_access.end());
432-
if (it != my_access.end())
433-
it += divider_access.size();
432+
if (it == my_access.end() && divider_access.size() != 0)
433+
return std::nullopt;
434+
it += divider_access.size();
434435
return sys_string_t(it, my_access.end());
435436
}
436437

437438
template<class Storage>
438439
template<class StringOrChar>
439-
auto sysstr::sys_string_t<Storage>::headBeforeFirst(const StringOrChar & divider) const ->
440-
std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>
440+
auto sysstr::sys_string_t<Storage>::prefix_before_first(const StringOrChar & divider) const ->
441+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>
441442
{
442443
sys_string_t<Storage>::char_access my_access(*this);
443444
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
444445
auto it = std::search(my_access.begin(), my_access.end(), divider_access.begin(), divider_access.end());
446+
if (it == my_access.end() && divider_access.size() != 0)
447+
return std::nullopt;
445448
return sys_string_t(my_access.begin(), it);
446449
}
447450

448451
template<class Storage>
449452
template<class StringOrChar>
450-
auto sysstr::sys_string_t<Storage>::tailAfterLast(const StringOrChar & divider) const ->
451-
std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>
453+
auto sysstr::sys_string_t<Storage>::suffix_after_last(const StringOrChar & divider) const ->
454+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>
452455
{
453456
sys_string_t<Storage>::char_access my_access(*this);
454457
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
455458
auto it = std::search(my_access.rbegin(), my_access.rend(), divider_access.rbegin(), divider_access.rend());
459+
if (it == my_access.rend() && divider_access.size() != 0)
460+
return std::nullopt;
456461
return sys_string_t(my_access.begin() + (my_access.rend() - it), my_access.end());
457462
}
458463

459464
template<class Storage>
460465
template<class StringOrChar>
461-
auto sysstr::sys_string_t<Storage>::headBeforeLast(const StringOrChar & divider) const ->
462-
std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>
466+
auto sysstr::sys_string_t<Storage>::prefix_before_last(const StringOrChar & divider) const ->
467+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>
463468
{
464469
sys_string_t<Storage>::char_access my_access(*this);
465470
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
466471
auto it = std::search(my_access.rbegin(), my_access.rend(), divider_access.rbegin(), divider_access.rend());
467-
if (it != my_access.rend())
468-
it += divider_access.size();
472+
if (it == my_access.rend() && divider_access.size() != 0)
473+
return std::nullopt;
474+
it += divider_access.size();
469475
return sys_string_t(my_access.begin(), my_access.begin() + (my_access.rend() - it));
470476
}
477+
478+
template<class Storage>
479+
template<class StringOrChar>
480+
auto sysstr::sys_string_t<Storage>::partition_at_first(const StringOrChar & divider) const ->
481+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<std::pair<sys_string_t, sys_string_t>>>
482+
{
483+
sys_string_t<Storage>::char_access my_access(*this);
484+
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
485+
auto it = std::search(my_access.begin(), my_access.end(), divider_access.begin(), divider_access.end());
486+
if (it == my_access.end() && divider_access.size() != 0)
487+
return std::nullopt;
488+
return std::pair(sys_string_t(my_access.begin(), it), sys_string_t(it + divider_access.size(), my_access.end()));
489+
}
490+
491+
template<class Storage>
492+
template<class StringOrChar>
493+
auto sysstr::sys_string_t<Storage>::partition_at_last(const StringOrChar & divider) const ->
494+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<std::pair<sys_string_t, sys_string_t>>>
495+
{
496+
sys_string_t<Storage>::char_access my_access(*this);
497+
util::string_or_char32_char_access<Storage, StringOrChar> divider_access(divider);
498+
auto it = std::search(my_access.rbegin(), my_access.rend(), divider_access.rbegin(), divider_access.rend());
499+
if (it == my_access.rend() && divider_access.size() != 0)
500+
return std::nullopt;
501+
return std::pair(sys_string_t(my_access.begin(), my_access.begin() + (my_access.rend() - it - divider_access.size())),
502+
sys_string_t(my_access.begin() + (my_access.rend() - it), my_access.end()));
503+
}

lib/inc/sys_string/sys_string.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <vector>
1717
#include <string>
1818
#include <string_view>
19+
#include <optional>
1920
#include <ostream>
2021
#include <limits>
2122

@@ -282,13 +283,24 @@ namespace sysstr
282283
std::enable_if_t<is_string_or_char<StringOrChar1> && is_string_or_char<StringOrChar2>, sys_string_t>;
283284

284285
template<class StringOrChar>
285-
auto tailAfterFirst(const StringOrChar & divider) const -> std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>;
286+
auto suffix_after_first(const StringOrChar & divider) const ->
287+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>;
286288
template<class StringOrChar>
287-
auto headBeforeFirst(const StringOrChar & divider) const -> std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>;
289+
auto prefix_before_first(const StringOrChar & divider) const ->
290+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>;
288291
template<class StringOrChar>
289-
auto tailAfterLast(const StringOrChar & divider) const -> std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>;
292+
auto suffix_after_last(const StringOrChar & divider) const ->
293+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>;
290294
template<class StringOrChar>
291-
auto headBeforeLast(const StringOrChar & divider) const -> std::enable_if_t<is_string_or_char<StringOrChar>, sys_string_t>;
295+
auto prefix_before_last(const StringOrChar & divider) const ->
296+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<sys_string_t>>;
297+
298+
template<class StringOrChar>
299+
auto partition_at_first(const StringOrChar & divider) const ->
300+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<std::pair<sys_string_t, sys_string_t>>>;
301+
template<class StringOrChar>
302+
auto partition_at_last(const StringOrChar & divider) const ->
303+
std::enable_if_t<is_string_or_char<StringOrChar>, std::optional<std::pair<sys_string_t, sys_string_t>>>;
292304

293305
private:
294306
static auto compare(const sys_string_t & lhs, const sys_string_t & rhs) noexcept -> compare_result;

test/test_general.cpp

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -452,34 +452,51 @@ TEST_CASE( "Replace", "[general]" ) {
452452

453453
TEST_CASE( "HeadTail", "[general]" ) {
454454

455-
CHECK(S("").tailAfterFirst(S("")) == S(""));
456-
CHECK(S("").tailAfterFirst(U'a') == S(""));
457-
CHECK(S("").headBeforeFirst(S("")) == S(""));
458-
CHECK(S("").headBeforeFirst(U'a') == S(""));
459-
CHECK(S("").tailAfterLast(S("")) == S(""));
460-
CHECK(S("").tailAfterLast(U'a') == S(""));
461-
CHECK(S("").headBeforeLast(S("")) == S(""));
462-
CHECK(S("").headBeforeLast(U'a') == S(""));
463-
464-
CHECK(S("ab").tailAfterFirst(S("c")) == S(""));
465-
CHECK(S("ab").headBeforeFirst(S("c")) == S("ab"));
466-
CHECK(S("ab").tailAfterLast(S("c")) == S("ab"));
467-
CHECK(S("ab").headBeforeLast(S("c")) == S(""));
468-
469-
CHECK(S("ab").tailAfterFirst(S("a")) == S("b"));
470-
CHECK(S("ab").headBeforeFirst(S("a")) == S(""));
471-
CHECK(S("ab").tailAfterLast(S("b")) == S(""));
472-
CHECK(S("ab").headBeforeLast(S("b")) == S("a"));
473-
474-
CHECK(S("a🥸b").tailAfterFirst(S("🥸")) == S("b"));
475-
CHECK(S("a🥸b").headBeforeFirst(S("🥸")) == S("a"));
476-
CHECK(S("a🥸b").tailAfterLast(S("🥸")) == S("b"));
477-
CHECK(S("a🥸b").headBeforeLast(S("🥸")) == S("a"));
478-
479-
CHECK(S("a🥸b🥸c").tailAfterFirst(S("🥸")) == S("b🥸c"));
480-
CHECK(S("a🥸b🥸c").headBeforeFirst(S("🥸")) == S("a"));
481-
CHECK(S("a🥸b🥸c").tailAfterLast(S("🥸")) == S("c"));
482-
CHECK(S("a🥸b🥸c").headBeforeLast(S("🥸")) == S("a🥸b"));
455+
CHECK(S("").suffix_after_first(S("")) == S(""));
456+
CHECK(S("").suffix_after_first(U'a') == std::nullopt);
457+
CHECK(S("").prefix_before_first(S("")) == S(""));
458+
CHECK(S("").prefix_before_first(U'a') == std::nullopt);
459+
CHECK(S("").suffix_after_last(S("")) == S(""));
460+
CHECK(S("").suffix_after_last(U'a') == std::nullopt);
461+
CHECK(S("").prefix_before_last(S("")) == S(""));
462+
CHECK(S("").prefix_before_last(U'a') == std::nullopt);
463+
464+
CHECK(S("ab").suffix_after_first(S("c")) == std::nullopt);
465+
CHECK(S("ab").prefix_before_first(S("c")) == std::nullopt);
466+
CHECK(S("ab").suffix_after_last(S("c")) == std::nullopt);
467+
CHECK(S("ab").prefix_before_last(S("c")) == std::nullopt);
468+
469+
CHECK(S("ab").suffix_after_first(S("a")) == S("b"));
470+
CHECK(S("ab").prefix_before_first(S("a")) == S(""));
471+
CHECK(S("ab").suffix_after_last(S("b")) == S(""));
472+
CHECK(S("ab").prefix_before_last(S("b")) == S("a"));
473+
474+
CHECK(S("a🥸b").suffix_after_first(S("🥸")) == S("b"));
475+
CHECK(S("a🥸b").prefix_before_first(S("🥸")) == S("a"));
476+
CHECK(S("a🥸b").suffix_after_last(S("🥸")) == S("b"));
477+
CHECK(S("a🥸b").prefix_before_last(S("🥸")) == S("a"));
478+
479+
CHECK(S("a🥸b🥸c").suffix_after_first(S("🥸")) == S("b🥸c"));
480+
CHECK(S("a🥸b🥸c").prefix_before_first(S("🥸")) == S("a"));
481+
CHECK(S("a🥸b🥸c").suffix_after_last(S("🥸")) == S("c"));
482+
CHECK(S("a🥸b🥸c").prefix_before_last(S("🥸")) == S("a🥸b"));
483+
}
484+
485+
TEST_CASE( "Partition", "[general]" ) {
486+
CHECK(S("").partition_at_first(S("")) == std::pair(S(""), S("")));
487+
CHECK(S("").partition_at_first(U'a') == std::nullopt);
488+
CHECK(S("").partition_at_last(S("")) == std::pair(S(""), S("")));
489+
CHECK(S("").partition_at_last(U'a') == std::nullopt);
490+
491+
CHECK(S("ab").partition_at_first(S("c")) == std::nullopt);
492+
CHECK(S("ab").partition_at_last(S("c")) == std::nullopt);
493+
CHECK(S("ab").partition_at_first(S("a")) == std::pair(S(""), S("b")));
494+
CHECK(S("ab").partition_at_last(S("b")) == std::pair(S("a"), S("")));
495+
496+
CHECK(S("a🥸b").partition_at_first(S("🥸")) == std::pair(S("a"), S("b")));
497+
CHECK(S("a🥸b").partition_at_last(S("🥸")) == std::pair(S("a"), S("b")));
498+
CHECK(S("a🥸b🥸c").partition_at_first(S("🥸")) == std::pair(S("a"), S("b🥸c")));
499+
CHECK(S("a🥸b🥸c").partition_at_last(S("🥸")) == std::pair(S("a🥸b"), S("c")));
483500
}
484501

485502
TEST_CASE( "Addition", "[general]" ) {

0 commit comments

Comments
 (0)