Skip to content

Commit

Permalink
Added util::constrained_string
Browse files Browse the repository at this point in the history
  • Loading branch information
IESE-T3 committed Sep 20, 2023
1 parent 634bf34 commit 57e0ae5
Show file tree
Hide file tree
Showing 4 changed files with 316 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/util/basyx/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ SET(HEADER_FILES_UTIL
${CMAKE_CURRENT_SOURCE_DIR}/algorithm/string.hpp
${CMAKE_CURRENT_SOURCE_DIR}/container/container.hpp
${CMAKE_CURRENT_SOURCE_DIR}/optional/optional.hpp
${CMAKE_CURRENT_SOURCE_DIR}/constrained_string/constrained_string.hpp
${CMAKE_CURRENT_SOURCE_DIR}/constrained_string/regex_checker.hpp
${CMAKE_CURRENT_SOURCE_DIR}/string_view/basic_string_view.hpp
${CMAKE_CURRENT_SOURCE_DIR}/string_view/string_view.hpp
)
Expand Down
145 changes: 145 additions & 0 deletions src/util/basyx/util/constrained_string/constrained_string.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#ifndef BASYX_UTIL_CONSTRAINED_STRING_H
#define BASYX_UTIL_CONSTRAINED_STRING_H

#include <basyx/util/string_view/string_view.hpp>

namespace basyx {
namespace util {

class NullConstraint
{
public:
bool operator()(basyx::util::string_view sv) { return true; };
};

template<std::size_t Min = 1, std::size_t Max = 2048, typename ConstraintT = NullConstraint, char FillChar = '-'>
class constrained_string
{
public:
using constraint_t = ConstraintT;

public:
using iterator = std::string::iterator;
using const_iterator = std::string::const_iterator;

public:
static constexpr char fill_char = FillChar;

private:
constraint_t constraint;
std::string content;

public:
static constexpr std::size_t min = Min;
static constexpr std::size_t max = Max;

public:
// Constructors
explicit constrained_string() noexcept {};
constrained_string(const char* c_str) noexcept { this->assign(c_str); }
constrained_string(const std::string& string) noexcept { this->assign(string); };
constrained_string(util::string_view sv) noexcept { this->assign(sv); }

// Copy constructors
template<std::size_t Min_ = Min, std::size_t Max_ = Max, typename ConstraintT_ = ConstraintT, char FillChar_ = FillChar>
constrained_string(const constrained_string<Min_, Max_, ConstraintT_, FillChar_>& rhs) noexcept {
this->assign(rhs.str());
};

template<std::size_t Min_ = Min, std::size_t Max_ = Max, typename ConstraintT_ = ConstraintT, char FillChar_ = FillChar>
constrained_string& operator=(const constrained_string<Min_, Max_, ConstraintT_, FillChar_>& rhs) noexcept {
this->assign(rhs.str());
return *this;
};

// Move constructors
template<std::size_t Min_ = Min, std::size_t Max_ = Max, typename ConstraintT_ = ConstraintT, char FillChar_ = FillChar>
constrained_string(constrained_string<Min_, Max_, ConstraintT_, FillChar_> && rhs) noexcept {
this->assign(std::move(rhs.content));
};

template<std::size_t Min_ = Min, std::size_t Max_ = Max, typename ConstraintT_ = ConstraintT, char FillChar_ = FillChar>
constrained_string& operator=(constrained_string<Min_, Max_, ConstraintT_, FillChar_>&& rhs) noexcept {
this->assign(std::move(rhs.content));
return *this;
};

// Assignment operators
constrained_string& operator=(const char* c_str) noexcept { this->assign(c_str); return *this; }
constrained_string& operator=(const std::string& string) noexcept { this->assign(string); return *this; };
constrained_string& operator=(util::string_view sv) noexcept { this->assign(sv); return *this; }

public:
bool check_constraint(util::string_view sv) {
//if (sv.size() < Min || sv.size() > Max)
// return false;

return constraint(sv);
};

private:
void assign_fill(util::string_view sv) {
this->content = sv.to_string();

if (sv.size() > Max) {
this->content.resize(max, fill_char);
}
else if (sv.size() < Min) {
this->content.resize(min, fill_char);
};
};

public:
void assign(util::string_view sv) {
if (check_constraint(sv)) {
this->assign_fill(sv);
};
};

public:
inline std::size_t size() const { return this->content.size(); };
inline const char* data() const { return this->content.data(); };
inline bool empty() const { return this->content.empty(); };

public:
inline const std::string& str() const { return this->content; };
inline operator const std::string& () const { return this->str(); };

public:
inline iterator begin() noexcept { return this->content.begin(); };
inline const_iterator begin() const noexcept { return this->content.cbegin(); };

inline iterator end() noexcept { return this->content.end(); };
inline const_iterator cend() const noexcept { return this->content.end(); };

public:
inline iterator rbegin() noexcept { return this->content.rbegin(); };
inline const_iterator crbegin() const noexcept { return this->content.crbegin() };

inline iterator rend() noexcept { return this->content.rend(); };
inline const_iterator crend() const noexcept { return this->content.crend(); };
};


// Comparison operators
template<std::size_t Min, std::size_t Max, typename ConstraintT, char FillChar>
inline bool operator==(const constrained_string<Min, Max, ConstraintT, FillChar>& lhs, util::string_view sv) {
return lhs.str().compare(0, sv.size(), sv.data()) == 0;
};

template<std::size_t Min, std::size_t Max, typename ConstraintT, char FillChar>
inline bool operator!=(const constrained_string<Min, Max, ConstraintT, FillChar>& rhs, util::string_view sv) {
return !(rhs == sv);
};

// Stream operator
template<std::size_t Min, std::size_t Max, typename ConstraintT, char FillChar>
std::ostream& operator <<(std::ostream& os, const constrained_string<Min, Max, ConstraintT, FillChar>& constr_str) {
os << constr_str.str();
return os;
}

}
}

#endif
25 changes: 25 additions & 0 deletions src/util/basyx/util/constrained_string/regex_checker.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef BASYX_UTIL_CONSTRAINED_STRING_REGEX_CHECKER_H
#define BASYX_UTIL_CONSTRAINED_STRING_REGEX_CHECKER_H

#include <regex>

namespace basyx {
namespace util {

template<typename Holder>
class RegExChecker
{
public:
bool check(basyx::util::string_view sv) {
std::cmatch matches;

return std::regex_match(sv.begin(), sv.end(), matches, Holder::regex);
};

bool operator()(basyx::util::string_view sv) { return check(sv); };
};

}
}

#endif
144 changes: 144 additions & 0 deletions tests/tests_libaas/test_constrained_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include <gtest/gtest.h>

#include <basyx/util/constrained_string/constrained_string.hpp>
#include <basyx/util/constrained_string/regex_checker.hpp>

#include <string>

using namespace basyx;

class TestRegEx
{
public:
static std::regex regex;
};

std::regex TestRegEx::regex("^([0-9]|[1-9][0-9]*)$");

class ConstrainedStringTest : public ::testing::Test
{
protected:
// Test settings

// Test variables

virtual void SetUp()
{
}

virtual void TearDown()
{

}
};

using label_type_t = util::constrained_string<1, 64>;
using short_label_type_t = util::constrained_string<1, 4>;
using min_label_type_t = util::constrained_string<4, 8>;
using version_revision_type_t = util::constrained_string<1, 4, util::RegExChecker<TestRegEx>>;

TEST_F(ConstrainedStringTest, Constructor1)
{
std::string test_str = "test";
util::string_view test_sv = test_str;

label_type_t label_c_str("test");
label_type_t label_c_str_assign = "test";

label_type_t label_str(test_str);
label_type_t label_str_assign = test_str;

label_type_t label_sv(test_sv);
label_type_t label_sv_assign = test_sv;

ASSERT_EQ(label_c_str, "test");
ASSERT_EQ(label_c_str_assign, "test");

ASSERT_EQ(label_str, test_str);
ASSERT_EQ(label_str_assign, test_str);

ASSERT_EQ(label_sv, test_sv);
ASSERT_EQ(label_sv_assign, test_sv);
}

TEST_F(ConstrainedStringTest, Compare)
{
label_type_t label_1("test");
label_type_t label_2("999");
version_revision_type_t version_1("999");

ASSERT_EQ(label_1, label_1);
ASSERT_NE(label_1, label_2);
ASSERT_NE(label_1, version_1);

ASSERT_EQ(label_1, label_1);
ASSERT_EQ(label_2, label_2);
ASSERT_EQ(version_1, version_1);
ASSERT_EQ(version_1, label_2);
}

TEST_F(ConstrainedStringTest, EqualsOperator)
{
label_type_t label_1("test");
label_type_t label_2("999");
version_revision_type_t version_1("999");

ASSERT_TRUE(label_1 == "test");
ASSERT_TRUE(label_1 == std::string("test"));
ASSERT_TRUE(label_1 == util::string_view("test"));
ASSERT_FALSE(label_1 == "abcd");

ASSERT_TRUE(version_1 == "999");
ASSERT_TRUE(version_1 == std::string("999"));
ASSERT_TRUE(version_1 == util::string_view("999"));
ASSERT_FALSE(version_1 == "111");
}

TEST_F(ConstrainedStringTest, StringInteropTests)
{
std::string str("abcd");
label_type_t label_1("test");

str = label_1;
ASSERT_EQ(str, "test");
ASSERT_EQ(str, label_1.str());

util::string_view sv = label_1;
ASSERT_EQ(sv, "test");
ASSERT_EQ(sv, label_1);
}

TEST_F(ConstrainedStringTest, ConstraintCheckTest)
{
short_label_type_t label_1{ "abcd" };
short_label_type_t label_2{ "test" };
short_label_type_t label_3{ "test1234" };
version_revision_type_t version_1("999");

ASSERT_EQ(label_1, "abcd");
ASSERT_EQ(label_2, "test");
ASSERT_EQ(label_3, "test");

label_2 = "abcd1234";
ASSERT_EQ(label_2, "abcd");

label_2 = version_1;
ASSERT_EQ(label_2, "999");
ASSERT_EQ(version_1, "999");

version_1 = label_1;
ASSERT_EQ(version_1, "999");
ASSERT_EQ(label_1, "abcd");

version_1 = "0111";
ASSERT_EQ(version_1, "999");

version_1 = "111";
ASSERT_EQ(version_1, "111");

min_label_type_t min_label{ "test" };
ASSERT_EQ(min_label, "test");

min_label = "abc";
ASSERT_EQ(min_label, "abc-");
}

0 comments on commit 57e0ae5

Please sign in to comment.