Simplify fillMessageArgs
The aforementioned function does a lot of reconstruction of strings as
args are filled in. This results in the end of the string being copied
many times (N). Replace the algorithm with one that builds a new
string, using reserve (which is good practice) and is also capable of
returning errors in the case of bad entries. fillMessageArgs now
returns a string instead of trying to do things in place, which avoids
the initial std::string construction, so we should be net the same here.
Given this new algorithm can now detect failures in parsing (ie, trying
to parse %1 with no arguments) add unit tests for coverage of that, and
modify event manager slightly to handle errors.
Tested: Unit tests pass. Pretty good coverage of this stuff.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I16f28a2ac78580fb35266561f5ae38078b471989
diff --git a/redfish-core/include/registries.hpp b/redfish-core/include/registries.hpp
index a995d76..4247aa8 100644
--- a/redfish-core/include/registries.hpp
+++ b/redfish-core/include/registries.hpp
@@ -16,7 +16,10 @@
#pragma once
#include <array>
+#include <charconv>
#include <cstddef>
+#include <iostream>
+#include <numeric>
#include <span>
#include <string>
#include <string_view>
@@ -50,20 +53,40 @@
};
using MessageEntry = std::pair<const char*, const Message>;
-inline void fillMessageArgs(const std::span<const std::string_view> messageArgs,
- std::string& msg)
+inline std::string
+ fillMessageArgs(const std::span<const std::string_view> messageArgs,
+ std::string_view msg)
{
- int i = 0;
- for (const std::string_view& messageArg : messageArgs)
+ std::string ret;
+ size_t reserve = msg.size();
+ for (const std::string_view& arg : messageArgs)
{
- std::string argStr = "%" + std::to_string(i + 1);
- size_t argPos = msg.find(argStr);
- if (argPos != std::string::npos)
- {
- msg.replace(argPos, argStr.length(), messageArg);
- }
- i++;
+ reserve += arg.size();
}
+ ret.reserve(reserve);
+
+ for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos;
+ stringIndex = msg.find('%'))
+ {
+ ret += msg.substr(0, stringIndex);
+ msg.remove_prefix(stringIndex + 1);
+ size_t number = 0;
+ auto it = std::from_chars(msg.data(), &*msg.end(), number);
+ if (it.ec != std::errc())
+ {
+ return "";
+ }
+ msg.remove_prefix(1);
+ // Redfish message args are 1 indexed.
+ number--;
+ if (number >= messageArgs.size())
+ {
+ return "";
+ }
+ ret += messageArgs[number];
+ }
+ ret += msg;
+ return ret;
}
} // namespace redfish::registries