Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added starts_with ends_with and ""_s literal for Bounded(Const)String #777

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>);
}
Loading