GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/util.h Lines: 133 133 100.0 %
Date: 2020-09-06 22:14:11 Branches: 70 129 54.3 %

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

2458208
    CHECK_LT(index, length());
363
2458209
    return buf_[index];
364
  }
365
366
10698
  const T& operator[](size_t index) const {
367
10698
    CHECK_LT(index, length());
368
10698
    return buf_[index];
369
  }
370
371
5096825
  size_t length() const {
372
5096825
    return length_;
373
  }
374
375
  // Current maximum capacity of the buffer with which SetLength() can be used
376
  // without first calling AllocateSufficientStorage().
377
14311092
  size_t capacity() const {
378
14311092
    return capacity_;
379
  }
380
381
  // Make sure enough space for `storage` entries is available.
382
  // This method can be called multiple times throughout the lifetime of the
383
  // buffer, but once this has been called Invalidate() cannot be used.
384
  // Content of the buffer in the range [0, length()) is preserved.
385
5100263
  void AllocateSufficientStorage(size_t storage) {
386


5100263
    CHECK(!IsInvalidated());
387


5100270
    if (storage > capacity()) {
388
362848
      bool was_allocated = IsAllocated();
389


362848
      T* allocated_ptr = was_allocated ? buf_ : nullptr;
390
362848
      buf_ = Realloc(allocated_ptr, storage);
391
362848
      capacity_ = storage;
392





362848
      if (!was_allocated && length_ > 0)
393
2
        memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
394
    }
395
396
5100268
    length_ = storage;
397
5100268
  }
398
399
4908608
  void SetLength(size_t length) {
400
    // capacity() returns how much memory is actually available.
401

4908608
    CHECK_LE(length, capacity());
402
4908612
    length_ = length;
403
4908612
  }
404
405
4289384
  void SetLengthAndZeroTerminate(size_t length) {
406
    // capacity() returns how much memory is actually available.
407

4289384
    CHECK_LE(length + 1, capacity());
408
4289400
    SetLength(length);
409
410
    // T() is 0 for integer types, nullptr for pointers, etc.
411
4289404
    buf_[length] = T();
412
4289404
  }
413
414
  // Make derefencing this object return nullptr.
415
  // This method can be called multiple times throughout the lifetime of the
416
  // buffer, but once this has been called AllocateSufficientStorage() cannot
417
  // be used.
418
2
  void Invalidate() {
419
2
    CHECK(!IsAllocated());
420
2
    capacity_ = 0;
421
2
    length_ = 0;
422
2
    buf_ = nullptr;
423
2
  }
424
425
  // If the buffer is stored in the heap rather than on the stack.
426
6183947
  bool IsAllocated() const {
427





6183947
    return !IsInvalidated() && buf_ != buf_st_;
428
  }
429
430
  // If Invalidate() has been called.
431
11291762
  bool IsInvalidated() const {
432
11291762
    return buf_ == nullptr;
433
  }
434
435
  // Release ownership of the malloc'd buffer.
436
  // Note: This does not free the buffer.
437
74
  void Release() {
438

74
    CHECK(IsAllocated());
439
74
    buf_ = buf_st_;
440
74
    length_ = 0;
441
74
    capacity_ = arraysize(buf_st_);
442
74
  }
443
444
5805780
  MaybeStackBuffer()
445

83534621
      : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
446
    // Default to a zero-length, null-terminated buffer.
447
6228708
    buf_[0] = T();
448
5805790
  }
449
450
340892
  explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
451
340893
    AllocateSufficientStorage(storage);
452
340892
  }
453
454
5805763
  ~MaybeStackBuffer() {
455


5805763
    if (IsAllocated())
456
362772
      free(buf_);
457
5805768
  }
458
459
 private:
460
  size_t length_;
461
  // capacity of the malloc'ed buf_
462
  size_t capacity_;
463
  T* buf_;
464
  T buf_st_[kStackStorageSize];
465
};
466
467
// Provides access to an ArrayBufferView's storage, either the original,
468
// or for small data, a copy of it. This object's lifetime is bound to the
469
// original ArrayBufferView's lifetime.
470
template <typename T, size_t kStackStorageSize = 64>
471
class ArrayBufferViewContents {
472
 public:
473
1871
  ArrayBufferViewContents() = default;
474
475
  explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
476
  explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
477
  explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
478
  inline void Read(v8::Local<v8::ArrayBufferView> abv);
479
480
600572
  inline const T* data() const { return data_; }
481
2419003
  inline size_t length() const { return length_; }
482
483
 private:
484
  T stack_storage_[kStackStorageSize];
485
  T* data_ = nullptr;
486
  size_t length_ = 0;
487
};
488
489
3505764
class Utf8Value : public MaybeStackBuffer<char> {
490
 public:
491
  explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
492
493
813
  inline std::string ToString() const { return std::string(out(), length()); }
494
495
4814
  inline bool operator==(const char* a) const {
496
4814
    return strcmp(out(), a) == 0;
497
  }
498
};
499
500
602954
class TwoByteValue : public MaybeStackBuffer<uint16_t> {
501
 public:
502
  explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
503
};
504
505
180401
class BufferValue : public MaybeStackBuffer<char> {
506
 public:
507
  explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
508
509
  inline std::string ToString() const { return std::string(out(), length()); }
510
};
511
512
#define SPREAD_BUFFER_ARG(val, name)                                          \
513
  CHECK((val)->IsArrayBufferView());                                          \
514
  v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>();      \
515
  std::shared_ptr<v8::BackingStore> name##_bs =                               \
516
      name->Buffer()->GetBackingStore();                                      \
517
  const size_t name##_offset = name->ByteOffset();                            \
518
  const size_t name##_length = name->ByteLength();                            \
519
  char* const name##_data =                                                   \
520
      static_cast<char*>(name##_bs->Data()) + name##_offset;                  \
521
  if (name##_length > 0)                                                      \
522
    CHECK_NE(name##_data, nullptr);
523
524
// Use this when a variable or parameter is unused in order to explicitly
525
// silence a compiler warning about that.
526
2844140
template <typename T> inline void USE(T&&) {}
527
528
template <typename Fn>
529
struct OnScopeLeaveImpl {
530
  Fn fn_;
531
  bool active_;
532
533
1143341
  explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
534

1143267
  ~OnScopeLeaveImpl() { if (active_) fn_(); }
535
536
  OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
537
  OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
538
  OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
539
    : fn_(std::move(other.fn_)), active_(other.active_) {
540
    other.active_ = false;
541
  }
542
  OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
543
    if (this == &other) return *this;
544
    this->~OnScopeLeave();
545
    new (this)OnScopeLeaveImpl(std::move(other));
546
    return *this;
547
  }
548
};
549
550
// Run a function when exiting the current scope. Used like this:
551
// auto on_scope_leave = OnScopeLeave([&] {
552
//   // ... run some code ...
553
// });
554
template <typename Fn>
555
1143352
inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
556
1143352
  return OnScopeLeaveImpl<Fn>{std::move(fn)};
557
}
558
559
// Simple RAII wrapper for contiguous data that uses malloc()/free().
560
template <typename T>
561
struct MallocedBuffer {
562
  T* data;
563
  size_t size;
564
565
  T* release() {
566
    T* ret = data;
567
    data = nullptr;
568
    return ret;
569
  }
570
571
  void Truncate(size_t new_size) {
572
    CHECK(new_size <= size);
573
    size = new_size;
574
  }
575
576
  void Realloc(size_t new_size) {
577
    Truncate(new_size);
578
    data = UncheckedRealloc(data, new_size);
579
  }
580
581
54547
  inline bool is_empty() const { return data == nullptr; }
582
583
205693
  MallocedBuffer() : data(nullptr), size(0) {}
584
4
  explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
585
54552
  MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
586
446288
  MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
587
446288
    other.data = nullptr;
588
446288
  }
589
119422
  MallocedBuffer& operator=(MallocedBuffer&& other) {
590
119422
    this->~MallocedBuffer();
591
119426
    return *new(this) MallocedBuffer(std::move(other));
592
  }
593
706324
  ~MallocedBuffer() {
594
706324
    free(data);
595
706324
  }
596
  MallocedBuffer(const MallocedBuffer&) = delete;
597
  MallocedBuffer& operator=(const MallocedBuffer&) = delete;
598
};
599
600
template <typename T>
601
1351
class NonCopyableMaybe {
602
 public:
603
1
  NonCopyableMaybe() : empty_(true) {}
604
1350
  explicit NonCopyableMaybe(T&& value)
605
      : empty_(false),
606
1350
        value_(std::move(value)) {}
607
608
1351
  bool IsEmpty() const {
609
1351
    return empty_;
610
  }
611
612
1350
  T&& Release() {
613
1350
    CHECK_EQ(empty_, false);
614
1350
    empty_ = true;
615
1350
    return std::move(value_);
616
  }
617
618
 private:
619
  bool empty_;
620
  T value_;
621
};
622
623
// Test whether some value can be called with ().
624
template <typename T, typename = void>
625
struct is_callable : std::is_function<T> { };
626
627
template <typename T>
628
struct is_callable<T, typename std::enable_if<
629
    std::is_same<decltype(void(&T::operator())), void>::value
630
    >::type> : std::true_type { };
631
632
template <typename T, void (*function)(T*)>
633
struct FunctionDeleter {
634
429437
  void operator()(T* pointer) const { function(pointer); }
635
  typedef std::unique_ptr<T, FunctionDeleter> Pointer;
636
};
637
638
template <typename T, void (*function)(T*)>
639
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
640
641
std::vector<std::string> SplitString(const std::string& in, char delim);
642
643
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
644
                                           const std::string& str,
645
                                           v8::Isolate* isolate = nullptr);
646
template <typename T, typename test_for_number =
647
    typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
648
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
649
                                           const T& number,
650
                                           v8::Isolate* isolate = nullptr);
651
template <typename T>
652
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
653
                                           const std::vector<T>& vec,
654
                                           v8::Isolate* isolate = nullptr);
655
template <typename T, typename U>
656
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
657
                                           const std::unordered_map<T, U>& map,
658
                                           v8::Isolate* isolate = nullptr);
659
660
// These macros expects a `Isolate* isolate` and a `Local<Context> context`
661
// to be in the scope.
662
#define READONLY_PROPERTY(obj, name, value)                                    \
663
  do {                                                                         \
664
    obj->DefineOwnProperty(                                                    \
665
           context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
666
        .Check();                                                              \
667
  } while (0)
668
669
#define READONLY_DONT_ENUM_PROPERTY(obj, name, var)                            \
670
  do {                                                                         \
671
    obj->DefineOwnProperty(                                                    \
672
           context,                                                            \
673
           OneByteString(isolate, name),                                       \
674
           var,                                                                \
675
           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum))    \
676
        .Check();                                                              \
677
  } while (0)
678
679
#define READONLY_FALSE_PROPERTY(obj, name)                                     \
680
  READONLY_PROPERTY(obj, name, v8::False(isolate))
681
682
#define READONLY_TRUE_PROPERTY(obj, name)                                      \
683
  READONLY_PROPERTY(obj, name, v8::True(isolate))
684
685
#define READONLY_STRING_PROPERTY(obj, name, str)                               \
686
  READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
687
688
// Variation on NODE_DEFINE_CONSTANT that sets a String value.
689
#define NODE_DEFINE_STRING_CONSTANT(target, name, constant)                    \
690
  do {                                                                         \
691
    v8::Isolate* isolate = target->GetIsolate();                               \
692
    v8::Local<v8::String> constant_name =                                      \
693
        v8::String::NewFromUtf8(isolate, name).ToLocalChecked();               \
694
    v8::Local<v8::String> constant_value =                                     \
695
        v8::String::NewFromUtf8(isolate, constant).ToLocalChecked();           \
696
    v8::PropertyAttribute constant_attributes =                                \
697
        static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);     \
698
    target                                                                     \
699
        ->DefineOwnProperty(isolate->GetCurrentContext(),                      \
700
                            constant_name,                                     \
701
                            constant_value,                                    \
702
                            constant_attributes)                               \
703
        .Check();                                                              \
704
  } while (0)
705
706
enum Endianness {
707
  kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
708
  kBigEndian
709
};
710
711
19382
inline enum Endianness GetEndianness() {
712
  // Constant-folded by the compiler.
713
  const union {
714
    uint8_t u8[2];
715
    uint16_t u16;
716
19382
  } u = {{1, 0}};
717
19382
  return u.u16 == 1 ? kLittleEndian : kBigEndian;
718
}
719
720
1
inline bool IsLittleEndian() {
721
1
  return GetEndianness() == kLittleEndian;
722
}
723
724
19381
inline bool IsBigEndian() {
725
19381
  return GetEndianness() == kBigEndian;
726
}
727
728
// Round up a to the next highest multiple of b.
729
template <typename T>
730
121307
constexpr T RoundUp(T a, T b) {
731
121307
  return a % b != 0 ? a + b - (a % b) : a;
732
}
733
734
// Align ptr to an `alignment`-bytes boundary.
735
template <typename T, typename U>
736
23801
constexpr T* AlignUp(T* ptr, U alignment) {
737
  return reinterpret_cast<T*>(
738
23801
      RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
739
}
740
741
40545
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
742
 public:
743
  inline explicit SlicedArguments(
744
      const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
745
};
746
747
// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
748
// optimization for strong persistent handles.
749
class PersistentToLocal {
750
 public:
751
  // If persistent.IsWeak() == false, then do not call persistent.Reset()
752
  // while the returned Local<T> is still in scope, it will destroy the
753
  // reference to the object.
754
  template <class TypeName>
755
4816152
  static inline v8::Local<TypeName> Default(
756
      v8::Isolate* isolate,
757
      const v8::PersistentBase<TypeName>& persistent) {
758

4816152
    if (persistent.IsWeak()) {
759
2176546
      return PersistentToLocal::Weak(isolate, persistent);
760
    } else {
761
2639606
      return PersistentToLocal::Strong(persistent);
762
    }
763
  }
764
765
  // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
766
  // use with care!
767
  //
768
  // Do not call persistent.Reset() while the returned Local<T> is still in
769
  // scope, it will destroy the reference to the object.
770
  template <class TypeName>
771
16432741
  static inline v8::Local<TypeName> Strong(
772
      const v8::PersistentBase<TypeName>& persistent) {
773
    return *reinterpret_cast<v8::Local<TypeName>*>(
774
16432741
        const_cast<v8::PersistentBase<TypeName>*>(&persistent));
775
  }
776
777
  template <class TypeName>
778
2176545
  static inline v8::Local<TypeName> Weak(
779
      v8::Isolate* isolate,
780
      const v8::PersistentBase<TypeName>& persistent) {
781
2176545
    return v8::Local<TypeName>::New(isolate, persistent);
782
  }
783
};
784
785
// Can be used as a key for std::unordered_map when lookup performance is more
786
// important than size and the keys are statically used to avoid redundant hash
787
// computations.
788
class FastStringKey {
789
 public:
790
  constexpr explicit FastStringKey(const char* name);
791
792
4855
  struct Hash {
793
    constexpr size_t operator()(const FastStringKey& key) const;
794
  };
795
  constexpr bool operator==(const FastStringKey& other) const;
796
797
  constexpr const char* c_str() const;
798
799
 private:
800
  static constexpr size_t HashImpl(const char* str);
801
802
  const char* name_;
803
  size_t cached_hash_;
804
};
805
806
// Like std::static_pointer_cast but for unique_ptr with the default deleter.
807
template <typename T, typename U>
808
10411
std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
809
10411
  return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
810
}
811
812
#define MAYBE_FIELD_PTR(ptr, field) ptr == nullptr ? nullptr : &(ptr->field)
813
}  // namespace node
814
815
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
816
817
#endif  // SRC_UTIL_H_