[llvm] [llvm] specialize cl::opt_storage for std::string (PR #149172)
Andrew Rogers via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 16 12:57:54 PDT 2025
https://github.com/andrurogerz updated https://github.com/llvm/llvm-project/pull/149172
>From fc308a1028844e0f19f6d548af2d537f03790cb9 Mon Sep 17 00:00:00 2001
From: Andrew Rogers <andrurogerz at gmail.com>
Date: Wed, 16 Jul 2025 09:32:09 -0700
Subject: [PATCH] [llvm] specialize cl::opt_storage for std::string
---
llvm/include/llvm/Support/CommandLine.h | 143 ++++++++++++++++++++++++
llvm/include/llvm/TargetParser/Triple.h | 4 +
2 files changed, 147 insertions(+)
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index adaa75cc6c348..ab16c491e0d2b 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -1390,6 +1390,149 @@ class opt_storage<DataType, false, true> : public DataType {
const OptionValue<DataType> &getDefault() const { return Default; }
};
+// Define a fully-specialized version of opt_storage for std::string. This
+// implementation avoids inheriting from std::string while still being
+// compatible with std::string in common cases.
+//
+template <> class opt_storage<std::string, false, true> {
+ using Self = opt_storage<std::string, false, true>;
+
+public:
+ std::string Value;
+ OptionValue<std::string> Default;
+
+ // Make sure we initialize the value with the default constructor for the
+ // type.
+ opt_storage() : Value(std::string()), Default() {}
+
+ template <class T> void setValue(const T &V, bool initial = false) {
+ Value = static_cast<std::string>(V);
+ if (initial)
+ Default = static_cast<std::string>(V);
+ }
+
+ std::string &getValue() { return Value; }
+ std::string getValue() const { return Value; }
+
+ const OptionValue<std::string> &getDefault() const { return Default; }
+
+ // Support implicit conversions to std::string and LLVM string-like types.
+ operator std::string() const { return Value; }
+ operator llvm::StringRef() const { return llvm::StringRef(Value); }
+ operator llvm::Twine() const { return llvm::Twine(llvm::StringRef(Value)); }
+
+ // If the datatype is a pointer, support -> on it.
+ std::string operator->() const { return Value; }
+
+ template <typename T>
+ std::enable_if_t<std::is_convertible_v<T, std::string_view>, Self &>
+ operator=(const T &rhs) {
+ Value = std::string(rhs);
+ return *this;
+ }
+
+ template <typename T>
+ std::enable_if_t<std::is_convertible_v<T, std::string_view>, std::string &>
+ operator+=(const T &rhs) {
+ return Value += std::string_view(rhs);
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>,
+ std::string>
+ operator+(const Self &lhs, const T &rhs) {
+ return (lhs.Value + std::string_view(rhs)).str();
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>,
+ std::string>
+ operator+(const T &lhs, const Self &rhs) {
+ return (std::string_view(lhs) + rhs.Value).str();
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>, bool>
+ operator==(const Self &lhs, const T &rhs) {
+ return lhs.Value == std::string_view(rhs);
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>, bool>
+ operator==(const T &lhs, const Self &rhs) {
+ return std::string_view(lhs) == rhs.Value;
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>, bool>
+ operator!=(const Self &lhs, const T &rhs) {
+ return lhs.Value != std::string_view(rhs);
+ }
+
+ template <typename T>
+ friend std::enable_if_t<std::is_convertible_v<T, std::string_view>, bool>
+ operator!=(const T &lhs, const Self &rhs) {
+ return std::string_view(lhs) != rhs.Value;
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &os, const Self &str) {
+ return os << str.Value;
+ }
+
+ // Implement a subset of std::string methods
+ size_t size() const noexcept { return Value.size(); };
+ size_t max_size() const noexcept { return Value.max_size(); };
+ size_t length() const noexcept { return Value.length(); };
+ bool empty() const noexcept { return Value.empty(); }
+ void clear() noexcept { Value.clear(); }
+
+ const char *c_str() const { return Value.c_str(); };
+ const char *data() const { return Value.data(); };
+
+ auto begin() noexcept { return Value.begin(); }
+ auto end() noexcept { return Value.end(); }
+ auto begin() const noexcept { return Value.begin(); }
+ auto end() const noexcept { return Value.end(); }
+ auto cbegin() const noexcept { return Value.cbegin(); }
+ auto cend() const noexcept { return Value.cend(); }
+
+ auto rbegin() noexcept { return Value.rbegin(); }
+ auto rend() noexcept { return Value.rend(); }
+ auto rbegin() const noexcept { return Value.rbegin(); }
+ auto rend() const noexcept { return Value.rend(); }
+ auto crbegin() const noexcept { return Value.rbegin(); }
+ auto crend() const noexcept { return Value.rend(); }
+
+ void erase(size_t pos = 0, size_t count = std::string::npos) {
+ Value.erase(pos, count);
+ }
+
+ size_t find(const std::string &str, size_t pos = 0) const {
+ return Value.find(str, pos);
+ }
+
+ size_t find(const char *s, size_t pos = 0) const {
+ return Value.find(s, pos);
+ }
+
+ size_t find(char c, size_t pos = 0) const { return Value.find(c, pos); }
+
+ std::string substr(size_t pos = 0, size_t count = std::string::npos) const {
+ return Value.substr(pos, count);
+ }
+
+ char operator[](size_t pos) const { return Value.at(pos); }
+
+ char &at(size_t pos) { return Value[pos]; }
+ const char &at(size_t pos) const { return Value.at(pos); }
+
+ char &front() { return Value.front(); }
+ const char &front() const { return Value.front(); }
+
+ char &back() { return Value.back(); }
+ const char &back() const { return Value.back(); }
+};
+
// Define a partial specialization to handle things we cannot inherit from. In
// this case, we store an instance through containment, and overload operators
// to get at the value.
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 57d771b80251a..57d4c02d339c1 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -356,6 +356,10 @@ class Triple {
explicit Triple(const std::string &Str) : Triple(std::string(Str)) {}
LLVM_ABI explicit Triple(const Twine &Str);
+ template <typename S, typename = std::enable_if_t<
+ std::is_convertible<S, StringRef>::value>>
+ explicit Triple(const S &Str) : Triple(StringRef(Str)) {}
+
LLVM_ABI Triple(const Twine &ArchStr, const Twine &VendorStr,
const Twine &OSStr);
LLVM_ABI Triple(const Twine &ArchStr, const Twine &VendorStr,
More information about the llvm-commits
mailing list