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"
14 namespace mozilla::detail
{
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];
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];
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;
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;
42 bool nsTStringRepr
<T
>::Equals(const substring_tuple_type
& aTuple
) const {
43 return Equals(substring_type(aTuple
));
47 bool nsTStringRepr
<T
>::Equals(const substring_tuple_type
& aTuple
,
48 comparator_type aComp
) const {
49 return Equals(substring_type(aTuple
), aComp
);
53 bool nsTStringRepr
<T
>::Equals(const char_type
* aData
) const {
54 // unfortunately, some callers pass null :-(
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;
67 bool nsTStringRepr
<T
>::Equals(const char_type
* aData
,
68 comparator_type aComp
) const {
69 // unfortunately, some callers pass null :-(
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;
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;
88 bool nsTStringRepr
<T
>::EqualsASCII(const char* aData
) const {
89 return char_traits::compareASCIINullTerminated(this->mData
, this->mLength
,
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()) {
126 auto begin
= BeginReading();
127 auto end
= EndReading();
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 {
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);
239 StringToFP(converter
, aString
.Data(), aString
.Length(), &processed
, &result
);
241 *aErrorCode
= std::isfinite(result
) ? NS_OK
: NS_ERROR_ILLEGAL_VALUE
;
245 template <typename T
>
246 double nsTStringRepr
<T
>::ToDouble(nsresult
* aErrorCode
) const {
247 return ParseFloatingPoint
<double, T
>(*this, /* aAllowTrailingChars */ false,
251 template <typename T
>
252 double nsTStringRepr
<T
>::ToDoubleAllowTrailingChars(
253 nsresult
* aErrorCode
) const {
254 return ParseFloatingPoint
<double, T
>(*this, /* aAllowTrailingChars */ true,
258 template <typename T
>
259 float nsTStringRepr
<T
>::ToFloat(nsresult
* aErrorCode
) const {
260 return ParseFloatingPoint
<float, T
>(*this, /* aAllowTrailingChars */ false,
264 template <typename T
>
265 float nsTStringRepr
<T
>::ToFloatAllowTrailingChars(nsresult
* aErrorCode
) const {
266 return ParseFloatingPoint
<float, T
>(*this, /* aAllowTrailingChars */ true,
270 } // namespace mozilla::detail
272 template class mozilla::detail::nsTStringRepr
<char>;
273 template class mozilla::detail::nsTStringRepr
<char16_t
>;