summaryrefslogtreecommitdiffstats
path: root/js/public/String.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/public/String.h')
-rw-r--r--js/public/String.h233
1 files changed, 233 insertions, 0 deletions
diff --git a/js/public/String.h b/js/public/String.h
new file mode 100644
index 0000000000..c7fbb18288
--- /dev/null
+++ b/js/public/String.h
@@ -0,0 +1,233 @@
+/* -*- 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/. */
+
+/* JavaScript string operations. */
+
+#ifndef js_String_h
+#define js_String_h
+
+#include "js/shadow/String.h" // JS::shadow::String
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE, MOZ_MUST_USE
+#include "mozilla/Likely.h" // MOZ_LIKELY
+
+#include <algorithm> // std::copy_n
+#include <stddef.h> // size_t
+#include <stdint.h> // uint32_t, uint64_t, INT32_MAX
+
+#include "jstypes.h" // JS_PUBLIC_API
+
+#include "js/TypeDecls.h" // JS::Latin1Char
+
+class JS_PUBLIC_API JSAtom;
+class JSLinearString;
+class JS_PUBLIC_API JSString;
+
+namespace JS {
+
+class JS_PUBLIC_API AutoRequireNoGC;
+
+/**
+ * Maximum length of a JS string. This is chosen so that the number of bytes
+ * allocated for a null-terminated TwoByte string still fits in int32_t.
+ */
+static constexpr uint32_t MaxStringLength = (1 << 30) - 2;
+
+static_assert((uint64_t(MaxStringLength) + 1) * sizeof(char16_t) <= INT32_MAX,
+ "size of null-terminated JSString char buffer must fit in "
+ "INT32_MAX");
+
+/** Compute the length of a string. */
+MOZ_ALWAYS_INLINE size_t GetStringLength(JSString* s) {
+ return shadow::AsShadowString(s)->length();
+}
+
+/** Compute the length of a linear string. */
+MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) {
+ return shadow::AsShadowString(s)->length();
+}
+
+/** Return true iff the given linear string uses Latin-1 storage. */
+MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) {
+ return shadow::AsShadowString(s)->hasLatin1Chars();
+}
+
+/** Return true iff the given string uses Latin-1 storage. */
+MOZ_ALWAYS_INLINE bool StringHasLatin1Chars(JSString* s) {
+ return shadow::AsShadowString(s)->hasLatin1Chars();
+}
+
+/**
+ * Given a linear string known to use Latin-1 storage, return a pointer to that
+ * storage. This pointer remains valid only as long as no GC occurs.
+ */
+MOZ_ALWAYS_INLINE const Latin1Char* GetLatin1LinearStringChars(
+ const AutoRequireNoGC& nogc, JSLinearString* linear) {
+ return shadow::AsShadowString(linear)->latin1LinearChars();
+}
+
+/**
+ * Given a linear string known to use two-byte storage, return a pointer to that
+ * storage. This pointer remains valid only as long as no GC occurs.
+ */
+MOZ_ALWAYS_INLINE const char16_t* GetTwoByteLinearStringChars(
+ const AutoRequireNoGC& nogc, JSLinearString* linear) {
+ return shadow::AsShadowString(linear)->twoByteLinearChars();
+}
+
+/**
+ * Given an in-range index into the provided string, return the character at
+ * that index.
+ */
+MOZ_ALWAYS_INLINE char16_t GetLinearStringCharAt(JSLinearString* linear,
+ size_t index) {
+ shadow::String* s = shadow::AsShadowString(linear);
+ MOZ_ASSERT(index < s->length());
+
+ return s->hasLatin1Chars() ? s->latin1LinearChars()[index]
+ : s->twoByteLinearChars()[index];
+}
+
+/**
+ * Convert an atom to a linear string. All atoms are linear, so this
+ * operation is infallible.
+ */
+MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) {
+ return reinterpret_cast<JSLinearString*>(atom);
+}
+
+/**
+ * If the provided string uses externally-managed storage, return true and set
+ * |*callbacks| to the external-string callbacks used to create it and |*chars|
+ * to a pointer to its two-byte storage. (These pointers remain valid as long
+ * as the provided string is kept alive.)
+ */
+MOZ_ALWAYS_INLINE bool IsExternalString(
+ JSString* str, const JSExternalStringCallbacks** callbacks,
+ const char16_t** chars) {
+ shadow::String* s = shadow::AsShadowString(str);
+
+ if (!s->isExternal()) {
+ return false;
+ }
+
+ *callbacks = s->externalCallbacks;
+ *chars = s->nonInlineCharsTwoByte;
+ return true;
+}
+
+namespace detail {
+
+extern JS_FRIEND_API JSLinearString* StringToLinearStringSlow(JSContext* cx,
+ JSString* str);
+
+} // namespace detail
+
+/** Convert a string to a linear string. */
+MOZ_ALWAYS_INLINE JSLinearString* StringToLinearString(JSContext* cx,
+ JSString* str) {
+ if (MOZ_LIKELY(shadow::AsShadowString(str)->isLinear())) {
+ return reinterpret_cast<JSLinearString*>(str);
+ }
+
+ return detail::StringToLinearStringSlow(cx, str);
+}
+
+/** Copy characters in |s[start..start + len]| to |dest[0..len]|. */
+MOZ_ALWAYS_INLINE void CopyLinearStringChars(char16_t* dest, JSLinearString* s,
+ size_t len, size_t start = 0) {
+#ifdef DEBUG
+ size_t stringLen = GetLinearStringLength(s);
+ MOZ_ASSERT(start <= stringLen);
+ MOZ_ASSERT(len <= stringLen - start);
+#endif
+
+ shadow::String* str = shadow::AsShadowString(s);
+
+ if (str->hasLatin1Chars()) {
+ const Latin1Char* src = str->latin1LinearChars();
+ for (size_t i = 0; i < len; i++) {
+ dest[i] = src[start + i];
+ }
+ } else {
+ const char16_t* src = str->twoByteLinearChars();
+ std::copy_n(src + start, len, dest);
+ }
+}
+
+/**
+ * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
+ * truncating 16-bit values to |char| if necessary.
+ */
+MOZ_ALWAYS_INLINE void LossyCopyLinearStringChars(char* dest, JSLinearString* s,
+ size_t len,
+ size_t start = 0) {
+#ifdef DEBUG
+ size_t stringLen = GetLinearStringLength(s);
+ MOZ_ASSERT(start <= stringLen);
+ MOZ_ASSERT(len <= stringLen - start);
+#endif
+
+ shadow::String* str = shadow::AsShadowString(s);
+
+ if (LinearStringHasLatin1Chars(s)) {
+ const Latin1Char* src = str->latin1LinearChars();
+ for (size_t i = 0; i < len; i++) {
+ dest[i] = char(src[start + i]);
+ }
+ } else {
+ const char16_t* src = str->twoByteLinearChars();
+ for (size_t i = 0; i < len; i++) {
+ dest[i] = char(src[start + i]);
+ }
+ }
+}
+
+/**
+ * Copy characters in |s[start..start + len]| to |dest[0..len]|.
+ *
+ * This function is fallible. If you already have a linear string, use the
+ * infallible |JS::CopyLinearStringChars| above instead.
+ */
+inline MOZ_MUST_USE bool CopyStringChars(JSContext* cx, char16_t* dest,
+ JSString* s, size_t len,
+ size_t start = 0) {
+ JSLinearString* linear = StringToLinearString(cx, s);
+ if (!linear) {
+ return false;
+ }
+
+ CopyLinearStringChars(dest, linear, len, start);
+ return true;
+}
+
+/**
+ * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
+ * truncating 16-bit values to |char| if necessary.
+ *
+ * This function is fallible. If you already have a linear string, use the
+ * infallible |JS::LossyCopyLinearStringChars| above instead.
+ */
+inline MOZ_MUST_USE bool LossyCopyStringChars(JSContext* cx, char* dest,
+ JSString* s, size_t len,
+ size_t start = 0) {
+ JSLinearString* linear = StringToLinearString(cx, s);
+ if (!linear) {
+ return false;
+ }
+
+ LossyCopyLinearStringChars(dest, linear, len, start);
+ return true;
+}
+
+} // namespace JS
+
+/** DO NOT USE, only present for Rust bindings as a temporary hack */
+[[deprecated]] extern JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(
+ JSString* str);
+
+#endif // js_String_h