Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / xpcom / string / nsTStringRepr.cpp
blob405696fd2b6be2bdc17bb7b49a1ecf35f741ffa0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTStringRepr.h"
9 #include "double-conversion/string-to-double.h"
10 #include "mozilla/FloatingPoint.h"
11 #include "nsError.h"
12 #include "nsString.h"
14 namespace mozilla::detail {
16 template <typename T>
17 typename nsTStringRepr<T>::char_type nsTStringRepr<T>::First() const {
18 MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string");
19 return this->mData[0];
22 template <typename T>
23 typename nsTStringRepr<T>::char_type nsTStringRepr<T>::Last() const {
24 MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string");
25 return this->mData[this->mLength - 1];
28 template <typename T>
29 bool nsTStringRepr<T>::Equals(const self_type& aStr) const {
30 return this->mLength == aStr.mLength &&
31 char_traits::compare(this->mData, aStr.mData, this->mLength) == 0;
34 template <typename T>
35 bool nsTStringRepr<T>::Equals(const self_type& aStr,
36 comparator_type aComp) const {
37 return this->mLength == aStr.mLength &&
38 aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0;
41 template <typename T>
42 bool nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple) const {
43 return Equals(substring_type(aTuple));
46 template <typename T>
47 bool nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple,
48 comparator_type aComp) const {
49 return Equals(substring_type(aTuple), aComp);
52 template <typename T>
53 bool nsTStringRepr<T>::Equals(const char_type* aData) const {
54 // unfortunately, some callers pass null :-(
55 if (!aData) {
56 MOZ_ASSERT_UNREACHABLE("null data pointer");
57 return this->mLength == 0;
60 // XXX avoid length calculation?
61 size_type length = char_traits::length(aData);
62 return this->mLength == length &&
63 char_traits::compare(this->mData, aData, this->mLength) == 0;
66 template <typename T>
67 bool nsTStringRepr<T>::Equals(const char_type* aData,
68 comparator_type aComp) const {
69 // unfortunately, some callers pass null :-(
70 if (!aData) {
71 MOZ_ASSERT_UNREACHABLE("null data pointer");
72 return this->mLength == 0;
75 // XXX avoid length calculation?
76 size_type length = char_traits::length(aData);
77 return this->mLength == length &&
78 aComp(this->mData, aData, this->mLength, length) == 0;
81 template <typename T>
82 bool nsTStringRepr<T>::EqualsASCII(const char* aData, size_type aLen) const {
83 return this->mLength == aLen &&
84 char_traits::compareASCII(this->mData, aData, aLen) == 0;
87 template <typename T>
88 bool nsTStringRepr<T>::EqualsASCII(const char* aData) const {
89 return char_traits::compareASCIINullTerminated(this->mData, this->mLength,
90 aData) == 0;
93 template <typename T>
94 bool nsTStringRepr<T>::EqualsLatin1(const char* aData,
95 const size_type aLength) const {
96 return (this->mLength == aLength) &&
97 char_traits::equalsLatin1(this->mData, aData, aLength);
100 template <typename T>
101 bool nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData,
102 size_type aLen) const {
103 return this->mLength == aLen &&
104 char_traits::compareLowerCaseToASCII(this->mData, aData, aLen) == 0;
107 template <typename T>
108 bool nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData) const {
109 return char_traits::compareLowerCaseToASCIINullTerminated(
110 this->mData, this->mLength, aData) == 0;
113 template <typename T>
114 int32_t nsTStringRepr<T>::Find(const string_view& aString,
115 index_type aOffset) const {
116 auto idx = View().find(aString, aOffset);
117 return idx == string_view::npos ? kNotFound : idx;
120 template <typename T>
121 int32_t nsTStringRepr<T>::LowerCaseFindASCII(const std::string_view& aString,
122 index_type aOffset) const {
123 if (aOffset > Length()) {
124 return kNotFound;
126 auto begin = BeginReading();
127 auto end = EndReading();
128 auto it =
129 std::search(begin + aOffset, end, aString.begin(), aString.end(),
130 [](char_type l, char r) {
131 MOZ_ASSERT(!(r & ~0x7F), "Unexpected non-ASCII character");
132 MOZ_ASSERT(char_traits::ASCIIToLower(r) == char_type(r),
133 "Search string must be ASCII lowercase");
134 return char_traits::ASCIIToLower(l) == char_type(r);
136 return it == end ? kNotFound : std::distance(begin, it);
139 template <typename T>
140 int32_t nsTStringRepr<T>::RFind(const string_view& aString) const {
141 auto idx = View().rfind(aString);
142 return idx == string_view::npos ? kNotFound : idx;
145 template <typename T>
146 typename nsTStringRepr<T>::size_type nsTStringRepr<T>::CountChar(
147 char_type aChar) const {
148 return std::count(BeginReading(), EndReading(), aChar);
151 template <typename T>
152 int32_t nsTStringRepr<T>::FindChar(char_type aChar, index_type aOffset) const {
153 auto idx = View().find(aChar, aOffset);
154 return idx == string_view::npos ? kNotFound : idx;
157 template <typename T>
158 int32_t nsTStringRepr<T>::RFindChar(char_type aChar, int32_t aOffset) const {
159 auto idx = View().rfind(aChar, aOffset != -1 ? aOffset : string_view::npos);
160 return idx == string_view::npos ? kNotFound : idx;
163 template <typename T>
164 int32_t nsTStringRepr<T>::FindCharInSet(const string_view& aSet,
165 index_type aOffset) const {
166 auto idx = View().find_first_of(aSet, aOffset);
167 return idx == string_view::npos ? kNotFound : idx;
170 template <typename T>
171 int32_t nsTStringRepr<T>::RFindCharInSet(const string_view& aSet,
172 int32_t aOffset) const {
173 auto idx =
174 View().find_last_of(aSet, aOffset != -1 ? aOffset : string_view::npos);
175 return idx == string_view::npos ? kNotFound : idx;
178 template <typename T>
179 bool nsTStringRepr<T>::EqualsIgnoreCase(const std::string_view& aString) const {
180 return std::equal(BeginReading(), EndReading(), aString.begin(),
181 aString.end(), [](char_type l, char r) {
182 return char_traits::ASCIIToLower(l) ==
183 char_traits::ASCIIToLower(char_type(r));
187 // We can't use the method `StringToDoubleConverter::ToDouble` due to linking
188 // issues on Windows as it's in mozglue. Instead, implement the selection logic
189 // using an overload set.
191 // StringToFloat is used instead of StringToDouble for floats due to differences
192 // in rounding behaviour.
193 static void StringToFP(
194 const double_conversion::StringToDoubleConverter& aConverter,
195 const char* aData, size_t aLength, int* aProcessed, float* aResult) {
196 *aResult = aConverter.StringToFloat(aData, aLength, aProcessed);
199 static void StringToFP(
200 const double_conversion::StringToDoubleConverter& aConverter,
201 const char* aData, size_t aLength, int* aProcessed, double* aResult) {
202 *aResult = aConverter.StringToDouble(aData, aLength, aProcessed);
205 static void StringToFP(
206 const double_conversion::StringToDoubleConverter& aConverter,
207 const char16_t* aData, size_t aLength, int* aProcessed, float* aResult) {
208 *aResult = aConverter.StringToFloat(reinterpret_cast<const uc16*>(aData),
209 aLength, aProcessed);
212 static void StringToFP(
213 const double_conversion::StringToDoubleConverter& aConverter,
214 const char16_t* aData, size_t aLength, int* aProcessed, double* aResult) {
215 *aResult = aConverter.StringToDouble(reinterpret_cast<const uc16*>(aData),
216 aLength, aProcessed);
219 template <typename FloatT, typename CharT>
220 static FloatT ParseFloatingPoint(const nsTStringRepr<CharT>& aString,
221 bool aAllowTrailingChars,
222 nsresult* aErrorCode) {
223 // Performs conversion to double following the "rules for parsing
224 // floating-point number values" from the HTML standard.
225 // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values
227 // This behaviour allows for leading spaces, and will not generate infinity or
228 // NaN values except in error conditions.
229 int flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES;
230 if (aAllowTrailingChars) {
231 flags |= double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK;
233 double_conversion::StringToDoubleConverter converter(
234 flags, mozilla::UnspecifiedNaN<double>(),
235 mozilla::UnspecifiedNaN<double>(), nullptr, nullptr);
237 FloatT result;
238 int processed;
239 StringToFP(converter, aString.Data(), aString.Length(), &processed, &result);
241 *aErrorCode = std::isfinite(result) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
242 return result;
245 template <typename T>
246 double nsTStringRepr<T>::ToDouble(nsresult* aErrorCode) const {
247 return ParseFloatingPoint<double, T>(*this, /* aAllowTrailingChars */ false,
248 aErrorCode);
251 template <typename T>
252 double nsTStringRepr<T>::ToDoubleAllowTrailingChars(
253 nsresult* aErrorCode) const {
254 return ParseFloatingPoint<double, T>(*this, /* aAllowTrailingChars */ true,
255 aErrorCode);
258 template <typename T>
259 float nsTStringRepr<T>::ToFloat(nsresult* aErrorCode) const {
260 return ParseFloatingPoint<float, T>(*this, /* aAllowTrailingChars */ false,
261 aErrorCode);
264 template <typename T>
265 float nsTStringRepr<T>::ToFloatAllowTrailingChars(nsresult* aErrorCode) const {
266 return ParseFloatingPoint<float, T>(*this, /* aAllowTrailingChars */ true,
267 aErrorCode);
270 } // namespace mozilla::detail
272 template class mozilla::detail::nsTStringRepr<char>;
273 template class mozilla::detail::nsTStringRepr<char16_t>;