summaryrefslogtreecommitdiffstats
path: root/xpcom/string/nsTStringRepr.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xpcom/string/nsTStringRepr.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/xpcom/string/nsTStringRepr.cpp b/xpcom/string/nsTStringRepr.cpp
new file mode 100644
index 0000000000..0dd8eafb34
--- /dev/null
+++ b/xpcom/string/nsTStringRepr.cpp
@@ -0,0 +1,273 @@
+/* -*- 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/. */
+
+#include "nsTStringRepr.h"
+
+#include "double-conversion/string-to-double.h"
+#include "mozilla/FloatingPoint.h"
+#include "nsError.h"
+#include "nsString.h"
+
+namespace mozilla::detail {
+
+template <typename T>
+typename nsTStringRepr<T>::char_type nsTStringRepr<T>::First() const {
+ MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string");
+ return this->mData[0];
+}
+
+template <typename T>
+typename nsTStringRepr<T>::char_type nsTStringRepr<T>::Last() const {
+ MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string");
+ return this->mData[this->mLength - 1];
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const self_type& aStr) const {
+ return this->mLength == aStr.mLength &&
+ char_traits::compare(this->mData, aStr.mData, this->mLength) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const self_type& aStr,
+ comparator_type aComp) const {
+ return this->mLength == aStr.mLength &&
+ aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple) const {
+ return Equals(substring_type(aTuple));
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple,
+ comparator_type aComp) const {
+ return Equals(substring_type(aTuple), aComp);
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const char_type* aData) const {
+ // unfortunately, some callers pass null :-(
+ if (!aData) {
+ MOZ_ASSERT_UNREACHABLE("null data pointer");
+ return this->mLength == 0;
+ }
+
+ // XXX avoid length calculation?
+ size_type length = char_traits::length(aData);
+ return this->mLength == length &&
+ char_traits::compare(this->mData, aData, this->mLength) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::Equals(const char_type* aData,
+ comparator_type aComp) const {
+ // unfortunately, some callers pass null :-(
+ if (!aData) {
+ MOZ_ASSERT_UNREACHABLE("null data pointer");
+ return this->mLength == 0;
+ }
+
+ // XXX avoid length calculation?
+ size_type length = char_traits::length(aData);
+ return this->mLength == length &&
+ aComp(this->mData, aData, this->mLength, length) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::EqualsASCII(const char* aData, size_type aLen) const {
+ return this->mLength == aLen &&
+ char_traits::compareASCII(this->mData, aData, aLen) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::EqualsASCII(const char* aData) const {
+ return char_traits::compareASCIINullTerminated(this->mData, this->mLength,
+ aData) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::EqualsLatin1(const char* aData,
+ const size_type aLength) const {
+ return (this->mLength == aLength) &&
+ char_traits::equalsLatin1(this->mData, aData, aLength);
+}
+
+template <typename T>
+bool nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData,
+ size_type aLen) const {
+ return this->mLength == aLen &&
+ char_traits::compareLowerCaseToASCII(this->mData, aData, aLen) == 0;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData) const {
+ return char_traits::compareLowerCaseToASCIINullTerminated(
+ this->mData, this->mLength, aData) == 0;
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::Find(const string_view& aString,
+ index_type aOffset) const {
+ auto idx = View().find(aString, aOffset);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::LowerCaseFindASCII(const std::string_view& aString,
+ index_type aOffset) const {
+ if (aOffset > Length()) {
+ return kNotFound;
+ }
+ auto begin = BeginReading();
+ auto end = EndReading();
+ auto it =
+ std::search(begin + aOffset, end, aString.begin(), aString.end(),
+ [](char_type l, char r) {
+ MOZ_ASSERT(!(r & ~0x7F), "Unexpected non-ASCII character");
+ MOZ_ASSERT(char_traits::ASCIIToLower(r) == char_type(r),
+ "Search string must be ASCII lowercase");
+ return char_traits::ASCIIToLower(l) == char_type(r);
+ });
+ return it == end ? kNotFound : std::distance(begin, it);
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::RFind(const string_view& aString) const {
+ auto idx = View().rfind(aString);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+typename nsTStringRepr<T>::size_type nsTStringRepr<T>::CountChar(
+ char_type aChar) const {
+ return std::count(BeginReading(), EndReading(), aChar);
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::FindChar(char_type aChar, index_type aOffset) const {
+ auto idx = View().find(aChar, aOffset);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::RFindChar(char_type aChar, int32_t aOffset) const {
+ auto idx = View().rfind(aChar, aOffset != -1 ? aOffset : string_view::npos);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::FindCharInSet(const string_view& aSet,
+ index_type aOffset) const {
+ auto idx = View().find_first_of(aSet, aOffset);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+int32_t nsTStringRepr<T>::RFindCharInSet(const string_view& aSet,
+ int32_t aOffset) const {
+ auto idx =
+ View().find_last_of(aSet, aOffset != -1 ? aOffset : string_view::npos);
+ return idx == string_view::npos ? kNotFound : idx;
+}
+
+template <typename T>
+bool nsTStringRepr<T>::EqualsIgnoreCase(const std::string_view& aString) const {
+ return std::equal(BeginReading(), EndReading(), aString.begin(),
+ aString.end(), [](char_type l, char r) {
+ return char_traits::ASCIIToLower(l) ==
+ char_traits::ASCIIToLower(char_type(r));
+ });
+}
+
+// We can't use the method `StringToDoubleConverter::ToDouble` due to linking
+// issues on Windows as it's in mozglue. Instead, implement the selection logic
+// using an overload set.
+//
+// StringToFloat is used instead of StringToDouble for floats due to differences
+// in rounding behaviour.
+static void StringToFP(
+ const double_conversion::StringToDoubleConverter& aConverter,
+ const char* aData, size_t aLength, int* aProcessed, float* aResult) {
+ *aResult = aConverter.StringToFloat(aData, aLength, aProcessed);
+}
+
+static void StringToFP(
+ const double_conversion::StringToDoubleConverter& aConverter,
+ const char* aData, size_t aLength, int* aProcessed, double* aResult) {
+ *aResult = aConverter.StringToDouble(aData, aLength, aProcessed);
+}
+
+static void StringToFP(
+ const double_conversion::StringToDoubleConverter& aConverter,
+ const char16_t* aData, size_t aLength, int* aProcessed, float* aResult) {
+ *aResult = aConverter.StringToFloat(reinterpret_cast<const uc16*>(aData),
+ aLength, aProcessed);
+}
+
+static void StringToFP(
+ const double_conversion::StringToDoubleConverter& aConverter,
+ const char16_t* aData, size_t aLength, int* aProcessed, double* aResult) {
+ *aResult = aConverter.StringToDouble(reinterpret_cast<const uc16*>(aData),
+ aLength, aProcessed);
+}
+
+template <typename FloatT, typename CharT>
+static FloatT ParseFloatingPoint(const nsTStringRepr<CharT>& aString,
+ bool aAllowTrailingChars,
+ nsresult* aErrorCode) {
+ // Performs conversion to double following the "rules for parsing
+ // floating-point number values" from the HTML standard.
+ // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values
+ //
+ // This behaviour allows for leading spaces, and will not generate infinity or
+ // NaN values except in error conditions.
+ int flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES;
+ if (aAllowTrailingChars) {
+ flags |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+ }
+ double_conversion::StringToDoubleConverter converter(
+ flags, mozilla::UnspecifiedNaN<double>(),
+ mozilla::UnspecifiedNaN<double>(), nullptr, nullptr);
+
+ FloatT result;
+ int processed;
+ StringToFP(converter, aString.Data(), aString.Length(), &processed, &result);
+
+ *aErrorCode = mozilla::IsFinite(result) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
+ return result;
+}
+
+template <typename T>
+double nsTStringRepr<T>::ToDouble(nsresult* aErrorCode) const {
+ return ParseFloatingPoint<double, T>(*this, /* aAllowTrailingChars */ false,
+ aErrorCode);
+}
+
+template <typename T>
+double nsTStringRepr<T>::ToDoubleAllowTrailingChars(
+ nsresult* aErrorCode) const {
+ return ParseFloatingPoint<double, T>(*this, /* aAllowTrailingChars */ true,
+ aErrorCode);
+}
+
+template <typename T>
+float nsTStringRepr<T>::ToFloat(nsresult* aErrorCode) const {
+ return ParseFloatingPoint<float, T>(*this, /* aAllowTrailingChars */ false,
+ aErrorCode);
+}
+
+template <typename T>
+float nsTStringRepr<T>::ToFloatAllowTrailingChars(nsresult* aErrorCode) const {
+ return ParseFloatingPoint<float, T>(*this, /* aAllowTrailingChars */ true,
+ aErrorCode);
+}
+
+} // namespace mozilla::detail
+
+template class mozilla::detail::nsTStringRepr<char>;
+template class mozilla::detail::nsTStringRepr<char16_t>;