GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: util.h Lines: 132 132 100.0 %
Date: 2022-05-03 04:14:50 Branches: 34 46 73.9 %

Line Branch Exec Source
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_H_
23
#define SRC_UTIL_H_
24
25
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
26
27
#include "v8.h"
28
29
#include <climits>
30
#include <cstddef>
31
#include <cstdio>
32
#include <cstdlib>
33
#include <cstring>
34
35
#include <array>
36
#include <limits>
37
#include <memory>
38
#include <string>
39
#include <string_view>
40
#include <type_traits>
41
#include <set>
42
#include <unordered_map>
43
#include <utility>
44
#include <vector>
45
46
#ifdef __GNUC__
47
#define MUST_USE_RESULT __attribute__((warn_unused_result))
48
#else
49
#define MUST_USE_RESULT
50
#endif
51
52
namespace node {
53
54
// Maybe remove kPathSeparator when cpp17 is ready
55
#ifdef _WIN32
56
    constexpr char kPathSeparator = '\\';
57
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
58
#define PATH_MAX_BYTES (MAX_PATH * 4)
59
#else
60
    constexpr char kPathSeparator = '/';
61
#define PATH_MAX_BYTES (PATH_MAX)
62
#endif
63
64
// These should be used in our code as opposed to the native
65
// versions as they abstract out some platform and or
66
// compiler version specific functionality
67
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
68
// that the standard allows them to either return a unique pointer or a
69
// nullptr for zero-sized allocation requests.  Normalize by always using
70
// a nullptr.
71
template <typename T>
72
inline T* UncheckedRealloc(T* pointer, size_t n);
73
template <typename T>
74
inline T* UncheckedMalloc(size_t n);
75
template <typename T>
76
inline T* UncheckedCalloc(size_t n);
77
78
// Same things, but aborts immediately instead of returning nullptr when
79
// no memory is available.
80
template <typename T>
81
inline T* Realloc(T* pointer, size_t n);
82
template <typename T>
83
inline T* Malloc(size_t n);
84
template <typename T>
85
inline T* Calloc(size_t n);
86
87
inline char* Malloc(size_t n);
88
inline char* Calloc(size_t n);
89
inline char* UncheckedMalloc(size_t n);
90
inline char* UncheckedCalloc(size_t n);
91
92
template <typename T>
93
inline T MultiplyWithOverflowCheck(T a, T b);
94
95
namespace per_process {
96
// Tells whether the per-process V8::Initialize() is called and
97
// if it is safe to call v8::Isolate::TryGetCurrent().
98
extern bool v8_initialized;
99
}  // namespace per_process
100
101
// Used by the allocation functions when allocation fails.
102
// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks
103
// whether V8 is initialized.
104
void LowMemoryNotification();
105
106
// The reason that Assert() takes a struct argument instead of individual
107
// const char*s is to ease instruction cache pressure in calls from CHECK.
108
struct AssertionInfo {
109
  const char* file_line;  // filename:line
110
  const char* message;
111
  const char* function;
112
};
113
[[noreturn]] void Assert(const AssertionInfo& info);
114
[[noreturn]] void Abort();
115
void DumpBacktrace(FILE* fp);
116
117
// Windows 8+ does not like abort() in Release mode
118
#ifdef _WIN32
119
#define ABORT_NO_BACKTRACE() _exit(134)
120
#else
121
#define ABORT_NO_BACKTRACE() abort()
122
#endif
123
124
#define ABORT() node::Abort()
125
126
#define ERROR_AND_ABORT(expr)                                                 \
127
  do {                                                                        \
128
    /* Make sure that this struct does not end up in inline code, but      */ \
129
    /* rather in a read-only data section when modifying this code.        */ \
130
    static const node::AssertionInfo args = {                                 \
131
      __FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME           \
132
    };                                                                        \
133
    node::Assert(args);                                                       \
134
  } while (0)
135
136
#ifdef __GNUC__
137
#define LIKELY(expr) __builtin_expect(!!(expr), 1)
138
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
139
#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
140
#else
141
#define LIKELY(expr) expr
142
#define UNLIKELY(expr) expr
143
#define PRETTY_FUNCTION_NAME ""
144
#endif
145
146
#define STRINGIFY_(x) #x
147
#define STRINGIFY(x) STRINGIFY_(x)
148
149
#define CHECK(expr)                                                           \
150
  do {                                                                        \
151
    if (UNLIKELY(!(expr))) {                                                  \
152
      ERROR_AND_ABORT(expr);                                                  \
153
    }                                                                         \
154
  } while (0)
155
156
#define CHECK_EQ(a, b) CHECK((a) == (b))
157
#define CHECK_GE(a, b) CHECK((a) >= (b))
158
#define CHECK_GT(a, b) CHECK((a) > (b))
159
#define CHECK_LE(a, b) CHECK((a) <= (b))
160
#define CHECK_LT(a, b) CHECK((a) < (b))
161
#define CHECK_NE(a, b) CHECK((a) != (b))
162
#define CHECK_NULL(val) CHECK((val) == nullptr)
163
#define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
164
#define CHECK_IMPLIES(a, b) CHECK(!(a) || (b))
165
166
#ifdef DEBUG
167
  #define DCHECK(expr) CHECK(expr)
168
  #define DCHECK_EQ(a, b) CHECK((a) == (b))
169
  #define DCHECK_GE(a, b) CHECK((a) >= (b))
170
  #define DCHECK_GT(a, b) CHECK((a) > (b))
171
  #define DCHECK_LE(a, b) CHECK((a) <= (b))
172
  #define DCHECK_LT(a, b) CHECK((a) < (b))
173
  #define DCHECK_NE(a, b) CHECK((a) != (b))
174
  #define DCHECK_NULL(val) CHECK((val) == nullptr)
175
  #define DCHECK_NOT_NULL(val) CHECK((val) != nullptr)
176
  #define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b))
177
#else
178
  #define DCHECK(expr)
179
  #define DCHECK_EQ(a, b)
180
  #define DCHECK_GE(a, b)
181
  #define DCHECK_GT(a, b)
182
  #define DCHECK_LE(a, b)
183
  #define DCHECK_LT(a, b)
184
  #define DCHECK_NE(a, b)
185
  #define DCHECK_NULL(val)
186
  #define DCHECK_NOT_NULL(val)
187
  #define DCHECK_IMPLIES(a, b)
188
#endif
189
190
191
#define UNREACHABLE(...)                                                      \
192
  ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)
193
194
// ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1)
195
constexpr int64_t kMaxSafeJsInteger = 9007199254740991;
196
197
inline bool IsSafeJsInt(v8::Local<v8::Value> v);
198
199
// TAILQ-style intrusive list node.
200
template <typename T>
201
class ListNode;
202
203
// TAILQ-style intrusive list head.
204
template <typename T, ListNode<T> (T::*M)>
205
class ListHead;
206
207
template <typename T>
208
class ListNode {
209
 public:
210
  inline ListNode();
211
  inline ~ListNode();
212
  inline void Remove();
213
  inline bool IsEmpty() const;
214
215
  ListNode(const ListNode&) = delete;
216
  ListNode& operator=(const ListNode&) = delete;
217
218
 private:
219
  template <typename U, ListNode<U> (U::*M)> friend class ListHead;
220
  friend int GenDebugSymbols();
221
  ListNode* prev_;
222
  ListNode* next_;
223
};
224
225
template <typename T, ListNode<T> (T::*M)>
226
class ListHead {
227
 public:
228
  class Iterator {
229
   public:
230
    inline T* operator*() const;
231
    inline const Iterator& operator++();
232
    inline bool operator!=(const Iterator& that) const;
233
234
   private:
235
    friend class ListHead;
236
    inline explicit Iterator(ListNode<T>* node);
237
    ListNode<T>* node_;
238
  };
239
240
22285
  inline ListHead() = default;
241
  inline ~ListHead();
242
  inline void PushBack(T* element);
243
  inline void PushFront(T* element);
244
  inline bool IsEmpty() const;
245
  inline T* PopFront();
246
  inline Iterator begin() const;
247
  inline Iterator end() const;
248
249
  ListHead(const ListHead&) = delete;
250
  ListHead& operator=(const ListHead&) = delete;
251
252
 private:
253
  friend int GenDebugSymbols();
254
  ListNode<T> head_;
255
};
256
257
// The helper is for doing safe downcasts from base types to derived types.
258
template <typename Inner, typename Outer>
259
class ContainerOfHelper {
260
 public:
261
  inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
262
  template <typename TypeName>
263
  inline operator TypeName*() const;
264
 private:
265
  Outer* const pointer_;
266
};
267
268
// Calculate the address of the outer (i.e. embedding) struct from
269
// the interior pointer to a data member.
270
template <typename Inner, typename Outer>
271
constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
272
                                                      Inner* pointer);
273
274
// Convenience wrapper around v8::String::NewFromOneByte().
275
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
276
                                           const char* data,
277
                                           int length = -1);
278
279
// For the people that compile with -funsigned-char.
280
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
281
                                           const signed char* data,
282
                                           int length = -1);
283
284
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
285
                                           const unsigned char* data,
286
                                           int length = -1);
287
288
// Used to be a macro, hence the uppercase name.
289
template <int N>
290
5179208
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
291
    v8::Isolate* isolate,
292
    const char(&data)[N]) {
293
5179208
  return OneByteString(isolate, data, N - 1);
294
}
295
296
template <std::size_t N>
297
572
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
298
    v8::Isolate* isolate,
299
    const std::array<char, N>& arr) {
300
572
  return OneByteString(isolate, arr.data(), N - 1);
301
}
302
303
304
305
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
306
// multiple of the word size (checked by function).
307
inline void SwapBytes16(char* data, size_t nbytes);
308
inline void SwapBytes32(char* data, size_t nbytes);
309
inline void SwapBytes64(char* data, size_t nbytes);
310
311
// tolower() is locale-sensitive.  Use ToLower() instead.
312
inline char ToLower(char c);
313
inline std::string ToLower(const std::string& in);
314
315
// toupper() is locale-sensitive.  Use ToUpper() instead.
316
inline char ToUpper(char c);
317
inline std::string ToUpper(const std::string& in);
318
319
// strcasecmp() is locale-sensitive.  Use StringEqualNoCase() instead.
320
inline bool StringEqualNoCase(const char* a, const char* b);
321
322
// strncasecmp() is locale-sensitive.  Use StringEqualNoCaseN() instead.
323
inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
324
325
template <typename T, size_t N>
326
10380551
constexpr size_t arraysize(const T (&)[N]) {
327
10380551
  return N;
328
}
329
330
template <typename T, size_t N>
331
constexpr size_t strsize(const T (&)[N]) {
332
  return N - 1;
333
}
334
335
// Allocates an array of member type T. For up to kStackStorageSize items,
336
// the stack is used, otherwise malloc().
337
template <typename T, size_t kStackStorageSize = 1024>
338
class MaybeStackBuffer {
339
 public:
340
5833
  const T* out() const {
341
5833
    return buf_;
342
  }
343
344
5645499
  T* out() {
345
5645499
    return buf_;
346
  }
347
348
  // operator* for compatibility with `v8::String::(Utf8)Value`
349
8197891
  T* operator*() {
350
8197891
    return buf_;
351
  }
352
353
30426
  const T* operator*() const {
354
30426
    return buf_;
355
  }
356
357
3891415
  T& operator[](size_t index) {
358
3891415
    CHECK_LT(index, length());
359
3891415
    return buf_[index];
360
  }
361
362
10922
  const T& operator[](size_t index) const {
363
10922
    CHECK_LT(index, length());
364
10922
    return buf_[index];
365
  }
366
367
11822816
  size_t length() const {
368
11822816
    return length_;
369
  }
370
371
  // Current maximum capacity of the buffer with which SetLength() can be used
372
  // without first calling AllocateSufficientStorage().
373
17675736
  size_t capacity() const {
374
17675736
    return capacity_;
375
  }
376
377
  // Make sure enough space for `storage` entries is available.
378
  // This method can be called multiple times throughout the lifetime of the
379
  // buffer, but once this has been called Invalidate() cannot be used.
380
  // Content of the buffer in the range [0, length()) is preserved.
381
6300401
  void AllocateSufficientStorage(size_t storage) {
382
6300401
    CHECK(!IsInvalidated());
383
6300401
    if (storage > capacity()) {
384
270858
      bool was_allocated = IsAllocated();
385
270858
      T* allocated_ptr = was_allocated ? buf_ : nullptr;
386
270858
      buf_ = Realloc(allocated_ptr, storage);
387
270858
      capacity_ = storage;
388

270858
      if (!was_allocated && length_ > 0)
389
4
        memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
390
    }
391
392
6300401
    length_ = storage;
393
6300401
  }
394
395
5554098
  void SetLength(size_t length) {
396
    // capacity() returns how much memory is actually available.
397
5554098
    CHECK_LE(length, capacity());
398
5554098
    length_ = length;
399
5554098
  }
400
401
7938767
  void SetLengthAndZeroTerminate(size_t length) {
402
    // capacity() returns how much memory is actually available.
403
7938767
    CHECK_LE(length + 1, capacity());
404
7938767
    SetLength(length);
405
406
    // T() is 0 for integer types, nullptr for pointers, etc.
407
7938767
    buf_[length] = T();
408
7938767
  }
409
410
  // Make dereferencing this object return nullptr.
411
  // This method can be called multiple times throughout the lifetime of the
412
  // buffer, but once this has been called AllocateSufficientStorage() cannot
413
  // be used.
414
2
  void Invalidate() {
415
2
    CHECK(!IsAllocated());
416
2
    capacity_ = 0;
417
2
    length_ = 0;
418
2
    buf_ = nullptr;
419
2
  }
420
421
  // If the buffer is stored in the heap rather than on the stack.
422
7987361
  bool IsAllocated() const {
423

7987361
    return !IsInvalidated() && buf_ != buf_st_;
424
  }
425
426
  // If Invalidate() has been called.
427
14346398
  bool IsInvalidated() const {
428
14346398
    return buf_ == nullptr;
429
  }
430
431
  // Release ownership of the malloc'd buffer.
432
  // Note: This does not free the buffer.
433
618
  void Release() {
434
618
    CHECK(IsAllocated());
435
618
    buf_ = buf_st_;
436
618
    length_ = 0;
437
618
    capacity_ = arraysize(buf_st_);
438
618
  }
439
440
7609570
  MaybeStackBuffer()
441
139690546
      : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
442
    // Default to a zero-length, null-terminated buffer.
443
7609570
    buf_[0] = T();
444
7609570
  }
445
446
734834
  explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
447
734834
    AllocateSufficientStorage(storage);
448
734834
  }
449
450
7707925
  ~MaybeStackBuffer() {
451
7707925
    if (IsAllocated())
452
270235
      free(buf_);
453
7707925
  }
454
455
 private:
456
  size_t length_;
457
  // capacity of the malloc'ed buf_
458
  size_t capacity_;
459
  T* buf_;
460
  T buf_st_[kStackStorageSize];
461
};
462
463
// Provides access to an ArrayBufferView's storage, either the original,
464
// or for small data, a copy of it. This object's lifetime is bound to the
465
// original ArrayBufferView's lifetime.
466
template <typename T, size_t kStackStorageSize = 64>
467
class ArrayBufferViewContents {
468
 public:
469
1230
  ArrayBufferViewContents() = default;
470
471
  explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
472
  explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
473
  explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
474
  inline void Read(v8::Local<v8::ArrayBufferView> abv);
475
476
172261
  inline const T* data() const { return data_; }
477
437583
  inline size_t length() const { return length_; }
478
479
 private:
480
  T stack_storage_[kStackStorageSize];
481
  T* data_ = nullptr;
482
  size_t length_ = 0;
483
};
484
485
class Utf8Value : public MaybeStackBuffer<char> {
486
 public:
487
  explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
488
489
1019
  inline std::string ToString() const { return std::string(out(), length()); }
490
491
4814
  inline bool operator==(const char* a) const {
492
4814
    return strcmp(out(), a) == 0;
493
  }
494
};
495
496
class TwoByteValue : public MaybeStackBuffer<uint16_t> {
497
 public:
498
  explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
499
};
500
501
class BufferValue : public MaybeStackBuffer<char> {
502
 public:
503
  explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
504
505
  inline std::string ToString() const { return std::string(out(), length()); }
506
};
507
508
#define SPREAD_BUFFER_ARG(val, name)                                          \
509
  CHECK((val)->IsArrayBufferView());                                          \
510
  v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>();      \
511
  std::shared_ptr<v8::BackingStore> name##_bs =                               \
512
      name->Buffer()->GetBackingStore();                                      \
513
  const size_t name##_offset = name->ByteOffset();                            \
514
  const size_t name##_length = name->ByteLength();                            \
515
  char* const name##_data =                                                   \
516
      static_cast<char*>(name##_bs->Data()) + name##_offset;                  \
517
  if (name##_length > 0)                                                      \
518
    CHECK_NE(name##_data, nullptr);
519
520
// Use this when a variable or parameter is unused in order to explicitly
521
// silence a compiler warning about that.
522
4650168
template <typename T> inline void USE(T&&) {}
523
524
template <typename Fn>
525
struct OnScopeLeaveImpl {
526
  Fn fn_;
527
  bool active_;
528
529
3157120
  explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
530
1590416
  ~OnScopeLeaveImpl() { if (active_) fn_(); }
531
532
  OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
533
  OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
534
  OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
535
    : fn_(std::move(other.fn_)), active_(other.active_) {
536
    other.active_ = false;
537
  }
538
  OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
539
    if (this == &other) return *this;
540
    this->~OnScopeLeave();
541
    new (this)OnScopeLeaveImpl(std::move(other));
542
    return *this;
543
  }
544
};
545
546
// Run a function when exiting the current scope. Used like this:
547
// auto on_scope_leave = OnScopeLeave([&] {
548
//   // ... run some code ...
549
// });
550
template <typename Fn>
551
3157120
inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
552
3157120
  return OnScopeLeaveImpl<Fn>{std::move(fn)};
553
}
554
555
// Simple RAII wrapper for contiguous data that uses malloc()/free().
556
template <typename T>
557
struct MallocedBuffer {
558
  T* data;
559
  size_t size;
560
561
  T* release() {
562
    T* ret = data;
563
    data = nullptr;
564
    return ret;
565
  }
566
567
  void Truncate(size_t new_size) {
568
    CHECK(new_size <= size);
569
    size = new_size;
570
  }
571
572
  void Realloc(size_t new_size) {
573
    Truncate(new_size);
574
    data = UncheckedRealloc(data, new_size);
575
  }
576
577
60750
  inline bool is_empty() const { return data == nullptr; }
578
579
96156
  MallocedBuffer() : data(nullptr), size(0) {}
580
23
  explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
581
60763
  MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
582
156883
  MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
583
156883
    other.data = nullptr;
584
156883
  }
585
60777
  MallocedBuffer& operator=(MallocedBuffer&& other) {
586
60777
    this->~MallocedBuffer();
587
60777
    return *new(this) MallocedBuffer(std::move(other));
588
  }
589
313794
  ~MallocedBuffer() {
590
313794
    free(data);
591
313794
  }
592
  MallocedBuffer(const MallocedBuffer&) = delete;
593
  MallocedBuffer& operator=(const MallocedBuffer&) = delete;
594
};
595
596
template <typename T>
597
class NonCopyableMaybe {
598
 public:
599
4030
  NonCopyableMaybe() : empty_(true) {}
600
3804
  explicit NonCopyableMaybe(T&& value)
601
      : empty_(false),
602
7608
        value_(std::move(value)) {}
603
604
7556
  bool IsEmpty() const {
605
7556
    return empty_;
606
  }
607
608
1473
  const T* get() const {
609
1473
    return empty_ ? nullptr : &value_;
610
  }
611
612
24
  const T* operator->() const {
613
24
    CHECK(!empty_);
614
24
    return &value_;
615
  }
616
617
3709
  T&& Release() {
618
3709
    CHECK_EQ(empty_, false);
619
3709
    empty_ = true;
620
3709
    return std::move(value_);
621
  }
622
623
 private:
624
  bool empty_;
625
  T value_;
626
};
627
628
// Test whether some value can be called with ().
629
template <typename T, typename = void>
630
struct is_callable : std::is_function<T> { };
631
632
template <typename T>
633
struct is_callable<T, typename std::enable_if<
634
    std::is_same<decltype(void(&T::operator())), void>::value
635
    >::type> : std::true_type { };
636
637
template <typename T, void (*function)(T*)>
638
struct FunctionDeleter {
639
182894
  void operator()(T* pointer) const { function(pointer); }
640
  typedef std::unique_ptr<T, FunctionDeleter> Pointer;
641
};
642
643
template <typename T, void (*function)(T*)>
644
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
645
646
std::vector<std::string> SplitString(const std::string& in, char delim);
647
648
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
649
                                           std::string_view str,
650
                                           v8::Isolate* isolate = nullptr);
651
template <typename T, typename test_for_number =
652
    typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
653
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
654
                                           const T& number,
655
                                           v8::Isolate* isolate = nullptr);
656
template <typename T>
657
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
658
                                           const std::vector<T>& vec,
659
                                           v8::Isolate* isolate = nullptr);
660
template <typename T>
661
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
662
                                           const std::set<T>& set,
663
                                           v8::Isolate* isolate = nullptr);
664
template <typename T, typename U>
665
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
666
                                           const std::unordered_map<T, U>& map,
667
                                           v8::Isolate* isolate = nullptr);
668
669
// These macros expects a `Isolate* isolate` and a `Local<Context> context`
670
// to be in the scope.
671
#define READONLY_PROPERTY(obj, name, value)                                    \
672
  do {                                                                         \
673
    obj->DefineOwnProperty(                                                    \
674
           context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
675
        .Check();                                                              \
676
  } while (0)
677
678
#define READONLY_DONT_ENUM_PROPERTY(obj, name, var)                            \
679
  do {                                                                         \
680
    obj->DefineOwnProperty(                                                    \
681
           context,                                                            \
682
           OneByteString(isolate, name),                                       \
683
           var,                                                                \
684
           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum))    \
685
        .Check();                                                              \
686
  } while (0)
687
688
#define READONLY_FALSE_PROPERTY(obj, name)                                     \
689
  READONLY_PROPERTY(obj, name, v8::False(isolate))
690
691
#define READONLY_TRUE_PROPERTY(obj, name)                                      \
692
  READONLY_PROPERTY(obj, name, v8::True(isolate))
693
694
#define READONLY_STRING_PROPERTY(obj, name, str)                               \
695
  READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
696
697
// Variation on NODE_DEFINE_CONSTANT that sets a String value.
698
#define NODE_DEFINE_STRING_CONSTANT(target, name, constant)                    \
699
  do {                                                                         \
700
    v8::Isolate* isolate = target->GetIsolate();                               \
701
    v8::Local<v8::String> constant_name =                                      \
702
        v8::String::NewFromUtf8(isolate, name).ToLocalChecked();               \
703
    v8::Local<v8::String> constant_value =                                     \
704
        v8::String::NewFromUtf8(isolate, constant).ToLocalChecked();           \
705
    v8::PropertyAttribute constant_attributes =                                \
706
        static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);     \
707
    target                                                                     \
708
        ->DefineOwnProperty(isolate->GetCurrentContext(),                      \
709
                            constant_name,                                     \
710
                            constant_value,                                    \
711
                            constant_attributes)                               \
712
        .Check();                                                              \
713
  } while (0)
714
715
enum Endianness {
716
  kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
717
  kBigEndian
718
};
719
720
7983
inline enum Endianness GetEndianness() {
721
  // Constant-folded by the compiler.
722
  const union {
723
    uint8_t u8[2];
724
    uint16_t u16;
725
7983
  } u = {{1, 0}};
726
7983
  return u.u16 == 1 ? kLittleEndian : kBigEndian;
727
}
728
729
1
inline bool IsLittleEndian() {
730
1
  return GetEndianness() == kLittleEndian;
731
}
732
733
7982
inline bool IsBigEndian() {
734
7982
  return GetEndianness() == kBigEndian;
735
}
736
737
// Round up a to the next highest multiple of b.
738
template <typename T>
739
128398
constexpr T RoundUp(T a, T b) {
740
128398
  return a % b != 0 ? a + b - (a % b) : a;
741
}
742
743
// Align ptr to an `alignment`-bytes boundary.
744
template <typename T, typename U>
745
23652
constexpr T* AlignUp(T* ptr, U alignment) {
746
  return reinterpret_cast<T*>(
747
23652
      RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
748
}
749
750
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
751
 public:
752
  inline explicit SlicedArguments(
753
      const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
754
};
755
756
// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
757
// optimization for strong persistent handles.
758
class PersistentToLocal {
759
 public:
760
  // If persistent.IsWeak() == false, then do not call persistent.Reset()
761
  // while the returned Local<T> is still in scope, it will destroy the
762
  // reference to the object.
763
  template <class TypeName>
764
6641957
  static inline v8::Local<TypeName> Default(
765
      v8::Isolate* isolate,
766
      const v8::PersistentBase<TypeName>& persistent) {
767
6641957
    if (persistent.IsWeak()) {
768
4443317
      return PersistentToLocal::Weak(isolate, persistent);
769
    } else {
770
2198640
      return PersistentToLocal::Strong(persistent);
771
    }
772
  }
773
774
  // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
775
  // use with care!
776
  //
777
  // Do not call persistent.Reset() while the returned Local<T> is still in
778
  // scope, it will destroy the reference to the object.
779
  template <class TypeName>
780
34482360
  static inline v8::Local<TypeName> Strong(
781
      const v8::PersistentBase<TypeName>& persistent) {
782
    DCHECK(!persistent.IsWeak());
783
    return *reinterpret_cast<v8::Local<TypeName>*>(
784
34482360
        const_cast<v8::PersistentBase<TypeName>*>(&persistent));
785
  }
786
787
  template <class TypeName>
788
2327215
  static inline v8::Local<TypeName> Weak(
789
      v8::Isolate* isolate,
790
      const v8::PersistentBase<TypeName>& persistent) {
791
2327215
    return v8::Local<TypeName>::New(isolate, persistent);
792
  }
793
};
794
795
// Can be used as a key for std::unordered_map when lookup performance is more
796
// important than size and the keys are statically used to avoid redundant hash
797
// computations.
798
class FastStringKey {
799
 public:
800
  constexpr explicit FastStringKey(const char* name);
801
802
  struct Hash {
803
    constexpr size_t operator()(const FastStringKey& key) const;
804
  };
805
  constexpr bool operator==(const FastStringKey& other) const;
806
807
  constexpr const char* c_str() const;
808
809
 private:
810
  static constexpr size_t HashImpl(const char* str);
811
812
  const char* name_;
813
  size_t cached_hash_;
814
};
815
816
// Like std::static_pointer_cast but for unique_ptr with the default deleter.
817
template <typename T, typename U>
818
10598
std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
819
10598
  return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
820
}
821
822
#define MAYBE_FIELD_PTR(ptr, field) ptr == nullptr ? nullptr : &(ptr->field)
823
824
// Returns a non-zero code if it fails to open or read the file,
825
// aborts if it fails to close the file.
826
int ReadFileSync(std::string* result, const char* path);
827
}  // namespace node
828
829
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
830
831
#endif  // SRC_UTIL_H_