mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1717448 - Integrate {fmt} with nsString. r=xpcom-reviewers,nika,mccr8
Differential Revision: https://phabricator.services.mozilla.com/D217721
This commit is contained in:
parent
6a1d862d72
commit
661bc320d5
@ -13,6 +13,7 @@ EXPORTS += [
|
||||
"nsCharTraits.h",
|
||||
"nsDependentString.h",
|
||||
"nsDependentSubstring.h",
|
||||
"nsFmtString.h",
|
||||
"nsLiteralString.h",
|
||||
"nsPrintfCString.h",
|
||||
"nsPromiseFlatString.h",
|
||||
|
43
xpcom/string/nsFmtString.h
Normal file
43
xpcom/string/nsFmtString.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFmtCString_h___
|
||||
#define nsFmtCString_h___
|
||||
|
||||
#include <type_traits>
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/xchar.h"
|
||||
#include "nsString.h"
|
||||
|
||||
/**
|
||||
* nsTFmtString lets you create a nsTString using a C++20-style format
|
||||
* string. For example:
|
||||
*
|
||||
* NS_WARNING(nsFmtCString(FMT_STRING("Unexpected value: {}"), 13.917).get());
|
||||
* NS_WARNING(nsFmtString(FMT_STRING(u"Unexpected value: {}"),
|
||||
* u"weird").get());
|
||||
*
|
||||
* nsTFmtString has a small built-in auto-buffer. For larger strings, it
|
||||
* will allocate on the heap.
|
||||
*
|
||||
* See also nsTSubstring::AppendFmt().
|
||||
*/
|
||||
template <typename T>
|
||||
class nsTFmtString : public nsTAutoStringN<T, 16> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit nsTFmtString(
|
||||
fmt::basic_format_string<T, type_identity_t<Args>...> aFormatStr,
|
||||
Args&&... aArgs) {
|
||||
this->AppendFmt(aFormatStr, std::forward<Args>(aArgs)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTFmtString<Char>, Char>
|
||||
: fmt::formatter<nsTString<Char>, Char> {};
|
||||
|
||||
#endif // !defined(nsFmtString_h___)
|
@ -33,6 +33,10 @@ class nsPrintfCString : public nsAutoCStringN<16> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<nsPrintfCString, char> : fmt::formatter<nsCString, char> {
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -61,4 +65,8 @@ class nsVprintfCString : public nsAutoCStringN<16> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<nsVprintfCString, char>
|
||||
: fmt::formatter<nsCString, char> {};
|
||||
|
||||
#endif // !defined(nsPrintfCString_h___)
|
||||
|
@ -58,6 +58,10 @@ class NS_LossyConvertUTF16toASCII : public nsAutoCString {
|
||||
NS_LossyConvertUTF16toASCII(char) = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<NS_LossyConvertUTF16toASCII, char>
|
||||
: fmt::formatter<nsAutoCString, char> {};
|
||||
|
||||
class NS_ConvertASCIItoUTF16 : public nsAutoString {
|
||||
public:
|
||||
explicit NS_ConvertASCIItoUTF16(const char* aCString) {
|
||||
@ -81,6 +85,10 @@ class NS_ConvertASCIItoUTF16 : public nsAutoString {
|
||||
NS_ConvertASCIItoUTF16(char16_t) = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<NS_ConvertASCIItoUTF16, char16_t>
|
||||
: fmt::formatter<nsAutoString, char16_t> {};
|
||||
|
||||
/**
|
||||
* A helper class that converts a UTF-16 string to UTF-8
|
||||
*/
|
||||
@ -108,6 +116,10 @@ class NS_ConvertUTF16toUTF8 : public nsAutoCString {
|
||||
NS_ConvertUTF16toUTF8(char) = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<NS_ConvertUTF16toUTF8, char>
|
||||
: fmt::formatter<nsAutoCString, char> {};
|
||||
|
||||
class NS_ConvertUTF8toUTF16 : public nsAutoString {
|
||||
public:
|
||||
explicit NS_ConvertUTF8toUTF16(const char* aCString) {
|
||||
@ -131,6 +143,10 @@ class NS_ConvertUTF8toUTF16 : public nsAutoString {
|
||||
NS_ConvertUTF8toUTF16(char16_t) = delete;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<NS_ConvertUTF8toUTF16, char16_t>
|
||||
: fmt::formatter<nsAutoString, char16_t> {};
|
||||
|
||||
/**
|
||||
* Converts an integer (signed/unsigned, 32/64bit) to its decimal string
|
||||
* representation and returns it as an nsAutoCString/nsAutoString.
|
||||
|
@ -40,6 +40,8 @@ class nsTDependentString;
|
||||
template <typename T>
|
||||
class nsTDependentSubstring;
|
||||
template <typename T>
|
||||
class nsTFmtString;
|
||||
template <typename T>
|
||||
class nsTPromiseFlatString;
|
||||
template <typename T>
|
||||
class nsTLiteralString;
|
||||
@ -69,6 +71,7 @@ template <size_t N>
|
||||
using nsAutoStringN = nsTAutoStringN<char16_t, N>;
|
||||
using nsDependentString = nsTDependentString<char16_t>;
|
||||
using nsDependentSubstring = nsTDependentSubstring<char16_t>;
|
||||
using nsFmtString = nsTFmtString<char16_t>;
|
||||
using nsPromiseFlatString = nsTPromiseFlatString<char16_t>;
|
||||
using nsStringComparator = nsTStringComparator<char16_t>;
|
||||
using nsLiteralString = nsTLiteralString<char16_t>;
|
||||
@ -84,6 +87,7 @@ template <size_t N>
|
||||
using nsAutoCStringN = nsTAutoStringN<char, N>;
|
||||
using nsDependentCString = nsTDependentString<char>;
|
||||
using nsDependentCSubstring = nsTDependentSubstring<char>;
|
||||
using nsFmtCString = nsTFmtString<char>;
|
||||
using nsPromiseFlatCString = nsTPromiseFlatString<char>;
|
||||
using nsCStringComparator = nsTStringComparator<char>;
|
||||
using nsLiteralCString = nsTLiteralString<char>;
|
||||
|
@ -123,4 +123,8 @@ class nsTDependentString : public nsTString<T> {
|
||||
extern template class nsTDependentString<char>;
|
||||
extern template class nsTDependentString<char16_t>;
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTDependentString<Char>, Char>
|
||||
: fmt::formatter<nsTString<Char>, Char> {};
|
||||
|
||||
#endif
|
||||
|
@ -104,6 +104,10 @@ class nsTDependentSubstring : public nsTSubstring<T> {
|
||||
extern template class nsTDependentSubstring<char>;
|
||||
extern template class nsTDependentSubstring<char16_t>;
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTDependentSubstring<Char>, Char>
|
||||
: fmt::formatter<nsTSubstring<Char>, Char> {};
|
||||
|
||||
template <typename T>
|
||||
inline const nsTDependentSubstring<T> Substring(const nsTSubstring<T>& aStr,
|
||||
size_t aStartPos,
|
||||
|
@ -113,6 +113,10 @@ class nsTLiteralString : public mozilla::detail::nsTStringRepr<T> {
|
||||
extern template class nsTLiteralString<char>;
|
||||
extern template class nsTLiteralString<char16_t>;
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTLiteralString<Char>, Char>
|
||||
: fmt::formatter<mozilla::detail::nsTStringRepr<Char>, Char> {};
|
||||
|
||||
namespace mozilla {
|
||||
constexpr MOZ_IMPLICIT StaticString::StaticString(nsLiteralCString const& str)
|
||||
: mStr(str.get()) {}
|
||||
|
@ -115,6 +115,10 @@ class MOZ_STACK_CLASS nsTPromiseFlatString : public nsTString<T> {
|
||||
extern template class nsTPromiseFlatString<char>;
|
||||
extern template class nsTPromiseFlatString<char16_t>;
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTPromiseFlatString<Char>, Char>
|
||||
: fmt::formatter<nsTString<Char>, Char> {};
|
||||
|
||||
// We template this so that the constructor is chosen based on the type of the
|
||||
// parameter. This allows us to reject attempts to promise a flat flat string.
|
||||
template <class T>
|
||||
|
@ -238,6 +238,10 @@ class nsTString : public nsTSubstring<T> {
|
||||
extern template class nsTString<char>;
|
||||
extern template class nsTString<char16_t>;
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTString<Char>, Char>
|
||||
: fmt::formatter<nsTSubstring<Char>, Char> {};
|
||||
|
||||
/**
|
||||
* nsTAutoStringN
|
||||
*
|
||||
@ -368,6 +372,10 @@ class MOZ_NON_MEMMOVABLE nsTAutoStringN : public nsTString<T> {
|
||||
extern template class nsTAutoStringN<char, 64>;
|
||||
extern template class nsTAutoStringN<char16_t, 64>;
|
||||
|
||||
template <typename Char, size_t N>
|
||||
struct fmt::formatter<nsTAutoStringN<Char, N>, Char>
|
||||
: fmt::formatter<nsTString<Char>, Char> {};
|
||||
|
||||
//
|
||||
// nsAutoString stores pointers into itself which are invalidated when an
|
||||
// nsTArray is resized, so nsTArray must not be instantiated with nsAutoString
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include <string_view>
|
||||
#include <type_traits> // std::enable_if
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/xchar.h"
|
||||
|
||||
#include "mozilla/Char16.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/fallible.h"
|
||||
@ -555,4 +558,15 @@ inline bool operator>(const mozilla::detail::nsTStringRepr<T>& aLhs,
|
||||
return Compare(aLhs, aRhs) > 0;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<mozilla::detail::nsTStringRepr<Char>, Char>
|
||||
: fmt::formatter<basic_string_view<Char>, Char> {
|
||||
template <typename FormatContext>
|
||||
constexpr auto format(const mozilla::detail::nsTStringRepr<Char>& aVal,
|
||||
FormatContext& aCtx) const -> decltype(aCtx.out()) {
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
basic_string_view<Char>{aVal.BeginReading(), aVal.Length()}, aCtx);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -5,12 +5,17 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "double-conversion/double-conversion.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Printf.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
|
||||
#include <iterator>
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/xchar.h"
|
||||
|
||||
#include "nsASCIIMask.h"
|
||||
#include "nsCharTraits.h"
|
||||
#include "nsISupports.h"
|
||||
@ -1089,6 +1094,73 @@ void nsTSubstring<T>::StripCRLF() {
|
||||
StripTaggedASCII(mozilla::ASCIIMask::MaskCRLF());
|
||||
}
|
||||
|
||||
// An adapter type for a `nsTSubstring<T>` to provide a std::string-like
|
||||
// interface for `{fmt}`.
|
||||
template <typename T>
|
||||
class nsTSubstringStdCollectionAdapter {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
explicit nsTSubstringStdCollectionAdapter(nsTSubstring<T>& aString)
|
||||
: mSize(aString.Length()), mHandle(InfallibleBulkWrite(aString)) {}
|
||||
|
||||
~nsTSubstringStdCollectionAdapter() { mHandle.Finish(mSize, false); }
|
||||
|
||||
size_t size() const { return mSize; }
|
||||
void resize(size_t aNewSize) {
|
||||
EnsureCapacity(aNewSize);
|
||||
mSize = aNewSize;
|
||||
// XXX: technically resize should zero-initialize any new bytes to match
|
||||
// std::string.
|
||||
}
|
||||
|
||||
T& operator[](size_t i) {
|
||||
MOZ_RELEASE_ASSERT(i < mSize);
|
||||
return mHandle.Elements()[i];
|
||||
}
|
||||
const T& operator[](size_t i) const {
|
||||
MOZ_RELEASE_ASSERT(i < mSize);
|
||||
return mHandle.Elements()[i];
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureCapacity(size_t aNewCapacity) {
|
||||
if (aNewCapacity > mHandle.Length()) {
|
||||
auto result = mHandle.RestartBulkWrite(aNewCapacity, mSize, false);
|
||||
if (result.isErr()) {
|
||||
::NS_ABORT_OOM(aNewCapacity * sizeof(value_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
static mozilla::BulkWriteHandle<T> InfallibleBulkWrite(
|
||||
nsTSubstring<T>& aString) {
|
||||
size_t length = aString.Length();
|
||||
auto res = aString.BulkWrite(length, length, false);
|
||||
if (res.isErr()) {
|
||||
::NS_ABORT_OOM(length * sizeof(value_type));
|
||||
}
|
||||
return res.unwrap();
|
||||
}
|
||||
|
||||
size_t mSize;
|
||||
mozilla::BulkWriteHandle<T> mHandle;
|
||||
};
|
||||
|
||||
// Mark the collection as contiguous for {fmt} so that the buffer will be used
|
||||
// directly.
|
||||
namespace fmt {
|
||||
template <typename T>
|
||||
struct is_contiguous<nsTSubstringStdCollectionAdapter<T>> : std::true_type {};
|
||||
} // namespace fmt
|
||||
|
||||
template <typename T>
|
||||
void nsTSubstring<T>::AppendVfmt(
|
||||
fmt::basic_string_view<char_type> aFormatStr,
|
||||
fmt::basic_format_args<fmt::buffered_context<char_type>> aArgs) {
|
||||
nsTSubstringStdCollectionAdapter<char_type> adapter{*this};
|
||||
fmt::vformat_to(std::back_inserter(adapter), aFormatStr, aArgs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct MOZ_STACK_CLASS PrintfAppend : public mozilla::PrintfTarget {
|
||||
explicit PrintfAppend(nsTSubstring<T>* aString) : mString(aString) {}
|
||||
|
@ -37,6 +37,12 @@ class nsTString;
|
||||
template <typename T>
|
||||
class nsTSubstring;
|
||||
|
||||
|
||||
template <typename T> struct type_identity {
|
||||
using type = T;
|
||||
};
|
||||
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
@ -731,6 +737,19 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
|
||||
[[nodiscard]] bool AppendASCII(const char* aData, size_type aLength,
|
||||
const fallible_t& aFallible);
|
||||
|
||||
template <typename... Args>
|
||||
void AppendFmt(
|
||||
fmt::basic_format_string<char_type, type_identity_t<Args>...>
|
||||
aFormatStr,
|
||||
Args&&... aArgs) {
|
||||
AppendVfmt(
|
||||
aFormatStr,
|
||||
fmt::make_format_args<fmt::buffered_context<char_type>>(aArgs...));
|
||||
}
|
||||
void AppendVfmt(
|
||||
fmt::basic_string_view<char_type> aFormatStr,
|
||||
fmt::basic_format_args<fmt::buffered_context<char_type>> aArgs);
|
||||
|
||||
// Appends a literal string ("" literal in the 8-bit case and u"" literal
|
||||
// in the 16-bit case) to the string.
|
||||
//
|
||||
@ -1474,4 +1493,8 @@ Span(const nsTSubstring<char16_t>&) -> Span<const char16_t>;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
template <typename Char>
|
||||
struct fmt::formatter<nsTSubstring<Char>, Char>
|
||||
: fmt::formatter<mozilla::detail::nsTStringRepr<Char>, Char> {};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user