diff --git a/CMakeLists.txt b/CMakeLists.txt index 54bb08e..a4deb98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.15 FATAL_ERROR) -project(EduceLabCore VERSION 0.2.1) +project(EduceLabCore VERSION 0.3.0) # Setup project directories set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) diff --git a/include/educelab/core/utils/String.hpp b/include/educelab/core/utils/String.hpp index 24a99a8..457781e 100644 --- a/include/educelab/core/utils/String.hpp +++ b/include/educelab/core/utils/String.hpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -189,6 +191,39 @@ static auto split(std::string_view s, const Ds&... ds) return tokens; } +/** @brief Partition a string by a separator substring */ +static auto partition(std::string_view s, const std::string_view sep) + -> std::tuple +{ + // Find the starting position + const auto startPos = s.find(sep); + + // Didn't find the delimiter + if (startPos == std::string::npos) { + return {s, "", ""}; + } + + // Split into parts + auto pre = s.substr(0, startPos); + auto mid = s.substr(startPos, sep.size()); + auto post = s.substr(startPos + sep.size()); + + // Return the parts + return {pre, mid, post}; +} + +/** @brief Convert an Integer to a padded string */ +template < + typename Integer, + std::enable_if_t, bool> = true> +auto to_padded_string(Integer val, const int padding, const char fill = '0') + -> std::string +{ + std::stringstream stream; + stream << std::setw(padding) << std::setfill(fill) << val; + return stream.str(); +} + /** * @brief Convert a string to a numeric type. * diff --git a/tests/src/TestString.cpp b/tests/src/TestString.cpp index 55ac8bf..9a6d7e1 100644 --- a/tests/src/TestString.cpp +++ b/tests/src/TestString.cpp @@ -1,6 +1,7 @@ #include #include +#include #include "educelab/core/utils/String.hpp" @@ -151,17 +152,50 @@ TEST(String, Split) EXPECT_EQ(split("This is only a test."), expected); } +TEST(String, Partition) +{ + // key=value + const auto [p0, m0, s0] = partition("key=value", "="); + EXPECT_EQ(p0, "key"); + EXPECT_EQ(m0, "="); + EXPECT_EQ(s0, "value"); + + // {} replacement + const auto [p1, m1, s1] = partition("prefix{}suffix", "{}"); + EXPECT_EQ(p1, "prefix"); + EXPECT_EQ(m1, "{}"); + EXPECT_EQ(s1, "suffix"); + + // to existing strings + std::string p2, m2, s2; + std::tie(p2, m2, s2) = partition("abc", "b"); + EXPECT_EQ(p2, "a"); + EXPECT_EQ(m2, "b"); + EXPECT_EQ(s2, "c"); +} + +TEST(String, ToPaddedString) +{ + // zero-pad (default) + EXPECT_EQ(to_padded_string(5, 3), "005"); + EXPECT_EQ(to_padded_string(5, 10), "0000000005"); + + // zero-pad (custom) + EXPECT_EQ(to_padded_string(5, 3, '5'), "555"); + EXPECT_EQ(to_padded_string(5, 3, 'x'), "xx5"); +} + TEST(String, ToNumeric) { std::string test{"100.3456 unparsed"}; - EXPECT_EQ(to_numeric(test), int8_t(100)); - EXPECT_EQ(to_numeric(test), uint8_t(100)); - EXPECT_EQ(to_numeric(test), int16_t(100)); - EXPECT_EQ(to_numeric(test), uint16_t(100)); - EXPECT_EQ(to_numeric(test), int32_t(100)); - EXPECT_EQ(to_numeric(test), uint32_t(100)); - EXPECT_EQ(to_numeric(test), int64_t(100)); - EXPECT_EQ(to_numeric(test), uint64_t(100)); + EXPECT_EQ(to_numeric(test), std::int8_t{100}); + EXPECT_EQ(to_numeric(test), std::uint8_t{100}); + EXPECT_EQ(to_numeric(test), std::int16_t{100}); + EXPECT_EQ(to_numeric(test), std::uint16_t{100}); + EXPECT_EQ(to_numeric(test), std::int32_t{100}); + EXPECT_EQ(to_numeric(test), std::uint32_t{100}); + EXPECT_EQ(to_numeric(test), std::int64_t{100}); + EXPECT_EQ(to_numeric(test), std::uint64_t{100}); EXPECT_EQ(to_numeric(test), 100.3456F); EXPECT_EQ(to_numeric(test), 100.3456);