1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a
4
+ // copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ // persons to whom the Software is furnished to do so, subject to the
9
+ // following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ #ifndef SRC_UTIL_LOCAL_VECTOR_H_
23
+ #define SRC_UTIL_LOCAL_VECTOR_H_
24
+
25
+ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
26
+
27
+ #include " util.h"
28
+ #include " v8.h"
29
+
30
+ namespace node {
31
+
32
+ // Template specialization for MaybeStackBuffer<v8::Local<T>> that uses
33
+ // v8::LocalVector<T> for heap allocations instead of malloc/free.
34
+ template <typename T, size_t kStackStorageSize >
35
+ class MaybeStackBuffer <v8::Local<T>, kStackStorageSize > {
36
+ public:
37
+ // Disallow copy constructor
38
+ MaybeStackBuffer (const MaybeStackBuffer&) = delete ;
39
+ // Disallow copy assignment operator
40
+ MaybeStackBuffer& operator =(const MaybeStackBuffer& other) = delete ;
41
+
42
+ const v8::Local<T>* out () const { return buf_; }
43
+
44
+ v8::Local<T>* out () { return buf_; }
45
+
46
+ // operator* for compatibility with `v8::String::(Utf8)Value`
47
+ v8::Local<T>* operator *() { return buf_; }
48
+
49
+ const v8::Local<T>* operator *() const { return buf_; }
50
+
51
+ v8::Local<T>& operator [](size_t index) {
52
+ CHECK_LT (index, length ());
53
+ return buf_[index];
54
+ }
55
+
56
+ const v8::Local<T>& operator [](size_t index) const {
57
+ CHECK_LT (index, length ());
58
+ return buf_[index];
59
+ }
60
+
61
+ size_t length () const { return length_; }
62
+
63
+ // Current maximum capacity of the buffer with which SetLength() can be used
64
+ // without first calling AllocateSufficientStorage().
65
+ size_t capacity () const { return capacity_; }
66
+
67
+ // Make sure enough space for `storage` entries is available.
68
+ // This method can be called multiple times throughout the lifetime of the
69
+ // buffer, but once this has been called Invalidate() cannot be used.
70
+ // Content of the buffer in the range [0, length()) is preserved.
71
+ void AllocateSufficientStorage (size_t storage) {
72
+ CHECK (!IsInvalidated ());
73
+ if (storage > capacity ()) {
74
+ bool was_allocated = IsAllocated ();
75
+
76
+ if (was_allocated) {
77
+ // Copy from existing LocalVector to a new one
78
+ v8::Isolate* isolate = v8::Isolate::GetCurrent ();
79
+ auto new_vec = std::make_unique<v8::LocalVector<T>>(isolate, storage);
80
+ for (size_t i = 0 ; i < length_; i++) {
81
+ (*new_vec)[i] = buf_[i];
82
+ }
83
+ vector_buf_ = std::move (new_vec);
84
+ buf_ = vector_buf_->data ();
85
+ } else {
86
+ // First allocation or switching from stack to heap
87
+ v8::Isolate* isolate = v8::Isolate::GetCurrent ();
88
+ vector_buf_ = std::make_unique<v8::LocalVector<T>>(isolate, storage);
89
+
90
+ // Copy from stack to LocalVector if needed
91
+ if (length_ > 0 ) {
92
+ for (size_t i = 0 ; i < length_; i++) {
93
+ (*vector_buf_)[i] = buf_st_[i];
94
+ }
95
+ }
96
+ buf_ = vector_buf_->data ();
97
+ }
98
+ capacity_ = storage;
99
+ }
100
+
101
+ length_ = storage;
102
+ }
103
+
104
+ void SetLength (size_t length) {
105
+ // capacity() returns how much memory is actually available.
106
+ CHECK_LE (length, capacity ());
107
+ length_ = length;
108
+ }
109
+
110
+ void SetLengthAndZeroTerminate (size_t length) {
111
+ // capacity() returns how much memory is actually available.
112
+ CHECK_LE (length + 1 , capacity ());
113
+ SetLength (length);
114
+
115
+ // Set null for the last element
116
+ buf_[length] = v8::Local<T>();
117
+ }
118
+
119
+ // Make dereferencing this object return nullptr.
120
+ // This method can be called multiple times throughout the lifetime of the
121
+ // buffer, but once this has been called AllocateSufficientStorage() cannot
122
+ // be used.
123
+ void Invalidate () {
124
+ CHECK (!IsAllocated ());
125
+ capacity_ = 0 ;
126
+ length_ = 0 ;
127
+ buf_ = nullptr ;
128
+ }
129
+
130
+ // If the buffer is stored in the heap rather than on the stack.
131
+ bool IsAllocated () const { return !IsInvalidated () && buf_ != buf_st_; }
132
+
133
+ // If Invalidate() has been called.
134
+ bool IsInvalidated () const { return buf_ == nullptr ; }
135
+
136
+ // Release ownership of the LocalVector buffer.
137
+ void Release () {
138
+ CHECK (IsAllocated ());
139
+ vector_buf_.reset ();
140
+ buf_ = buf_st_;
141
+ length_ = 0 ;
142
+ capacity_ = arraysize (buf_st_);
143
+ }
144
+
145
+ MaybeStackBuffer ()
146
+ : length_(0 ),
147
+ capacity_ (arraysize(buf_st_)),
148
+ buf_(buf_st_),
149
+ vector_buf_(nullptr ) {
150
+ // Default to a zero-length buffer.
151
+ }
152
+
153
+ explicit MaybeStackBuffer (size_t storage) : MaybeStackBuffer() {
154
+ AllocateSufficientStorage (storage);
155
+ }
156
+
157
+ ~MaybeStackBuffer () {
158
+ // LocalVector manages its own memory
159
+ vector_buf_.reset ();
160
+ }
161
+
162
+ private:
163
+ size_t length_;
164
+ // capacity of the vector_buf_ or stack buffer
165
+ size_t capacity_;
166
+ v8::Local<T>* buf_;
167
+ v8::Local<T> buf_st_[kStackStorageSize ];
168
+ // Used when we allocate on the heap
169
+ std::unique_ptr<v8::LocalVector<T>> vector_buf_;
170
+ };
171
+
172
+ } // namespace node
173
+
174
+ #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
175
+
176
+ #endif // SRC_UTIL_LOCAL_VECTOR_H_
0 commit comments