MediaMetricsService: Extract common string utilities to audio_utils

Flag: EXEMPT refactor
Test: atest audio_stringutils_tests
Test: atest mediametrics_tests
Bug: 376579631
Change-Id: Ic28c5f2b6c6cc55579b15300fc5ad80ff40cf673
diff --git a/services/mediametrics/StringUtils.cpp b/services/mediametrics/StringUtils.cpp
index 3b2db85..c4111ae 100644
--- a/services/mediametrics/StringUtils.cpp
+++ b/services/mediametrics/StringUtils.cpp
@@ -19,105 +19,12 @@
 #include <utils/Log.h>
 
 #include "StringUtils.h"
-
+#include "AudioTypes.h"
+#include <audio_utils/StringUtils.h>
 #include <charconv>
 
-#include "AudioTypes.h"
-
 namespace android::mediametrics::stringutils {
 
-std::string tokenizer(std::string::const_iterator& it,
-        const std::string::const_iterator& end, const char *reserved)
-{
-    // consume leading white space
-    for (; it != end && std::isspace(*it); ++it);
-    if (it == end) return {};
-
-    auto start = it;
-    // parse until we hit a reserved keyword or space
-    if (strchr(reserved, *it)) return {start, ++it};
-    for (;;) {
-        ++it;
-        if (it == end || std::isspace(*it) || strchr(reserved, *it)) return {start, it};
-    }
-}
-
-std::vector<std::string> split(const std::string& flags, const char *delim)
-{
-    std::vector<std::string> result;
-    for (auto it = flags.begin(); ; ) {
-        auto flag = tokenizer(it, flags.end(), delim);
-        if (flag.empty() || !std::isalnum(flag[0])) return result;
-        result.emplace_back(std::move(flag));
-
-        // look for the delimeter and discard
-        auto token = tokenizer(it, flags.end(), delim);
-        if (token.size() != 1 || strchr(delim, token[0]) == nullptr) return result;
-    }
-}
-
-bool parseVector(const std::string &str, std::vector<int32_t> *vector) {
-    std::vector<int32_t> values;
-    const char *p = str.c_str();
-    const char *last = p + str.size();
-    while (p != last) {
-        if (*p == ',' || *p == '{' || *p == '}') {
-            p++;
-        }
-        int32_t value = -1;
-        auto [ptr, error] = std::from_chars(p, last, value);
-        if (error == std::errc::invalid_argument || error == std::errc::result_out_of_range) {
-            return false;
-        }
-        p = ptr;
-        values.push_back(value);
-    }
-    *vector = std::move(values);
-    return true;
-}
-
-std::vector<std::pair<std::string, std::string>> getDeviceAddressPairs(const std::string& devices)
-{
-    std::vector<std::pair<std::string, std::string>> result;
-
-    // Currently, the device format is
-    //
-    // devices = device_addr OR device_addr|devices
-    // device_addr = device OR (device, addr)
-    //
-    // EXAMPLE:
-    // device1|(device2, addr2)|...
-
-    static constexpr char delim[] = "()|,";
-    for (auto it = devices.begin(); ; ) {
-        std::string address;
-        std::string device = tokenizer(it, devices.end(), delim);
-        if (device.empty()) return result;
-        if (device == "(") {  // it is a pair otherwise we consider it a device
-            device = tokenizer(it, devices.end(), delim); // get actual device
-            auto token = tokenizer(it, devices.end(), delim);
-            if (token != ",") return result;  // malformed, must have a comma
-
-            // special handling here for empty addresses
-            address = tokenizer(it, devices.end(), delim);
-            if (address.empty()) return result;
-            if (address == ")") {  // no address, just the ")"
-                address.clear();
-            } else {
-                token = tokenizer(it, devices.end(), delim);
-                if (token != ")") return result;
-            }
-        }
-        // misaligned token, device must start alphanumeric.
-        if (!std::isalnum(device[0])) return result;
-
-        result.emplace_back(std::move(device), std::move(address));
-
-        auto token = tokenizer(it, devices.end(), delim);
-        if (token != "|") return result;  // this includes end of string detection
-    }
-}
-
 size_t replace(std::string &str, const char *targetChars, const char replaceChar)
 {
     size_t replaced = 0;
@@ -134,7 +41,7 @@
 std::pair<std::string /* external statsd */, std::string /* internal */>
 parseDevicePairs(const std::string& devicePairs) {
     std::pair<std::string, std::string> result{};
-    const auto devaddrvec = stringutils::getDeviceAddressPairs(devicePairs);
+    const auto devaddrvec = audio_utils::stringutils::getDeviceAddressPairs(devicePairs);
     for (const auto& [device, addr] : devaddrvec) { // addr ignored for now.
         if (!result.second.empty()) {
             result.second.append("|"); // delimit devices with '|'.