From bd59c889f3fafd874b41606edfa858b7485e712d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@gmail.com>
Date: Mon, 8 Jul 2024 16:00:13 +0200
Subject: [PATCH] util/StringVerify: new library

---
 src/command/OutputCommands.cxx    | 13 ++++-------
 src/command/PartitionCommands.cxx | 13 ++++-------
 src/util/StringVerify.hxx         | 39 +++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 18 deletions(-)
 create mode 100644 src/util/StringVerify.hxx

diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx
index bc1b0d766..663295ba2 100644
--- a/src/command/OutputCommands.cxx
+++ b/src/command/OutputCommands.cxx
@@ -10,6 +10,7 @@
 #include "Partition.hxx"
 #include "IdleFlags.hxx"
 #include "util/CharUtil.hxx"
+#include "util/StringVerify.hxx"
 
 CommandResult
 handle_enableoutput(Client &client, Request args, Response &r)
@@ -62,22 +63,16 @@ handle_toggleoutput(Client &client, Request args, Response &r)
 	return CommandResult::OK;
 }
 
-static bool
+static constexpr bool
 IsValidAttributeNameChar(char ch) noexcept
 {
 	return IsAlphaNumericASCII(ch) || ch == '_';
 }
 
-[[gnu::pure]]
-static bool
+static constexpr bool
 IsValidAttributeName(const char *s) noexcept
 {
-	do {
-		if (!IsValidAttributeNameChar(*s))
-			return false;
-	} while (*++s);
-
-	return true;
+	return CheckCharsNonEmpty(s, IsValidAttributeNameChar);
 }
 
 CommandResult
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index 79825dd7a..e45316e96 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -10,6 +10,7 @@
 #include "client/Client.hxx"
 #include "client/Response.hxx"
 #include "util/CharUtil.hxx"
+#include "util/StringVerify.hxx"
 
 #include <fmt/format.h>
 
@@ -39,21 +40,15 @@ handle_listpartitions(Client &client, Request, Response &r)
 }
 
 static constexpr bool
-IsValidPartitionChar(char ch)
+IsValidPartitionChar(char ch) noexcept
 {
 	return IsAlphaNumericASCII(ch) || ch == '-' || ch == '_';
 }
 
-[[gnu::pure]]
-static bool
+static constexpr bool
 IsValidPartitionName(const char *name) noexcept
 {
-	do {
-		if (!IsValidPartitionChar(*name))
-			return false;
-	} while (*++name != 0);
-
-	return true;
+	return CheckCharsNonEmpty(name, IsValidPartitionChar);
 }
 
 [[gnu::pure]]
diff --git a/src/util/StringVerify.hxx b/src/util/StringVerify.hxx
new file mode 100644
index 000000000..e177f4a15
--- /dev/null
+++ b/src/util/StringVerify.hxx
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: BSD-2-Clause
+// Copyright CM4all GmbH
+// author: Max Kellermann <mk@cm4all.com>
+
+#pragma once
+
+#include <algorithm>
+#include <concepts>
+#include <string_view>
+
+/**
+ * Does the given string consist only of characters allowed by the
+ * given function?
+ */
+constexpr bool
+CheckChars(std::string_view s, std::predicate<char> auto f) noexcept
+{
+	return std::all_of(s.begin(), s.end(), f);
+}
+
+/**
+ * Is the given string non-empty and consists only of characters
+ * allowed by the given function?
+ */
+constexpr bool
+CheckCharsNonEmpty(std::string_view s, std::predicate<char> auto f) noexcept
+{
+	return !s.empty() && CheckChars(s, f);
+}
+
+constexpr bool
+CheckCharsNonEmpty(const char *s, std::predicate<char> auto f) noexcept
+{
+	do {
+		if (!f(*s))
+			return false;
+	} while (*++s);
+	return true;
+}