/* * (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2004-2023 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #pragma once // This file would be called String.h, but that conflicts with // on systems without case-sensitive file systems. #include #include #include #include #include #include #ifdef __OBJC__ #include #include #endif #if OS(WINDOWS) #include #endif namespace WTF { // Declarations of string operations WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE double charactersToDouble(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE double charactersToFixedDouble(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE double charactersToFixedDouble(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE float charactersToFloat(std::span, bool* ok = nullptr); WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); WTF_EXPORT_PRIVATE float charactersToFloat(std::span, size_t& parsedLength); template bool NODELETE containsOnly(std::span); inline const String& nullString(); enum class TrailingZerosPolicy : bool { Keep, Truncate }; class String final { WTF_DEPRECATED_MAKE_FAST_ALLOCATED(String); public: // Construct a null string, distinguishable from an empty string. String() = default; // Construct a string with UTF-16 data. WTF_EXPORT_PRIVATE String(std::span characters); // Construct a string with Latin-1 data. WTF_EXPORT_PRIVATE String(std::span characters); ALWAYS_INLINE static String fromLatin1(const char* characters) { return String { characters }; } ALWAYS_INLINE static String fromLatin1(std::span characters) { return String { characters }; } // Construct a string with UTF-8 data, null string if it contains invalid UTF-8 sequences. WTF_EXPORT_PRIVATE String(std::span); String(const char8_t* characters) : String(unsafeSpan(characters)) { } // Construct a string from a CString that knows its encoding, decoding it as that encoding. // Unlike CString, which would have to be decoded by the caller, and unlike fromUTF8(), which // will happily reinterpret Latin-1 bytes as UTF-8, the character type picks the decoding. template String(const CStringWithEncoding&); // Construct a string referencing an existing StringImpl. String(StringImpl&); String(StringImpl*); String(Ref&&); String(RefPtr&&); String(ExternalStringImpl&); String(ExternalStringImpl*); String(Ref&&); String(RefPtr&&); String(Ref&&); String(RefPtr&&); String(StaticStringImpl&); String(StaticStringImpl*); // Construct a string from a constant string literal. String(ASCIILiteral); String(const String&) = default; String(String&&) = default; String& operator=(const String&) = default; String& operator=(String&&) = default; ALWAYS_INLINE ~String() = default; void swap(String& o) { m_impl.swap(o.m_impl); } static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTF::move(buffer)); } static String adopt(StringBuffer&& buffer) { return StringImpl::adopt(WTF::move(buffer)); } template static String adopt(Vector&& vector) { return StringImpl::adopt(WTF::move(vector)); } bool isNull() const { return !m_impl; } bool isEmpty() const { return !m_impl || m_impl->isEmpty(); } StringImpl* impl() const LIFETIME_BOUND { return m_impl.get(); } RefPtr releaseImpl() { return WTF::move(m_impl); } unsigned length() const { return m_impl ? m_impl->length() : 0; } std::span span8() const LIFETIME_BOUND { return m_impl ? m_impl->span8() : std::span(); } std::span span16() const LIFETIME_BOUND { return m_impl ? m_impl->span16() : std::span(); } // Return span8() or span16() depending on CharacterType. template std::span span() const LIFETIME_BOUND; bool is8Bit() const { return !m_impl || m_impl->is8Bit(); } unsigned sizeInBytes() const { return m_impl ? m_impl->length() * (is8Bit() ? sizeof(Latin1Character) : sizeof(char16_t)) : 0; } WTF_EXPORT_PRIVATE ASCIICString ascii() const; WTF_EXPORT_PRIVATE Latin1CString latin1() const; WTF_EXPORT_PRIVATE UTF8CString utf8(ConversionMode = LenientConversion) const; template std::expected>, UTF8ConversionError> tryGetUTF8(NOESCAPE const Func&, ConversionMode = LenientConversion) const; WTF_EXPORT_PRIVATE std::expected tryGetUTF8(ConversionMode) const; WTF_EXPORT_PRIVATE std::expected tryGetUTF8() const; char16_t codeUnitAt(unsigned index) const; char16_t operator[](unsigned index) const { return codeUnitAt(index); } WTF_EXPORT_PRIVATE static String NODELETE number(int); WTF_EXPORT_PRIVATE static String NODELETE number(unsigned); WTF_EXPORT_PRIVATE static String number(long); WTF_EXPORT_PRIVATE static String number(unsigned long); WTF_EXPORT_PRIVATE static String number(long long); WTF_EXPORT_PRIVATE static String number(unsigned long long); WTF_EXPORT_PRIVATE static String number(float); WTF_EXPORT_PRIVATE static String number(double); WTF_EXPORT_PRIVATE static String numberToStringFixedPrecision(float, unsigned precision = 6, TrailingZerosPolicy = TrailingZerosPolicy::Truncate); WTF_EXPORT_PRIVATE static String numberToStringFixedPrecision(double, unsigned precision = 6, TrailingZerosPolicy = TrailingZerosPolicy::Truncate); WTF_EXPORT_PRIVATE static String numberToStringFixedWidth(double, unsigned decimalPlaces); AtomString toExistingAtomString() const; // Find a single character or string, also with match function & latin1 forms. size_t find(char16_t character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } size_t find(Latin1Character character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } size_t find(char character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; } size_t NODELETE find(StringView) const; size_t NODELETE find(StringView, unsigned start) const; size_t NODELETE findIgnoringASCIICase(StringView) const; size_t NODELETE findIgnoringASCIICase(StringView, unsigned start) const; template requires (std::is_invocable_r_v) size_t find(CodeUnitMatchFunction matchFunction, unsigned start = 0) const { return m_impl ? m_impl->find(matchFunction, start) : notFound; } size_t find(ASCIILiteral literal, unsigned start = 0) const { return m_impl ? m_impl->find(literal, start) : notFound; } // Find the last instance of a single character or string. size_t reverseFind(char16_t character, unsigned start = MaxLength) const { return m_impl ? m_impl->reverseFind(character, start) : notFound; } size_t reverseFind(ASCIILiteral literal, unsigned start = MaxLength) const { return m_impl ? m_impl->reverseFind(literal, start) : notFound; } size_t reverseFind(StringView, unsigned start = MaxLength) const; WTF_EXPORT_PRIVATE std::expected, UTF8ConversionError> charactersWithNullTermination() const; WTF_EXPORT_PRIVATE std::expected, UTF8ConversionError> charactersWithoutNullTermination() const; WTF_EXPORT_PRIVATE char32_t NODELETE codePointAt(unsigned) const; bool contains(char16_t character) const { return find(character) != notFound; } bool contains(ASCIILiteral literal) const { return find(literal) != notFound; } bool NODELETE contains(StringView) const; template requires (std::is_invocable_r_v) bool contains(CodeUnitMatchFunction matchFunction) const { return find(matchFunction, 0) != notFound; } bool NODELETE containsIgnoringASCIICase(StringView) const; bool NODELETE containsIgnoringASCIICase(StringView, unsigned start) const; bool NODELETE startsWith(StringView) const; bool NODELETE startsWithIgnoringASCIICase(StringView) const; bool startsWith(char16_t character) const { return m_impl && m_impl->startsWith(character); } bool NODELETE hasInfixStartingAt(StringView prefix, unsigned start) const; bool NODELETE endsWith(StringView) const; bool NODELETE endsWithIgnoringASCIICase(StringView) const; bool endsWith(char16_t character) const { return m_impl && m_impl->endsWith(character); } bool endsWith(char character) const { return endsWith(static_cast(character)); } bool NODELETE hasInfixEndingAt(StringView suffix, unsigned end) const; [[nodiscard]] String substring(unsigned position, unsigned length = MaxLength) const; [[nodiscard]] WTF_EXPORT_PRIVATE String substringSharingImpl(unsigned position, unsigned length = MaxLength) const; [[nodiscard]] String left(unsigned length) const { return substring(0, length); } [[nodiscard]] String right(unsigned length) const { return substring(this->length() - length, length); } [[nodiscard]] WTF_EXPORT_PRIVATE String convertToASCIILowercase() const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToASCIIUppercase() const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToLowercaseWithoutLocale() const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned) const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToLowercaseWithoutLocaleStartingAtFailingIndex16Bit(unsigned) const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToUppercaseWithoutLocale() const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToUppercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned failingIndex) const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToUppercaseWithoutLocaleStartingAtFailingIndex16Bit(unsigned failingIndex) const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToLowercaseWithLocale(const AtomString& localeIdentifier) const; [[nodiscard]] WTF_EXPORT_PRIVATE String convertToUppercaseWithLocale(const AtomString& localeIdentifier) const; [[nodiscard]] WTF_EXPORT_PRIVATE String simplifyWhiteSpace(CodeUnitMatchFunction) const; [[nodiscard]] WTF_EXPORT_PRIVATE String trim(CodeUnitMatchFunction) const; template [[nodiscard]] String removeCharacters(const Predicate&) const; // Returns the string with case folded for case insensitive comparison. // Use convertToASCIILowercase instead if ASCII case insensitive comparison is desired. [[nodiscard]] WTF_EXPORT_PRIVATE String foldCase() const; // Returns an uninitialized string. The characters needs to be written // into the buffer returned in data before the returned string is used. static String createUninitialized(unsigned length, std::span& data) { return StringImpl::createUninitialized(length, data); } static String createUninitialized(unsigned length, std::span& data) { return StringImpl::createUninitialized(length, data); } static String tryCreateUninitialized(size_t length, std::span& data) { RefPtr impl = StringImpl::tryCreateUninitialized(length, data); if (!impl) [[unlikely]] return nullString(); return impl; } static String tryCreateUninitialized(size_t length, std::span& data) { RefPtr impl = StringImpl::tryCreateUninitialized(length, data); if (!impl) [[unlikely]] return nullString(); return impl; } using SplitFunctor = WTF::Function; WTF_EXPORT_PRIVATE void split(char16_t separator, NOESCAPE const SplitFunctor&) const; [[nodiscard]] WTF_EXPORT_PRIVATE Vector split(char16_t separator) const; [[nodiscard]] WTF_EXPORT_PRIVATE Vector split(StringView separator) const; WTF_EXPORT_PRIVATE void splitAllowingEmptyEntries(char16_t separator, NOESCAPE const SplitFunctor&) const; [[nodiscard]] WTF_EXPORT_PRIVATE Vector splitAllowingEmptyEntries(char16_t separator) const; [[nodiscard]] WTF_EXPORT_PRIVATE Vector splitAllowingEmptyEntries(StringView separator) const; WTF_EXPORT_PRIVATE double toDouble(bool* ok = nullptr) const; WTF_EXPORT_PRIVATE float toFloat(bool* ok = nullptr) const; [[nodiscard]] WTF_EXPORT_PRIVATE String isolatedCopy() const &; [[nodiscard]] WTF_EXPORT_PRIVATE String isolatedCopy() &&; WTF_EXPORT_PRIVATE bool NODELETE isSafeToSendToAnotherThread() const; // Prevent Strings from being implicitly convertable to bool as it will be ambiguous on any platform that // allows implicit conversion to another pointer type (e.g., Mac allows implicit conversion to NSString *). typedef struct ImplicitConversionFromWTFStringToBoolDisallowedA* (String::*UnspecifiedBoolTypeA); typedef struct ImplicitConversionFromWTFStringToBoolDisallowedB* (String::*UnspecifiedBoolTypeB); operator UnspecifiedBoolTypeA() const; operator UnspecifiedBoolTypeB() const; #if USE(CF) WTF_EXPORT_PRIVATE String(CFStringRef); WTF_EXPORT_PRIVATE RetainPtr createCFString() const; #endif #if USE(FOUNDATION) && defined(__OBJC__) String(NSString *string) : String((__bridge CFStringRef)string) { } // This conversion converts the null string to an empty NSString rather than to nil. // Given Cocoa idioms, this is a more useful default. Clients that need to preserve the // null string can check isNull explicitly. RetainPtr createNSString() const; #endif #if OS(WINDOWS) String(const wchar_t* characters, unsigned length) : String({ ucharFrom(characters), length }) { } String(const wchar_t* characters) : String({ ucharFrom(characters), static_cast(characters ? wcslen(characters) : 0) }) { } WTF_EXPORT_PRIVATE Vector wideCharacters() const; #endif WTF_EXPORT_PRIVATE static String make8Bit(std::span); WTF_EXPORT_PRIVATE void convertTo16Bit(); // String::fromUTF8 will return a null string if the input data contains invalid UTF-8 sequences. // FIXME: Deprecated: Use constructor that takes span. WTF_EXPORT_PRIVATE static String fromUTF8(std::span); static String fromUTF8(std::span characters) { return byteCast(characters); } static String fromUTF8(std::span characters) { return byteCast(characters); } static String fromUTF8(const char* string) { return byteCast(unsafeSpan(string)); } // Convert each invalid UTF-8 sequence into a replacement character. WTF_EXPORT_PRIVATE static String fromUTF8ReplacingInvalidSequences(std::span); static String fromUTF8ReplacingInvalidSequences(std::span characters) { return fromUTF8ReplacingInvalidSequences(byteCast(characters)); } // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8. // FIXME: Deprecated: Use fromUTF8ReplacingInvalidSequences. WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(std::span); static String fromUTF8WithLatin1Fallback(std::span characters) { return fromUTF8WithLatin1Fallback(byteCast(characters)); } static String fromUTF8WithLatin1Fallback(std::span characters) { return fromUTF8WithLatin1Fallback(byteCast(characters)); } WTF_EXPORT_PRIVATE static String fromCodePoint(char32_t codePoint); // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3. std::optional defaultWritingDirection() const; bool containsOnlyASCII() const { SUPPRESS_UNCOUNTED_ARG return !m_impl || m_impl->containsOnlyASCII(); } bool containsOnlyLatin1() const { SUPPRESS_UNCOUNTED_ARG return !m_impl || m_impl->containsOnlyLatin1(); } template bool containsOnly() const { SUPPRESS_UNCOUNTED_ARG return !m_impl || m_impl->containsOnly(); } // Hash table deleted values, which are only constructed and never copied or destroyed. String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } unsigned hash() const { return isNull() ? 0 : impl()->hash(); } unsigned existingHash() const { return isNull() ? 0 : impl()->existingHash(); } #ifndef NDEBUG WTF_EXPORT_PRIVATE void show() const; #endif // Turns this String empty if the StringImpl is not referenced by anyone else. // This is useful for clearing String-based caches. void clearImplIfNotShared(); static constexpr unsigned MaxLength = StringImpl::MaxLength; private: template void splitInternal(char16_t separator, NOESCAPE const SplitFunctor&) const; template Vector splitInternal(char16_t separator) const; template Vector splitInternal(StringView separator) const; // These are intentionally private, because `char` carries no encoding. // Use fromLatin1() / fromUTF8() / String(ASCIILiteral) instead. WTF_EXPORT_PRIVATE explicit String(const char* characters); WTF_EXPORT_PRIVATE explicit String(std::span characters); RefPtr m_impl; } SWIFT_ESCAPABLE; static_assert(sizeof(String) == sizeof(void*), "String should effectively be a pointer to a StringImpl, and efficient to pass by value"); inline bool operator==(const String& a, const String& b) { return equal(a.impl(), b.impl()); } inline bool operator==(const String& a, ASCIILiteral b) { return equal(a.impl(), b); } template inline bool operator==(const String& a, const Vector& b) { return b == a; } bool NODELETE equalIgnoringASCIICase(const String&, const String&); bool NODELETE equalIgnoringASCIICase(const String&, ASCIILiteral); bool equalLettersIgnoringASCIICase(const String&, ASCIILiteral); bool startsWithLettersIgnoringASCIICase(const String&, ASCIILiteral); inline bool equalIgnoringNullity(const String& a, const String& b) { return equalIgnoringNullity(a.impl(), b.impl()); } template inline bool equalIgnoringNullity(const Vector& a, const String& b) { return equalIgnoringNullity(a, b.impl()); } inline bool operator!(const String& string) { return string.isNull(); } inline void swap(String& a, String& b) { a.swap(b); } #ifdef __OBJC__ // Used in a small number of places where the long standing behavior has been "nil if empty". RetainPtr nsStringNilIfEmpty(const String&); // Used in a small number of places where null strings should be converted to nil but empty strings should be maintained. RetainPtr nsStringNilIfNull(const String&); #endif // Shared global empty and null string. struct StaticString { constexpr StaticString(StringImpl::StaticStringImpl* pointer) : m_pointer(pointer) { } StringImpl::StaticStringImpl* m_pointer; }; static_assert(sizeof(String) == sizeof(StaticString), "String and StaticString must be the same size!"); extern WTF_EXPORT_PRIVATE const StaticString nullStringData; extern WTF_EXPORT_PRIVATE const StaticString emptyStringData; inline const String& nullString() { SUPPRESS_MEMORY_UNSAFE_CAST return *reinterpret_cast(&nullStringData); } inline const String& emptyString() { SUPPRESS_MEMORY_UNSAFE_CAST return *reinterpret_cast(&emptyStringData); } template struct DefaultHash; template<> struct DefaultHash; template<> struct VectorTraits : VectorTraitsBase { static constexpr bool canInitializeWithMemset = true; static constexpr bool canMoveWithMemcpy = true; }; template<> struct IntegerToStringConversionTrait { using ReturnType = String; using AdditionalArgumentType = void; static String flush(std::span characters, void*) { return characters; } }; template<> struct MarkableTraits { static bool isEmptyValue(const String& string) { return string.isNull(); } static String emptyValue() { return nullString(); } }; #ifdef __OBJC__ WTF_EXPORT_PRIVATE RetainPtr makeNSArrayElement(const String&); WTF_EXPORT_PRIVATE std::optional makeVectorElement(const String*, id); #endif #if USE(CF) WTF_EXPORT_PRIVATE RetainPtr makeCFArrayElement(const String&); WTF_EXPORT_PRIVATE std::optional makeVectorElement(const String*, CFStringRef); #endif // Definitions of string operations inline String::String(StringImpl& string) : m_impl(&string) { } inline String::String(StringImpl* string) : m_impl(string) { } inline String::String(Ref&& string) : m_impl(WTF::move(string)) { } inline String::String(RefPtr&& string) : m_impl(WTF::move(string)) { } inline String::String(Ref&& string) : m_impl(WTF::move(string)) { } inline String::String(RefPtr&& string) : m_impl(WTF::move(string)) { } inline String::String(StaticStringImpl& string) : m_impl(reinterpret_cast(&string)) { } inline String::String(StaticStringImpl* string) : m_impl(reinterpret_cast(string)) { } template inline String::String(const CStringWithEncoding& string) : String(string.span()) { } inline String::String(ASCIILiteral characters) : m_impl(characters.isNull() ? nullptr : RefPtr { StringImpl::create(characters) }) { } inline String::String(ExternalStringImpl& string) : m_impl(&string) { } inline String::String(ExternalStringImpl* string) : m_impl(string) { } inline String::String(Ref&& string) : m_impl(WTF::move(string)) { } inline String::String(RefPtr&& string) : m_impl(WTF::move(string)) { } template<> inline std::span String::span() const LIFETIME_BOUND { return span8(); } template<> inline std::span String::span() const LIFETIME_BOUND { return span16(); } inline char16_t String::codeUnitAt(unsigned index) const { if (!m_impl || index >= m_impl->length()) return 0; return m_impl->at(index); } [[nodiscard]] inline String makeStringByReplacingAll(const String& string, char16_t target, char16_t replacement) { if (auto impl = string.impl()) return String { impl->replace(target, replacement) }; return string; } [[nodiscard]] ALWAYS_INLINE String makeStringByReplacingAll(const String& string, char16_t target, ASCIILiteral literal) { if (auto impl = string.impl()) return String { impl->replace(target, literal.span8()) }; return string; } [[nodiscard]] WTF_EXPORT_PRIVATE String makeStringByRemoving(const String&, unsigned position, unsigned lengthToRemove); WTF_EXPORT_PRIVATE String makeStringByJoining(std::span strings, const String& separator); inline std::optional String::defaultWritingDirection() const { if (m_impl) SUPPRESS_UNCOUNTED_ARG return m_impl->defaultWritingDirection(); return std::nullopt; } inline void String::clearImplIfNotShared() { if (m_impl && m_impl->hasOneRef()) m_impl = nullptr; } inline String String::substring(unsigned position, unsigned length) const { if (!m_impl) return { }; if (!position && length >= m_impl->length()) return *this; SUPPRESS_UNCOUNTED_ARG return m_impl->substring(position, length); } template inline std::expected>, UTF8ConversionError> String::tryGetUTF8(NOESCAPE const Func& function, ConversionMode mode) const { if (!m_impl) return function(nonNullEmptyUTF8Span()); SUPPRESS_UNCOUNTED_ARG return m_impl->tryGetUTF8(function, mode); } #if USE(FOUNDATION) && defined(__OBJC__) inline RetainPtr String::createNSString() const { if (RefPtr impl = m_impl) return impl->createNSString(); return @""; } inline RetainPtr nsStringNilIfEmpty(const String& string) { if (string.isEmpty()) return nil; return string.impl()->createNSString(); } inline RetainPtr nsStringNilIfNull(const String& string) { if (string.isNull()) return nil; return string.impl()->createNSString(); } #endif template String String::removeCharacters(const Predicate& findMatch) const { SUPPRESS_UNCOUNTED_ARG return m_impl ? m_impl->removeCharacters(findMatch) : String { }; } inline bool equalLettersIgnoringASCIICase(const String& string, ASCIILiteral literal) { return equalLettersIgnoringASCIICase(string.impl(), literal); } inline bool NODELETE equalIgnoringASCIICase(const String& a, const String& b) { return equalIgnoringASCIICase(a.impl(), b.impl()); } inline bool NODELETE equalIgnoringASCIICase(const String& a, ASCIILiteral b) { return equalIgnoringASCIICase(a.impl(), b); } inline bool startsWithLettersIgnoringASCIICase(const String& string, ASCIILiteral literal) { return startsWithLettersIgnoringASCIICase(string.impl(), literal); } inline namespace StringLiterals { inline String operator""_str(const char* characters, size_t) { return ASCIILiteral::fromLiteralUnsafe(characters); } inline String operator""_str(const char16_t* characters, size_t length) { return String(unsafeMakeSpan(characters, length)); } } // inline StringLiterals } // namespace WTF using WTF::TrailingZerosPolicy; using WTF::String; using WTF::charactersToDouble; using WTF::charactersToFixedDouble; using WTF::charactersToFloat; using WTF::emptyString; using WTF::makeStringByJoining; using WTF::makeStringByRemoving; using WTF::makeStringByReplacingAll; using WTF::nullString; using WTF::equal; using WTF::find; using WTF::containsOnly; using WTF::reverseFind; #include