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/. */
6 
7 #ifndef builtin_intl_StringAsciiChars_h
8 #define builtin_intl_StringAsciiChars_h
9 
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/Span.h"
14 #include "mozilla/TextUtils.h"
15 
16 #include <stddef.h>
17 
18 #include "js/GCAPI.h"
19 #include "js/TypeDecls.h"
20 #include "js/Vector.h"
21 
22 #include "vm/StringType.h"
23 
24 namespace js::intl {
25 
26 /**
27  * String view of an ASCII-only string.
28  *
29  * This holds a reference to a JSLinearString and can produce a string view
30  * into that string. If the string is represented by Latin1 characters, the
31  * span is returned directly. If the string is represented by UTF-16
32  * characters, it copies the char16_t characters into a char array, and then
33  * returns a span based on the copy.
34  *
35  * This allows us to avoid copying for the common use case that the ASCII
36  * characters are represented in Latin1.
37  */
38 class MOZ_STACK_CLASS StringAsciiChars final {
39   // When copying string characters, use this many bytes of inline storage.
40   static const size_t InlineCapacity = 24;
41 
42   JS::AutoCheckCannotGC nogc_;
43 
44   JSLinearString* str_;
45 
46   mozilla::Maybe<Vector<Latin1Char, InlineCapacity>> ownChars_;
47 
48  public:
StringAsciiChars(JSLinearString * str)49   explicit StringAsciiChars(JSLinearString* str) : str_(str) {
50     MOZ_ASSERT(StringIsAscii(str));
51   }
52 
53   operator mozilla::Span<const char>() const {
54     if (str_->hasLatin1Chars()) {
55       return mozilla::AsChars(str_->latin1Range(nogc_));
56     }
57     return mozilla::AsChars(mozilla::Span<const Latin1Char>(*ownChars_));
58   }
59 
init(JSContext * cx)60   [[nodiscard]] bool init(JSContext* cx) {
61     if (str_->hasLatin1Chars()) {
62       return true;
63     }
64 
65     ownChars_.emplace(cx);
66     if (!ownChars_->resize(str_->length())) {
67       return false;
68     }
69 
70     js::CopyChars(ownChars_->begin(), *str_);
71 
72     return true;
73   }
74 };
75 
76 }  // namespace js::intl
77 
78 #endif  // builtin_intl_StringAsciiChars_h
79