diff --git a/infra/util/BoundedString.cpp b/infra/util/BoundedString.cpp index a7054ba68..cb1cb7597 100644 --- a/infra/util/BoundedString.cpp +++ b/infra/util/BoundedString.cpp @@ -2,6 +2,15 @@ namespace infra { + + namespace literals + { + infra::BoundedConstString operator""_s(const char* str, std::size_t count) + { + return infra::BoundedConstString(str, count); + } + } + BoundedString ByteRangeAsString(infra::MemoryRange range) { return BoundedString(reinterpret_cast(range.begin()), range.size()); diff --git a/infra/util/BoundedString.hpp b/infra/util/BoundedString.hpp index fd1d6417a..3b4755f33 100644 --- a/infra/util/BoundedString.hpp +++ b/infra/util/BoundedString.hpp @@ -230,8 +230,21 @@ namespace infra size_type find_last_not_of(const char* s, size_type pos = npos) const; size_type find_last_not_of(char ch, size_type pos = npos) const; + template + bool starts_with(const BoundedStringBase& other) const; + bool starts_with(const char* s, size_type count) const; + bool starts_with(const char* s) const; + bool starts_with(char ch) const; + + template + bool ends_with(const BoundedStringBase& other) const; + bool ends_with(const char* s, size_type count) const; + bool ends_with(const char* s) const; + bool ends_with(char ch) const; + private: - static void AssignToRange(MemoryRange range, size_type& length, size_type count, char ch); + static void + AssignToRange(MemoryRange range, size_type& length, size_type count, char ch); template static void AssignToRange(MemoryRange range, size_type& length, const BoundedStringBase& other); template @@ -371,6 +384,11 @@ namespace infra } #endif + namespace literals + { + infra::BoundedConstString operator""_s(const char* str, std::size_t count); + } + //// Implementation //// template @@ -1290,6 +1308,58 @@ namespace infra return find_last_not_of(&ch, pos, 1); } + template + template + bool BoundedStringBase::starts_with(const BoundedStringBase& other) const + { + return starts_with(other.begin(), other.size()); + } + + template + bool BoundedStringBase::starts_with(const char* s, size_type count) const + { + return this->substr(0, count) == BoundedConstString{ s, count }; + } + + template + bool BoundedStringBase::starts_with(const char* s) const + { + return starts_with(s, std::strlen(s)); //NOSONAR + } + + template + bool BoundedStringBase::starts_with(char ch) const + { + return starts_with(&ch, 1); + } + + template + template + bool BoundedStringBase::ends_with(const BoundedStringBase& other) const + { + return ends_with(other.begin(), other.size()); + } + + template + bool BoundedStringBase::ends_with(const char* s, size_type count) const + { + if (count > length) + return false; + return this->substr(length - count, count) == BoundedConstString{ s, count }; + } + + template + bool BoundedStringBase::ends_with(const char* s) const + { + return ends_with(s, std::strlen(s)); //NOSONAR + } + + template + bool BoundedStringBase::ends_with(char ch) const + { + return ends_with(&ch, 1); + } + template void BoundedStringBase::AssignToRange(infra::MemoryRange range, size_type& length, size_type count, char ch) { diff --git a/infra/util/test/TestBoundedString.cpp b/infra/util/test/TestBoundedString.cpp index a7a899cae..ebf976709 100644 --- a/infra/util/test/TestBoundedString.cpp +++ b/infra/util/test/TestBoundedString.cpp @@ -1,6 +1,8 @@ #include "infra/util/BoundedString.hpp" #include "infra/util/ByteRange.hpp" +#include "gmock/gmock.h" #include "gtest/gtest.h" +#include TEST(BoundedStringTest, TestConstructedEmpty) { @@ -698,6 +700,28 @@ TEST(BoundedStringTest, TestFindLastNotOf) EXPECT_EQ(3, string.find_last_not_of('e')); } +TEST(BoundedStringTest, TestStartsWith) +{ + char search[] = "qwe"; + infra::BoundedConstString startsWith = "qwerty"; + infra::BoundedConstString endsWith = "tyrqwe"; + infra::BoundedConstString middle = "abcqwedef"; + EXPECT_THAT(startsWith.starts_with(search), testing::IsTrue()); + EXPECT_THAT(endsWith.starts_with(search), testing::IsFalse()); + EXPECT_THAT(middle.starts_with(search), testing::IsFalse()); +} + +TEST(BoundedStringTest, TestEndsWith) +{ + char search[] = "qwe"; + infra::BoundedConstString startsWith = "qwerty"; + infra::BoundedConstString endsWith = "tyrqwe"; + infra::BoundedConstString middle = "abcqwedef"; + EXPECT_THAT(startsWith.ends_with(search), testing::IsFalse()); + EXPECT_THAT(endsWith.ends_with(search), testing::IsTrue()); + EXPECT_THAT(middle.ends_with(search), testing::IsFalse()); +} + TEST(BoundedStringTest, TestStringAsByteRange) { infra::BoundedString::WithStorage<5> string("abcde"); @@ -754,3 +778,12 @@ TEST(BoundedStringTest, TestPrintTo2) infra::PrintTo(string, &stream); EXPECT_EQ(R"("abc")", stream.str()); } + +TEST(BoundedStringTest, TestStringLiteral) +{ + using namespace infra::literals; + auto string = "abc"_s; + EXPECT_THAT(string, testing::Eq("abc"_s)); + + static_assert(std::is_same_v); +}