summaryrefslogtreecommitdiff
path: root/src/node_union_bytes.h
blob: 33fada73039e2c554397c05e45bd731e0b46ef73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

#ifndef SRC_NODE_UNION_BYTES_H_
#define SRC_NODE_UNION_BYTES_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

// A union of const uint8_t* or const uint16_t* data that can be
// turned into external v8::String when given an isolate.

#include "env.h"
#include "v8.h"

namespace node {

class NonOwningExternalOneByteResource
    : public v8::String::ExternalOneByteStringResource {
 public:
  explicit NonOwningExternalOneByteResource(const uint8_t* data, size_t length)
      : data_(data), length_(length) {}
  ~NonOwningExternalOneByteResource() override = default;

  const char* data() const override {
    return reinterpret_cast<const char*>(data_);
  }
  size_t length() const override { return length_; }

 private:
  const uint8_t* data_;
  size_t length_;
  DISALLOW_COPY_AND_ASSIGN(NonOwningExternalOneByteResource);
};

class NonOwningExternalTwoByteResource
    : public v8::String::ExternalStringResource {
 public:
  explicit NonOwningExternalTwoByteResource(const uint16_t* data, size_t length)
      : data_(data), length_(length) {}
  ~NonOwningExternalTwoByteResource() override = default;

  const uint16_t* data() const override { return data_; }
  size_t length() const override { return length_; }

 private:
  const uint16_t* data_;
  size_t length_;
  DISALLOW_COPY_AND_ASSIGN(NonOwningExternalTwoByteResource);
};

// Similar to a v8::String, but it's independent from Isolates
// and can be materialized in Isolates as external Strings
// via ToStringChecked. The data pointers are owned by the caller.
class UnionBytes {
 public:
  UnionBytes(const uint16_t* data, size_t length)
      : is_one_byte_(false), two_bytes_(data), length_(length) {}
  UnionBytes(const uint8_t* data, size_t length)
      : is_one_byte_(true), one_bytes_(data), length_(length) {}

  UnionBytes(const UnionBytes&) = default;
  UnionBytes& operator=(const UnionBytes&) = default;
  UnionBytes(UnionBytes&&) = default;
  UnionBytes& operator=(UnionBytes&&) = default;

  bool is_one_byte() const { return is_one_byte_; }
  const uint16_t* two_bytes_data() const {
    CHECK(!is_one_byte_);
    CHECK_NOT_NULL(two_bytes_);
    return two_bytes_;
  }
  const uint8_t* one_bytes_data() const {
    CHECK(is_one_byte_);
    CHECK_NOT_NULL(one_bytes_);
    return one_bytes_;
  }
  v8::Local<v8::String> ToStringChecked(v8::Isolate* isolate) const {
    if (is_one_byte_) {
      CHECK_NOT_NULL(one_bytes_);
      NonOwningExternalOneByteResource* source =
          new NonOwningExternalOneByteResource(one_bytes_, length_);
      return v8::String::NewExternalOneByte(isolate, source).ToLocalChecked();
    } else {
      CHECK_NOT_NULL(two_bytes_);
      NonOwningExternalTwoByteResource* source =
          new NonOwningExternalTwoByteResource(two_bytes_, length_);
      return v8::String::NewExternalTwoByte(isolate, source).ToLocalChecked();
    }
  }
  size_t length() { return length_; }

 private:
  bool is_one_byte_;
  union {
    const uint8_t* one_bytes_;
    const uint16_t* two_bytes_;
  };
  size_t length_;
};

}  // namespace node

#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif  // SRC_NODE_UNION_BYTES_H_