summaryrefslogtreecommitdiff
path: root/Source/Core/Common/FormatUtil.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/Common/FormatUtil.h')
-rw-r--r--Source/Core/Common/FormatUtil.h35
1 files changed, 35 insertions, 0 deletions
diff --git a/Source/Core/Common/FormatUtil.h b/Source/Core/Common/FormatUtil.h
index 3c0bc3f262..1b33b74256 100644
--- a/Source/Core/Common/FormatUtil.h
+++ b/Source/Core/Common/FormatUtil.h
@@ -38,4 +38,39 @@ constexpr std::size_t CountFmtReplacementFields(std::string_view s)
static_assert(CountFmtReplacementFields("") == 0);
static_assert(CountFmtReplacementFields("{} test {:x}") == 2);
static_assert(CountFmtReplacementFields("{} {{}} test {{{}}}") == 2);
+
+constexpr bool ContainsNonPositionalArguments(std::string_view s)
+{
+ for (std::size_t i = 0; i < s.size(); ++i)
+ {
+ if (s[i] != '{' || i + 1 == s.size())
+ continue;
+
+ const char next = s[i + 1];
+
+ // If the opening brace is followed by another brace, what we have is
+ // an escaped brace, not a replacement field.
+ if (next == '{')
+ {
+ // Skip the second brace.
+ // This ensures that e.g. {{{}}} is counted correctly: when the first brace character
+ // is read and detected as being part of an '{{' escape sequence, the second character
+ // is skipped so the most inner brace (the third character) is not detected
+ // as the end of an '{{' pair.
+ ++i;
+ }
+ else if (next == '}' || next == ':')
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static_assert(!ContainsNonPositionalArguments(""));
+static_assert(ContainsNonPositionalArguments("{}"));
+static_assert(!ContainsNonPositionalArguments("{0}"));
+static_assert(ContainsNonPositionalArguments("{:x}"));
+static_assert(!ContainsNonPositionalArguments("{0:x}"));
+static_assert(!ContainsNonPositionalArguments("{0} {{}} test {{{1}}}"));
} // namespace Common