Remove boost::split

Replaced boost::split with a simple std::string_view-based split to
reduce Boost dependency and template instantiation during compilation

Tested: added UT and verified all tests passed

Change-Id: Icc84794a3d5a98088bdbce032dc76055a035f0dc
Signed-off-by: George Liu <liuxiwei@ieisystem.com>
diff --git a/src/entity_manager/entity_manager.cpp b/src/entity_manager/entity_manager.cpp
index ef4212a..852db33 100644
--- a/src/entity_manager/entity_manager.cpp
+++ b/src/entity_manager/entity_manager.cpp
@@ -14,9 +14,7 @@
 #include "utils.hpp"
 
 #include <boost/algorithm/string/case_conv.hpp>
-#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/post.hpp>
 #include <boost/asio/steady_timer.hpp>
diff --git a/src/entity_manager/utils.cpp b/src/entity_manager/utils.cpp
index 9e379e9..6f51ec8 100644
--- a/src/entity_manager/utils.cpp
+++ b/src/entity_manager/utils.cpp
@@ -6,9 +6,7 @@
 #include "phosphor-logging/lg2.hpp"
 
 #include <boost/algorithm/string/case_conv.hpp>
-#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
 #include <phosphor-logging/lg2.hpp>
 #include <sdbusplus/bus/match.hpp>
 
@@ -217,15 +215,14 @@
         // operate on the rest
         std::string end = strPtr->substr(nextItemIdx);
 
-        std::vector<std::string> split;
-        boost::split(split, end, boost::is_any_of(" "));
+        std::vector<std::string> splitResult = split(end, ' ');
 
         // need at least 1 operation and number
-        if (split.size() < 2)
+        if (splitResult.size() < 2)
         {
             lg2::error("Syntax error on template replacement of {STR}", "STR",
                        *strPtr);
-            for (const std::string& data : split)
+            for (const std::string& data : splitResult)
             {
                 lg2::error("{SPLIT} ", "SPLIT", data);
             }
@@ -237,8 +234,8 @@
         // only do math on numbers.. we might concatenate strings in the
         // future, but thats later
         int number = std::visit(VariantToIntVisitor(), propValue);
-        auto exprBegin = split.begin();
-        auto exprEnd = split.end();
+        auto exprBegin = splitResult.begin();
+        auto exprEnd = splitResult.end();
 
         number = expression::evaluate(number, exprBegin, exprEnd);
 
@@ -250,7 +247,7 @@
         ret = replaced;
 
         std::string result = prefix + std::to_string(number);
-        while (exprEnd != split.end())
+        while (exprEnd != splitResult.end())
         {
             result.append(" ").append(*exprEnd++);
         }
diff --git a/src/utils.cpp b/src/utils.cpp
index 0650a01..171c236 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -3,9 +3,7 @@
 
 #include "utils.hpp"
 
-#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
 #include <boost/container/flat_map.hpp>
 #include <boost/lexical_cast.hpp>
 #include <phosphor-logging/lg2.hpp>
@@ -180,3 +178,24 @@
 {
     return std::visit(MatchProbeForwarder(probe), dbusValue);
 }
+
+std::vector<std::string> split(std::string_view str, char delim)
+{
+    std::vector<std::string> out;
+
+    size_t start = 0;
+    while (start <= str.size())
+    {
+        size_t end = str.find(delim, start);
+        if (end == std::string_view::npos)
+        {
+            out.emplace_back(str.substr(start));
+            break;
+        }
+
+        out.emplace_back(str.substr(start, end - start));
+        start = end + 1;
+    }
+
+    return out;
+}
diff --git a/src/utils.hpp b/src/utils.hpp
index 4565db0..99ff236 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -95,6 +95,8 @@
     });
 }
 
+std::vector<std::string> split(std::string_view str, char delim);
+
 template <typename T>
 std::from_chars_result fromCharsWrapper(const std::string_view& str, T& out,
                                         bool& fullMatch, int base = 10)
diff --git a/test/test_utils.cpp b/test/test_utils.cpp
index 7c67e9b..af224a8 100644
--- a/test/test_utils.cpp
+++ b/test/test_utils.cpp
@@ -53,3 +53,45 @@
     auto match = iFindFirst("", "Hello");
     EXPECT_FALSE(match);
 }
+
+TEST(SplitTest, NormalSplit)
+{
+    auto result = split("a,b,c", ',');
+    std::vector<std::string> expected = {"a", "b", "c"};
+    EXPECT_EQ(result, expected);
+}
+
+TEST(SplitTest, ConsecutiveDelimiters)
+{
+    auto result = split("a,,b", ',');
+    std::vector<std::string> expected = {"a", "", "b"};
+    EXPECT_EQ(result, expected);
+}
+
+TEST(SplitTest, LeadingDelimiter)
+{
+    auto result = split(",a,b", ',');
+    std::vector<std::string> expected = {"", "a", "b"};
+    EXPECT_EQ(result, expected);
+}
+
+TEST(SplitTest, TrailingDelimiter)
+{
+    auto result = split("a,b,", ',');
+    std::vector<std::string> expected = {"a", "b", ""};
+    EXPECT_EQ(result, expected);
+}
+
+TEST(SplitTest, NoDelimiter)
+{
+    auto result = split("abc", ',');
+    std::vector<std::string> expected = {"abc"};
+    EXPECT_EQ(result, expected);
+}
+
+TEST(SplitTest, EmptyString)
+{
+    auto result = split("", ',');
+    std::vector<std::string> expected = {""};
+    EXPECT_EQ(result, expected);
+}