-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
src/util/basyx/util/constrained_string/constrained_string.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
#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 reverse_iterator = std::string::reverse_iterator; | ||
using const_iterator = std::string::const_iterator; | ||
using const_reverse_iterator = std::string::const_reverse_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 reverse_iterator rbegin() noexcept { return this->content.rbegin(); }; | ||
inline const_reverse_iterator crbegin() const noexcept { return this->content.crbegin(); }; | ||
|
||
inline reverse_iterator rend() noexcept { return this->content.rend(); }; | ||
inline const_reverse_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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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-"); | ||
} |