Bug 1685674 [wpt PR 27098] - Add a test for :autofill., a=testonly
[gecko.git] / js / public / String.h
blobc7fbb1828876d3b983517fbea39503fd4e614aa5
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* JavaScript string operations. */
9 #ifndef js_String_h
10 #define js_String_h
12 #include "js/shadow/String.h" // JS::shadow::String
14 #include "mozilla/Assertions.h" // MOZ_ASSERT
15 #include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE, MOZ_MUST_USE
16 #include "mozilla/Likely.h" // MOZ_LIKELY
18 #include <algorithm> // std::copy_n
19 #include <stddef.h> // size_t
20 #include <stdint.h> // uint32_t, uint64_t, INT32_MAX
22 #include "jstypes.h" // JS_PUBLIC_API
24 #include "js/TypeDecls.h" // JS::Latin1Char
26 class JS_PUBLIC_API JSAtom;
27 class JSLinearString;
28 class JS_PUBLIC_API JSString;
30 namespace JS {
32 class JS_PUBLIC_API AutoRequireNoGC;
34 /**
35 * Maximum length of a JS string. This is chosen so that the number of bytes
36 * allocated for a null-terminated TwoByte string still fits in int32_t.
38 static constexpr uint32_t MaxStringLength = (1 << 30) - 2;
40 static_assert((uint64_t(MaxStringLength) + 1) * sizeof(char16_t) <= INT32_MAX,
41 "size of null-terminated JSString char buffer must fit in "
42 "INT32_MAX");
44 /** Compute the length of a string. */
45 MOZ_ALWAYS_INLINE size_t GetStringLength(JSString* s) {
46 return shadow::AsShadowString(s)->length();
49 /** Compute the length of a linear string. */
50 MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) {
51 return shadow::AsShadowString(s)->length();
54 /** Return true iff the given linear string uses Latin-1 storage. */
55 MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) {
56 return shadow::AsShadowString(s)->hasLatin1Chars();
59 /** Return true iff the given string uses Latin-1 storage. */
60 MOZ_ALWAYS_INLINE bool StringHasLatin1Chars(JSString* s) {
61 return shadow::AsShadowString(s)->hasLatin1Chars();
64 /**
65 * Given a linear string known to use Latin-1 storage, return a pointer to that
66 * storage. This pointer remains valid only as long as no GC occurs.
68 MOZ_ALWAYS_INLINE const Latin1Char* GetLatin1LinearStringChars(
69 const AutoRequireNoGC& nogc, JSLinearString* linear) {
70 return shadow::AsShadowString(linear)->latin1LinearChars();
73 /**
74 * Given a linear string known to use two-byte storage, return a pointer to that
75 * storage. This pointer remains valid only as long as no GC occurs.
77 MOZ_ALWAYS_INLINE const char16_t* GetTwoByteLinearStringChars(
78 const AutoRequireNoGC& nogc, JSLinearString* linear) {
79 return shadow::AsShadowString(linear)->twoByteLinearChars();
82 /**
83 * Given an in-range index into the provided string, return the character at
84 * that index.
86 MOZ_ALWAYS_INLINE char16_t GetLinearStringCharAt(JSLinearString* linear,
87 size_t index) {
88 shadow::String* s = shadow::AsShadowString(linear);
89 MOZ_ASSERT(index < s->length());
91 return s->hasLatin1Chars() ? s->latin1LinearChars()[index]
92 : s->twoByteLinearChars()[index];
95 /**
96 * Convert an atom to a linear string. All atoms are linear, so this
97 * operation is infallible.
99 MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) {
100 return reinterpret_cast<JSLinearString*>(atom);
104 * If the provided string uses externally-managed storage, return true and set
105 * |*callbacks| to the external-string callbacks used to create it and |*chars|
106 * to a pointer to its two-byte storage. (These pointers remain valid as long
107 * as the provided string is kept alive.)
109 MOZ_ALWAYS_INLINE bool IsExternalString(
110 JSString* str, const JSExternalStringCallbacks** callbacks,
111 const char16_t** chars) {
112 shadow::String* s = shadow::AsShadowString(str);
114 if (!s->isExternal()) {
115 return false;
118 *callbacks = s->externalCallbacks;
119 *chars = s->nonInlineCharsTwoByte;
120 return true;
123 namespace detail {
125 extern JS_FRIEND_API JSLinearString* StringToLinearStringSlow(JSContext* cx,
126 JSString* str);
128 } // namespace detail
130 /** Convert a string to a linear string. */
131 MOZ_ALWAYS_INLINE JSLinearString* StringToLinearString(JSContext* cx,
132 JSString* str) {
133 if (MOZ_LIKELY(shadow::AsShadowString(str)->isLinear())) {
134 return reinterpret_cast<JSLinearString*>(str);
137 return detail::StringToLinearStringSlow(cx, str);
140 /** Copy characters in |s[start..start + len]| to |dest[0..len]|. */
141 MOZ_ALWAYS_INLINE void CopyLinearStringChars(char16_t* dest, JSLinearString* s,
142 size_t len, size_t start = 0) {
143 #ifdef DEBUG
144 size_t stringLen = GetLinearStringLength(s);
145 MOZ_ASSERT(start <= stringLen);
146 MOZ_ASSERT(len <= stringLen - start);
147 #endif
149 shadow::String* str = shadow::AsShadowString(s);
151 if (str->hasLatin1Chars()) {
152 const Latin1Char* src = str->latin1LinearChars();
153 for (size_t i = 0; i < len; i++) {
154 dest[i] = src[start + i];
156 } else {
157 const char16_t* src = str->twoByteLinearChars();
158 std::copy_n(src + start, len, dest);
163 * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
164 * truncating 16-bit values to |char| if necessary.
166 MOZ_ALWAYS_INLINE void LossyCopyLinearStringChars(char* dest, JSLinearString* s,
167 size_t len,
168 size_t start = 0) {
169 #ifdef DEBUG
170 size_t stringLen = GetLinearStringLength(s);
171 MOZ_ASSERT(start <= stringLen);
172 MOZ_ASSERT(len <= stringLen - start);
173 #endif
175 shadow::String* str = shadow::AsShadowString(s);
177 if (LinearStringHasLatin1Chars(s)) {
178 const Latin1Char* src = str->latin1LinearChars();
179 for (size_t i = 0; i < len; i++) {
180 dest[i] = char(src[start + i]);
182 } else {
183 const char16_t* src = str->twoByteLinearChars();
184 for (size_t i = 0; i < len; i++) {
185 dest[i] = char(src[start + i]);
191 * Copy characters in |s[start..start + len]| to |dest[0..len]|.
193 * This function is fallible. If you already have a linear string, use the
194 * infallible |JS::CopyLinearStringChars| above instead.
196 inline MOZ_MUST_USE bool CopyStringChars(JSContext* cx, char16_t* dest,
197 JSString* s, size_t len,
198 size_t start = 0) {
199 JSLinearString* linear = StringToLinearString(cx, s);
200 if (!linear) {
201 return false;
204 CopyLinearStringChars(dest, linear, len, start);
205 return true;
209 * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
210 * truncating 16-bit values to |char| if necessary.
212 * This function is fallible. If you already have a linear string, use the
213 * infallible |JS::LossyCopyLinearStringChars| above instead.
215 inline MOZ_MUST_USE bool LossyCopyStringChars(JSContext* cx, char* dest,
216 JSString* s, size_t len,
217 size_t start = 0) {
218 JSLinearString* linear = StringToLinearString(cx, s);
219 if (!linear) {
220 return false;
223 LossyCopyLinearStringChars(dest, linear, len, start);
224 return true;
227 } // namespace JS
229 /** DO NOT USE, only present for Rust bindings as a temporary hack */
230 [[deprecated]] extern JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(
231 JSString* str);
233 #endif // js_String_h