Replace boost::replace_all and boost::ireplace_all

Replaced with custom functions using std::string_view to remove Boost
dependency and reduce template instantiation, keeping original
behavior.

Tested: added UT and verified all tests passed

Change-Id: I82cc238c800c7780dc50b6a40445657931bf5250
Signed-off-by: George Liu <liuxiwei@ieisystem.com>
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/src/entity_manager/entity_manager.cpp b/src/entity_manager/entity_manager.cpp
index 852db33..522c6f3 100644
--- a/src/entity_manager/entity_manager.cpp
+++ b/src/entity_manager/entity_manager.cpp
@@ -14,7 +14,6 @@
 #include "utils.hpp"
 
 #include <boost/algorithm/string/case_conv.hpp>
-#include <boost/algorithm/string/replace.hpp>
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/post.hpp>
 #include <boost/asio/steady_timer.hpp>
diff --git a/src/entity_manager/overlay.cpp b/src/entity_manager/overlay.cpp
index 534c68f..ce41bca 100644
--- a/src/entity_manager/overlay.cpp
+++ b/src/entity_manager/overlay.cpp
@@ -3,10 +3,10 @@
 
 #include "overlay.hpp"
 
+#include "../utils.hpp"
 #include "devices.hpp"
 #include "utils.hpp"
 
-#include <boost/algorithm/string/replace.hpp>
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/steady_timer.hpp>
 #include <boost/container/flat_map.hpp>
@@ -39,7 +39,7 @@
         // remove brackets and comma from array
         std::string array = in.dump();
         array = array.substr(1, array.size() - 2);
-        boost::replace_all(array, ",", " ");
+        std::ranges::replace(array, ',', ' ');
         return array;
     }
     return in.dump();
@@ -247,10 +247,8 @@
         {
             channels = keyPair.value().get<std::vector<std::string>>();
         }
-        boost::replace_all(parameters, templateChar + keyPair.key(),
-                           subsituteString);
-        boost::replace_all(busPath, templateChar + keyPair.key(),
-                           subsituteString);
+        replaceAll(parameters, templateChar + keyPair.key(), subsituteString);
+        replaceAll(busPath, templateChar + keyPair.key(), subsituteString);
     }
 
     if (!bus || !address)
diff --git a/src/entity_manager/perform_probe.cpp b/src/entity_manager/perform_probe.cpp
index f398860..e5b57eb 100644
--- a/src/entity_manager/perform_probe.cpp
+++ b/src/entity_manager/perform_probe.cpp
@@ -5,7 +5,6 @@
 
 #include "perform_scan.hpp"
 
-#include <boost/algorithm/string/replace.hpp>
 #include <phosphor-logging/lg2.hpp>
 
 #include <regex>
@@ -114,7 +113,8 @@
                         return false;
                     }
                     std::string commandStr = *(match.begin() + 1);
-                    boost::replace_all(commandStr, "'", "");
+                    replaceAll(commandStr, "'", "");
+
                     cur = (std::find(scan->passedProbes.begin(),
                                      scan->passedProbes.end(), commandStr) !=
                            scan->passedProbes.end());
@@ -136,8 +136,9 @@
             }
             std::string commandStr = *(match.begin() + 1);
             // convert single ticks and single slashes into legal json
-            boost::replace_all(commandStr, "'", "\"");
-            boost::replace_all(commandStr, R"(\)", R"(\\)");
+            std::ranges::replace(commandStr, '\'', '"');
+
+            replaceAll(commandStr, R"(\)", R"(\\)");
             auto json = nlohmann::json::parse(commandStr, nullptr, false, true);
             if (json.is_discarded())
             {
diff --git a/src/entity_manager/utils.cpp b/src/entity_manager/utils.cpp
index 6f51ec8..4e46395 100644
--- a/src/entity_manager/utils.cpp
+++ b/src/entity_manager/utils.cpp
@@ -6,7 +6,6 @@
 #include "phosphor-logging/lg2.hpp"
 
 #include <boost/algorithm/string/case_conv.hpp>
-#include <boost/algorithm/string/replace.hpp>
 #include <phosphor-logging/lg2.hpp>
 #include <sdbusplus/bus/match.hpp>
 
@@ -170,11 +169,11 @@
         return ret;
     }
 
-    boost::replace_all(*strPtr, std::string(templateChar) + "index",
-                       std::to_string(index));
+    replaceAll(*strPtr, std::string(templateChar) + "index",
+               std::to_string(index));
     if (replaceStr)
     {
-        boost::replace_all(*strPtr, *replaceStr, std::to_string(index));
+        replaceAll(*strPtr, *replaceStr, std::to_string(index));
     }
 
     for (const auto& [propName, propValue] : interface)
@@ -205,7 +204,7 @@
                       strPtr->at(nextItemIdx)) == mathChars.end())
         {
             std::string val = std::visit(VariantToStringVisitor(), propValue);
-            boost::ireplace_all(*strPtr, templateName, val);
+            iReplaceAll(*strPtr, templateName, val);
             continue;
         }
 
diff --git a/src/utils.cpp b/src/utils.cpp
index 171c236..de433c8 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -3,7 +3,6 @@
 
 #include "utils.hpp"
 
-#include <boost/algorithm/string/replace.hpp>
 #include <boost/container/flat_map.hpp>
 #include <boost/lexical_cast.hpp>
 #include <phosphor-logging/lg2.hpp>
@@ -199,3 +198,40 @@
 
     return out;
 }
+
+void iReplaceAll(std::string& str, std::string_view search,
+                 std::string_view replace)
+{
+    if (search.empty() || search == replace)
+    {
+        return;
+    }
+
+    while (true)
+    {
+        std::ranges::subrange<std::string::iterator> match =
+            iFindFirst(str, search);
+        if (!match)
+        {
+            break;
+        }
+
+        str.replace(match.begin(), match.end(), replace.begin(), replace.end());
+    }
+}
+
+void replaceAll(std::string& str, std::string_view search,
+                std::string_view replace)
+{
+    if (search.empty())
+    {
+        return;
+    }
+
+    size_t pos = 0;
+    while ((pos = str.find(search, pos)) != std::string::npos)
+    {
+        str.replace(pos, search.size(), replace);
+        pos += replace.size();
+    }
+}
diff --git a/src/utils.hpp b/src/utils.hpp
index 99ff236..5ec882c 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -97,6 +97,12 @@
 
 std::vector<std::string> split(std::string_view str, char delim);
 
+void iReplaceAll(std::string& str, std::string_view search,
+                 std::string_view replace);
+
+void replaceAll(std::string& str, std::string_view search,
+                std::string_view replace);
+
 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 af224a8..54e2957 100644
--- a/test/test_utils.cpp
+++ b/test/test_utils.cpp
@@ -95,3 +95,59 @@
     std::vector<std::string> expected = {""};
     EXPECT_EQ(result, expected);
 }
+
+TEST(ReplaceAllTest, BasicReplacement)
+{
+    std::string str = "hello world, world!";
+    replaceAll(str, "world", "earth");
+    EXPECT_EQ(str, "hello earth, earth!");
+}
+
+TEST(ReplaceAllTest, NoMatch)
+{
+    std::string str = "hello world";
+    replaceAll(str, "xxx", "abc");
+    EXPECT_EQ(str, "hello world");
+}
+
+TEST(ReplaceAllTest, ReplaceWithEmpty)
+{
+    std::string str = "apple apple";
+    replaceAll(str, "apple", "");
+    EXPECT_EQ(str, " ");
+}
+
+TEST(ReplaceAllTest, ReplaceEmptySearch)
+{
+    std::string str = "abc";
+    replaceAll(str, "", "x");
+    EXPECT_EQ(str, "abc");
+}
+
+TEST(IReplaceAllTest, CaseInsensitive)
+{
+    std::string str = "Hello hEllo heLLo";
+    iReplaceAll(str, "hello", "hi");
+    EXPECT_EQ(str, "hi hi hi");
+}
+
+TEST(IReplaceAllTest, MixedContent)
+{
+    std::string str = "Hello World! WORLD world";
+    iReplaceAll(str, "world", "Earth");
+    EXPECT_EQ(str, "Hello Earth! Earth Earth");
+}
+
+TEST(IReplaceAllTest, NoMatchCaseInsensitive)
+{
+    std::string str = "Good Morning";
+    iReplaceAll(str, "night", "day");
+    EXPECT_EQ(str, "Good Morning");
+}
+
+TEST(IReplaceAllTest, ReplaceWithEmptyCaseInsensitive)
+{
+    std::string str = "ABC abc AbC";
+    iReplaceAll(str, "abc", "");
+    EXPECT_EQ(str, "  ");
+}