[flang-commits] [flang] [llvm] [Flang] Introduce *Value classes with unittests (PR #216958)
Michael Kruse via flang-commits
flang-commits at lists.llvm.org
Wed Sep 16 00:12:49 PDT 2026
================
@@ -0,0 +1,258 @@
+//===-- include/flang/Evaluate/character-value-impl.h -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_EVALUATE_CHARACTER_VALUE_IMPL_H_
+#define FORTRAN_EVALUATE_CHARACTER_VALUE_IMPL_H_
+
+#include "flang/Evaluate/common.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <optional>
+#include <string>
+#include <utility>
+#include <variant>
+
+namespace Fortran::evaluate::value {
+
+class CharacterValueImpl {
+ using Storage =
+ std::variant<std::monostate, std::string, std::u16string, std::u32string>;
+
+public:
+ // rule-of-five
+ ~CharacterValueImpl() = default;
+ CharacterValueImpl(const CharacterValueImpl &) = default;
+ CharacterValueImpl(CharacterValueImpl &&) = default;
+ CharacterValueImpl &operator=(const CharacterValueImpl &) = default;
+ CharacterValueImpl &operator=(CharacterValueImpl &&) = default;
+
+ CharacterValueImpl() = default;
+ explicit CharacterValueImpl(int kind, std::string s) {
+ withCharProto(kind, [&](auto c) {
+ using CharT = std::decay_t<decltype(c)>;
+ using StringT = std::basic_string<CharT>;
+ if (std::is_same_v<StringT, std::string>) {
+ storage_ = std::move(s);
+ } else {
+ StringT buf;
+ buf.resize(s.length());
+ for (auto [i, c] : llvm::enumerate(s)) {
+ buf[i] = c;
+ }
+ storage_ = std::move(buf);
+ }
+ });
+
+ CHECK(this->kind() == kind);
+ }
+
+ explicit CharacterValueImpl(int kind, std::u16string s)
+ : storage_{std::move(s)} {
+ CHECK(kind == 2);
+ CHECK(this->kind() == kind);
+ }
+
+ explicit CharacterValueImpl(int kind, std::u32string s)
+ : storage_{std::move(s)} {
+ CHECK(kind == 4);
+ CHECK(this->kind() == kind);
+ }
+
+ /// Fill constructors: create a string of n copies of the given character.
+ CharacterValueImpl(int kind, std::size_t n, char32_t c);
+
+ static CharacterValueImpl Zero(int kind);
+
+ static CharacterValueImpl FromRawBytes(
+ int kind, const void *raw, size_t byteSize);
+
+ void print(llvm::raw_ostream &os) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+
+ std::optional<llvm::StringRef> AsStringRef() const;
+
+ /// Return the string as std::string if kind==1, or nullopt otherwise.
+ std::optional<std::string> AsStdString() const;
+ std::optional<std::u16string> AsU16String() const;
+ std::optional<std::u32string> AsU32String() const;
+
+ std::string ToStdString() const;
+
+ bool IsNull() const { return storage_.index() == 0; }
+ int kind() const {
+ return withCharProto([](auto ct) { return sizeof(ct); });
+ }
+
+ /// Byte size of one character unit (1, 2, or 4).
+ std::size_t charSize() const;
+
+ /// Number of characters in this string.
+ std::size_t size() const;
+
+ /// String length (synonym for size()).
+ std::size_t length() const { return size(); }
+
+ /// True when the string is empty.
+ bool empty() const { return size() == 0; }
+
+ /// Raw byte pointer to the underlying character data.
+ void *data() { return charData(); }
+ const void *data() const { return charData(); }
+ void *charData();
+ const void *charData() const;
+
+ // Comparison operators
+ Ordering Compare(const CharacterValueImpl &y) const;
+ bool operator<(const CharacterValueImpl &y) const;
+ bool operator<=(const CharacterValueImpl &y) const { return !(y < *this); }
+ bool operator==(const CharacterValueImpl &y) const;
+ bool operator!=(const CharacterValueImpl &y) const { return !(*this == y); }
+ bool operator>=(const CharacterValueImpl &y) const { return !(*this < y); }
+ bool operator>(const CharacterValueImpl &y) const { return y < *this; }
+
+ /// Assign n copies of the given character.
+ void assign(int kind, std::size_t n, char32_t c);
+
+ /// Assign from a raw character pointer and length.
+ void assign(const char *p, std::size_t n) { storage_ = std::string(p, n); }
+ void assign(const char16_t *p, std::size_t n) {
+ storage_ = std::u16string(p, n);
+ }
+ void assign(const char32_t *p, std::size_t n) {
+ storage_ = std::u32string(p, n);
+ }
+
+ /// Erase from position pos to end.
+ void erase(std::size_t pos);
+
+ /// Append n copies of the given character.
+ void append(std::size_t n, char32_t c);
+
+ /// Replace the substring [pos, pos+len) with characters from other.
+ CharacterValueImpl &replace(
+ std::size_t pos, std::size_t len, const CharacterValueImpl &other);
+
+ /// Return a suffix starting at pos.
+ CharacterValueImpl substr(std::size_t pos) const;
+
+ /// Return a substring of len characters starting at pos.
+ CharacterValueImpl substr(std::size_t pos, std::size_t len) const;
+
+ CharacterValueImpl ToAscii(int kind) const;
+
+ /// Reserve storage for at least n characters.
+ void reserve(std::size_t n);
+
+ /// Return the character at position i as char32_t (safe for all kinds).
+ char32_t operator[](std::size_t i) const;
+
+ /// Concatenate two same-kind strings.
+ CharacterValueImpl operator+(const CharacterValueImpl &y) const;
+
+ /// Append another same-kind string.
+ CharacterValueImpl &operator+=(const CharacterValueImpl &y);
+
+ /// Append a character, converting it to the string's element type.
+ CharacterValueImpl &operator+=(char c);
+
+ /// Sentinel value for "not found" positions (same as std::string::npos).
+ static constexpr std::size_t npos{std::string::npos};
+
+ // Find-family methods; return npos when not found.
+ std::size_t find_first_not_of(char c) const {
+ return find_first_not_of(static_cast<char32_t>(c));
+ }
+ std::size_t find_first_not_of(char16_t c) const {
+ return find_first_not_of(static_cast<char32_t>(c));
+ }
+ std::size_t find_first_not_of(char32_t c) const;
+ std::size_t find_last_not_of(char c) const {
+ return find_last_not_of(static_cast<char32_t>(c));
+ }
+ std::size_t find_last_not_of(char16_t c) const {
+ return find_last_not_of(static_cast<char32_t>(c));
+ }
+ std::size_t find_last_not_of(char32_t c) const;
+ std::size_t find_first_not_of(const CharacterValueImpl &set) const;
+ std::size_t find_last_not_of(const CharacterValueImpl &set) const;
+ std::size_t find(const CharacterValueImpl &pattern) const;
+ std::size_t rfind(const CharacterValueImpl &pattern) const;
+ std::size_t find_first_of(const CharacterValueImpl &set) const;
+ std::size_t find_last_of(const CharacterValueImpl &set) const;
+
+ void StoreRawBytes(
+ void *dst, std::size_t size, bool *changed = nullptr) const;
+
+ // Compile-time dispatchers to current/specified kind
+
+ template <typename F>
+ auto withCharProto(F &&f) const
+ -> decltype(std::declval<F>()(std::declval<char>())) {
+ return common::visit(
+ common::visitors{
+ [](std::monostate) -> decltype(f(
+ std::declval<const std::string &>())) {
+ DIE("operation on uninitialized CharacterValueImpl");
+ },
+ [&f](auto s) {
----------------
Meinersbur wrote:
changed to `const auto &s`
https://github.com/llvm/llvm-project/pull/216958
More information about the flang-commits
mailing list