Skip to content

Commit

Permalink
feat: added starts_with ends_with and ""_s literal for Bounded(Const)…
Browse files Browse the repository at this point in the history
…String (#777)
  • Loading branch information
daantimmer authored Nov 27, 2024
1 parent feecdc6 commit 6c5cb00
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
9 changes: 9 additions & 0 deletions infra/util/BoundedString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> range)
{
return BoundedString(reinterpret_cast<char*>(range.begin()), range.size());
Expand Down
72 changes: 71 additions & 1 deletion infra/util/BoundedString.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<class U>
bool starts_with(const BoundedStringBase<U>& 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<class U>
bool ends_with(const BoundedStringBase<U>& 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<NonConstT> range, size_type& length, size_type count, char ch);
static void
AssignToRange(MemoryRange<NonConstT> range, size_type& length, size_type count, char ch);
template<class U>
static void AssignToRange(MemoryRange<NonConstT> range, size_type& length, const BoundedStringBase<U>& other);
template<class U>
Expand Down Expand Up @@ -371,6 +384,11 @@ namespace infra
}
#endif

namespace literals
{
infra::BoundedConstString operator""_s(const char* str, std::size_t count);
}

//// Implementation ////

template<class T>
Expand Down Expand Up @@ -1290,6 +1308,58 @@ namespace infra
return find_last_not_of(&ch, pos, 1);
}

template<class T>
template<class U>
bool BoundedStringBase<T>::starts_with(const BoundedStringBase<U>& other) const
{
return starts_with(other.begin(), other.size());
}

template<class T>
bool BoundedStringBase<T>::starts_with(const char* s, size_type count) const
{
return this->substr(0, count) == BoundedConstString{ s, count };
}

template<class T>
bool BoundedStringBase<T>::starts_with(const char* s) const
{
return starts_with(s, std::strlen(s)); //NOSONAR
}

template<class T>
bool BoundedStringBase<T>::starts_with(char ch) const
{
return starts_with(&ch, 1);
}

template<class T>
template<class U>
bool BoundedStringBase<T>::ends_with(const BoundedStringBase<U>& other) const
{
return ends_with(other.begin(), other.size());
}

template<class T>
bool BoundedStringBase<T>::ends_with(const char* s, size_type count) const
{
if (count > length)
return false;
return this->substr(length - count, count) == BoundedConstString{ s, count };
}

template<class T>
bool BoundedStringBase<T>::ends_with(const char* s) const
{
return ends_with(s, std::strlen(s)); //NOSONAR
}

template<class T>
bool BoundedStringBase<T>::ends_with(char ch) const
{
return ends_with(&ch, 1);
}

template<class T>
void BoundedStringBase<T>::AssignToRange(infra::MemoryRange<NonConstT> range, size_type& length, size_type count, char ch)
{
Expand Down
33 changes: 33 additions & 0 deletions infra/util/test/TestBoundedString.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "infra/util/BoundedString.hpp"
#include "infra/util/ByteRange.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <type_traits>

TEST(BoundedStringTest, TestConstructedEmpty)
{
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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<decltype(string), infra::BoundedConstString>);
}

0 comments on commit 6c5cb00

Please sign in to comment.