@auto_js/napi 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/transfer/visit.cc CHANGED
@@ -1,5 +1,5 @@
1
1
  export module napi_js:visit;
2
- import :container;
2
+ import :utility;
3
3
  import :value;
4
4
  import std;
5
5
  import util;
@@ -10,7 +10,7 @@ namespace js::napi {
10
10
  // Instantiated in the acceptor that corresponds to a napi visitor
11
11
  struct reference_map_type {
12
12
  template <class Type>
13
- using type = napi::value_map<Type>;
13
+ using type = napi::unordered_value_map<Type>;
14
14
  };
15
15
 
16
16
  // Visitor which may visit only property names. `symbol` should probably be rethought since they are
@@ -104,7 +104,6 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
104
104
  using reference_map_t<Reference, reference_map_type>::lookup_or_visit;
105
105
 
106
106
  visit_value(auto* /*transfer*/, Environment& env) :
107
- reference_map_t<Reference, reference_map_type>{env},
108
107
  env_{env} {}
109
108
 
110
109
  // If the private `immediate` operation is defined: this public operation will first
@@ -135,7 +134,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
135
134
 
136
135
  template <class Accept>
137
136
  auto operator()(value_of<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
138
- if (std::bit_cast<v8::Local<v8::Number>>(subject)->IsInt32()) {
137
+ if (maybe_is_number_int32(subject).value_or(false)) {
139
138
  return immediate(value_of<number_tag_of<std::int32_t>>::from(subject), accept);
140
139
  } else {
141
140
  return immediate(value_of<number_tag_of<double>>::from(subject), accept);
@@ -153,81 +152,96 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
153
152
 
154
153
  // Check the reference map, and lookup type via napi
155
154
  return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
156
- auto v8_subject = std::bit_cast<v8::Local<v8::Value>>(subject);
157
- return util::template_traverse(
158
- accept_tags_of_v<Accept>,
159
- util::overloaded{
160
- // Fast paths
161
- [ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
162
- return v8_subject->IsUndefined() ? (*this)(value_of<undefined_tag>::from(subject), accept) : next();
163
- },
164
- [ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
165
- return v8_subject->IsNull() ? (*this)(value_of<null_tag>::from(subject), accept) : next();
166
- },
167
- [ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
168
- return v8_subject->IsBoolean() ? (*this)(value_of<boolean_tag>::from(subject), accept) : next();
169
- },
170
- [ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
171
- return v8_subject->IsNumber() ? (*this)(value_of<number_tag>::from(subject), accept) : next();
172
- },
173
- [ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
174
- return v8_subject->IsString() ? immediate(value_of<string_tag>::from(subject), accept) : next();
175
- },
176
- [ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
177
- return v8_subject->IsBigInt() ? immediate(value_of<bigint_tag>::from(subject), accept) : next();
178
- },
179
- [ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
180
- return v8_subject->IsDate() ? immediate(value_of<date_tag>::from(subject), accept) : next();
181
- },
182
- [ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
183
- return v8_subject->IsArray() ? immediate(value_of<list_tag>::from(subject), accept) : next();
184
- },
185
- [ & ](object_tag /*tag*/, auto next) -> accept_target_t<Accept> {
186
- // nb: You can't really skip the subsequent is promise, is date, is arraybuffer, etc
187
- // checks. We don't really want to accept those types here, I don't think..
188
- return v8_subject->IsObject() ? immediate(value_of<object_tag>::from(subject), accept) : next();
189
- },
190
- [ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
191
- return v8_subject->IsFunction() ? immediate(value_of<function_tag>::from(subject), accept) : next();
192
- },
193
-
194
- // Skip these, otherwise `number_tag` and `string_tag` are invoked twice, which we don't
195
- // differentiate between.
196
- []<class Type>(number_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
197
- []<class Type>(string_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
198
-
199
- // Unknown tag
200
- [](auto /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
155
+ // This is the pure-napi implementation
156
+ auto slow_path = util::overloaded{
157
+ [ & ]() -> accept_target_t<Accept> {
158
+ auto type_of = napi::invoke(napi_typeof, napi_env{*this}, subject);
159
+ switch (type_of) {
160
+ case napi_undefined:
161
+ return (*this)(value_of<undefined_tag>::from(subject), accept);
162
+ case napi_null:
163
+ return (*this)(value_of<null_tag>::from(subject), accept);
164
+ case napi_boolean:
165
+ return (*this)(value_of<boolean_tag>::from(subject), accept);
166
+ case napi_number:
167
+ return (*this)(value_of<number_tag>::from(subject), accept);
168
+ case napi_string:
169
+ return immediate(value_of<string_tag>::from(subject), accept);
170
+ case napi_symbol:
171
+ return immediate(value_of<symbol_tag>::from(subject), accept);
172
+ case napi_object:
173
+ return immediate(value_of<object_tag>::from(subject), accept);
174
+ case napi_function:
175
+ return immediate(value_of<function_tag>::from(subject), accept);
176
+ case napi_external:
177
+ return immediate(value_of<external_tag>::from(subject), accept);
178
+ case napi_bigint:
179
+ return immediate(value_of<bigint_tag>::from(subject), accept);
180
+ }
181
+ std::unreachable();
182
+ },
201
183
 
202
- // Slow path
203
- [ & ]() -> accept_target_t<Accept> {
204
- auto type_of = napi::invoke(napi_typeof, napi_env{*this}, subject);
205
- switch (type_of) {
206
- case napi_undefined:
207
- return (*this)(value_of<undefined_tag>::from(subject), accept);
208
- case napi_null:
209
- return (*this)(value_of<null_tag>::from(subject), accept);
210
- case napi_boolean:
211
- return (*this)(value_of<boolean_tag>::from(subject), accept);
212
- case napi_number:
213
- return (*this)(value_of<number_tag>::from(subject), accept);
214
- case napi_string:
215
- return immediate(value_of<string_tag>::from(subject), accept);
216
- case napi_symbol:
217
- return immediate(value_of<symbol_tag>::from(subject), accept);
218
- case napi_object:
219
- return immediate(value_of<object_tag>::from(subject), accept);
220
- case napi_function:
221
- return immediate(value_of<function_tag>::from(subject), accept);
222
- case napi_external:
223
- return immediate(value_of<external_tag>::from(subject), accept);
224
- case napi_bigint:
225
- return immediate(value_of<bigint_tag>::from(subject), accept);
226
- }
227
- std::unreachable();
228
- },
229
- }
230
- );
184
+ [](auto /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
185
+ };
186
+
187
+ // Universal fast checks
188
+ auto fast_path = util::overloaded{
189
+ [ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
190
+ return fast_is_undefined(napi_env{*this}, subject) ? (*this)(value_of<undefined_tag>::from(subject), accept) : next();
191
+ },
192
+ [ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
193
+ return fast_is_null(napi_env{*this}, subject) ? (*this)(value_of<null_tag>::from(subject), accept) : next();
194
+ },
195
+ [ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
196
+ if (fast_is_false(napi_env{*this}, subject)) {
197
+ return (*this)(value_of<false_tag>::from(subject), accept);
198
+ } else if (fast_is_true(napi_env{*this}, subject)) {
199
+ return (*this)(value_of<true_tag>::from(subject), accept);
200
+ } else {
201
+ return next();
202
+ }
203
+ },
204
+ };
205
+
206
+ // Extended fast checks
207
+ auto extended_fast_path = util::overloaded{
208
+ [ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
209
+ return fast_is_number(subject) ? (*this)(value_of<number_tag>::from(subject), accept) : next();
210
+ },
211
+ [ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
212
+ return fast_is_string(subject) ? immediate(value_of<string_tag>::from(subject), accept) : next();
213
+ },
214
+ [ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
215
+ return fast_is_bigint(subject) ? immediate(value_of<bigint_tag>::from(subject), accept) : next();
216
+ },
217
+ [ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
218
+ return napi::invoke(napi_is_date, napi_env{*this}, subject) ? immediate(value_of<date_tag>::from(subject), accept) : next();
219
+ },
220
+ [ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
221
+ return fast_is_array(subject) ? immediate(value_of<list_tag>::from(subject), accept) : next();
222
+ },
223
+ [ & ](object_tag /*tag*/, auto next) -> accept_target_t<Accept> {
224
+ // nb: You can't really skip the subsequent is promise, is date, is arraybuffer, etc
225
+ // checks. We don't really want to accept those types here, I don't think..
226
+ return fast_is_object(subject) ? immediate(value_of<object_tag>::from(subject), accept) : next();
227
+ },
228
+ [ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
229
+ return fast_is_function(subject) ? immediate(value_of<function_tag>::from(subject), accept) : next();
230
+ },
231
+
232
+ // Skip these, otherwise `number_tag` and `string_tag` are invoked twice, which we don't
233
+ // differentiate between.
234
+ []<class Type>(number_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
235
+ []<class Type>(string_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
236
+ };
237
+
238
+ if (has_extended_fast_is_functions) {
239
+ auto traverse = util::overloaded{fast_path, extended_fast_path, slow_path};
240
+ return util::template_traverse(accept_tags_of_v<Accept>, traverse);
241
+ } else {
242
+ auto traverse = util::overloaded{fast_path, slow_path};
243
+ return util::template_traverse(accept_tags_of_v<Accept>, traverse);
244
+ }
231
245
  });
232
246
  }
233
247
 
@@ -267,10 +281,10 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
267
281
  // strings
268
282
  template <class Accept>
269
283
  auto immediate(value_of<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
270
- if (std::bit_cast<v8::Local<v8::String>>(subject)->IsOneByte()) {
271
- return accept_tagged(value_of<string_tag_of<char16_t>>::from(subject), accept);
272
- } else {
284
+ if (maybe_is_string_latin1(subject).value_or(false)) {
273
285
  return accept_tagged(value_of<string_tag_of<char>>::from(subject), accept);
286
+ } else {
287
+ return accept_tagged(value_of<string_tag_of<char16_t>>::from(subject), accept);
274
288
  }
275
289
  }
276
290
 
@@ -291,9 +305,9 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
291
305
  return immediate(value_of<typed_array_tag>::from(subject), accept);
292
306
  } else if (napi::invoke(napi_is_dataview, napi_env{*this}, subject)) {
293
307
  return immediate(value_of<data_view_tag>::from(subject), accept);
294
- } else if (std::bit_cast<v8::Local<v8::Object>>(subject)->IsSharedArrayBuffer()) {
308
+ } else if (maybe_is_shared_array_buffer(env_.get(), subject).value_or(false)) {
295
309
  return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
296
- } else if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
310
+ } else if (is_object_array_buffer(env_.get(), subject)) {
297
311
  return immediate(value_of<array_buffer_tag>::from(subject), accept);
298
312
  } else if (napi::invoke(napi_is_promise, napi_env{*this}, subject)) {
299
313
  return immediate(value_of<promise_tag>::from(subject), accept);
@@ -311,7 +325,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
311
325
  // data blocks
312
326
  template <class Accept>
313
327
  auto immediate(value_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
314
- if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
328
+ if (is_data_block_array_buffer(env_.get(), subject)) {
315
329
  return immediate(value_of<array_buffer_tag>::from(subject), accept);
316
330
  } else {
317
331
  return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
@@ -1,6 +1,7 @@
1
1
  module napi_js;
2
2
  import :api;
3
3
  import :array_buffer;
4
+ import :support.host;
4
5
  import std;
5
6
  import v8;
6
7
 
@@ -8,18 +9,6 @@ namespace js::napi {
8
9
 
9
10
  // `bound_value_for_data_block`
10
11
  bound_value_for_data_block::operator std::span<std::byte>() const {
11
- auto local = std::bit_cast<v8::Local<v8::ArrayBuffer>>(napi_value{*this});
12
- auto* data = reinterpret_cast<std::byte*>(local->Data());
13
- auto byte_length = local->ByteLength();
14
- return std::span{data, byte_length};
15
- }
16
-
17
- // `bound_value_for_array_buffer`
18
- bound_value_for_array_buffer::operator js::array_buffer() const {
19
- return js::array_buffer{std::span<std::byte>{*this}};
20
- }
21
-
22
- bound_value_for_array_buffer::operator std::span<std::byte>() const {
23
12
  // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
24
13
  void* bytes;
25
14
  // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
@@ -28,18 +17,16 @@ bound_value_for_array_buffer::operator std::span<std::byte>() const {
28
17
  return std::span{reinterpret_cast<std::byte*>(bytes), byte_length};
29
18
  }
30
19
 
31
- // `bound_value_for_shared_array_buffer`
32
- bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
33
- auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
34
- auto backing_store = local->GetBackingStore();
35
- auto* data = reinterpret_cast<std::byte*>(backing_store->Data());
36
- auto data_shared_ptr = std::shared_ptr<js::shared_array_buffer::array_type>{std::move(backing_store), data};
37
- return js::shared_array_buffer{local->ByteLength(), std::move(data_shared_ptr)};
20
+ // `bound_value_for_array_buffer`
21
+ bound_value_for_array_buffer::operator js::array_buffer() const {
22
+ return js::array_buffer{std::span<std::byte>{*this}};
38
23
  }
39
24
 
40
- bound_value_for_shared_array_buffer::operator std::span<std::byte>() const {
41
- auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
42
- return std::span{reinterpret_cast<std::byte*>(local->Data()), local->ByteLength()};
25
+ // `bound_value_for_shared_array_buffer`
26
+ bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
27
+ auto byte_length = shared_array_buffer_get_byte_length(value_of{*this});
28
+ auto backing_store = shared_array_buffer_get_backing_store(value_of{*this});
29
+ return js::shared_array_buffer{byte_length, std::move(backing_store)};
43
30
  }
44
31
 
45
32
  // `value_for_typed_array`
@@ -92,9 +79,7 @@ auto value_for_data_view::make(const environment& env, value_of<array_buffer_tag
92
79
  }
93
80
 
94
81
  auto value_for_data_view::make(const environment& /*env*/, value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
95
- auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
96
- auto view_local = v8::DataView::New(buffer_local, byte_offset, length);
97
- return value_of<data_view_tag>::from(std::bit_cast<napi_value>(view_local));
82
+ return make_sab_data_view(buffer, byte_offset, length);
98
83
  }
99
84
 
100
85
  // `bound_value_for_data_view`
@@ -20,20 +20,14 @@ class bound_value_for_data_block : public bound_value_next<data_block_tag> {
20
20
  class bound_value_for_array_buffer : public bound_value_next<array_buffer_tag> {
21
21
  public:
22
22
  using bound_value_next<array_buffer_tag>::bound_value_next;
23
- [[nodiscard]] constexpr auto byte_length() const -> std::size_t { return std::span<std::byte>{*this}.size(); }
24
- [[nodiscard]] constexpr auto data() const -> const std::byte* { return std::span<std::byte>{*this}.data(); }
25
23
  explicit operator js::array_buffer() const;
26
- explicit operator std::span<std::byte>() const;
27
24
  };
28
25
 
29
26
  // `SharedArrayBuffer`
30
27
  class bound_value_for_shared_array_buffer : public bound_value_next<shared_array_buffer_tag> {
31
28
  public:
32
29
  using bound_value_next<shared_array_buffer_tag>::bound_value_next;
33
- [[nodiscard]] constexpr auto byte_length() const -> std::size_t { return std::span<std::byte>{*this}.size(); }
34
- [[nodiscard]] constexpr auto data() const -> const std::byte* { return std::span<std::byte>{*this}.data(); }
35
30
  explicit operator js::shared_array_buffer() const;
36
- explicit operator std::span<std::byte>() const;
37
31
  };
38
32
 
39
33
  // `ArrayBufferView` (hidden superclass of `TypedArray` and `DataView`)
@@ -120,23 +114,7 @@ class value_for_typed_array_of : public value_next<typed_array_tag_of<Type>> {
120
114
 
121
115
  // napi doesn't provide a way to make a typed array view on a shared array buffer
122
116
  static auto make(const environment& /*env*/, value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag_of<Type>> {
123
- using constructor_type = type_t<util::overloaded{
124
- [](std::type_identity<double>) -> std::type_identity<v8::Float64Array> { return {}; },
125
- [](std::type_identity<float>) -> std::type_identity<v8::Float32Array> { return {}; },
126
- [](std::type_identity<js::float16_t>) -> std::type_identity<v8::Float16Array> { return {}; },
127
- [](std::type_identity<js::uint8_clamped_t>) -> std::type_identity<v8::Uint8ClampedArray> { return {}; },
128
- [](std::type_identity<std::int16_t>) -> std::type_identity<v8::Int16Array> { return {}; },
129
- [](std::type_identity<std::int32_t>) -> std::type_identity<v8::Int32Array> { return {}; },
130
- [](std::type_identity<std::int64_t>) -> std::type_identity<v8::BigInt64Array> { return {}; },
131
- [](std::type_identity<std::int8_t>) -> std::type_identity<v8::Int8Array> { return {}; },
132
- [](std::type_identity<std::uint16_t>) -> std::type_identity<v8::Uint16Array> { return {}; },
133
- [](std::type_identity<std::uint32_t>) -> std::type_identity<v8::Uint32Array> { return {}; },
134
- [](std::type_identity<std::uint64_t>) -> std::type_identity<v8::BigUint64Array> { return {}; },
135
- [](std::type_identity<std::uint8_t>) -> std::type_identity<v8::Uint8Array> { return {}; },
136
- }(type<Type>)>;
137
- auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
138
- auto view_local = constructor_type::New(buffer_local, byte_offset, length);
139
- return value_of<typed_array_tag_of<Type>>::from(std::bit_cast<napi_value>(view_local));
117
+ return make_sab_typed_array_of<Type>(buffer, byte_offset, length);
140
118
  }
141
119
  };
142
120
 
package/value/class.cc CHANGED
@@ -42,7 +42,7 @@ auto value_for_class_of<Type>::transfer_construct(auto& env, auto instance, std:
42
42
  napi::invoke0(napi_type_tag_object, napi_env{env}, this_arg, &type_tag_for<element_type>);
43
43
 
44
44
  // Wrap w/ finalizer
45
- return apply_finalizer(std::move(instance), [ & ](element_type* instance, napi_finalize finalize, void* hint) -> napi_value {
45
+ return apply_finalizer(std::move(instance), [ & ](element_type* instance, node_api_basic_finalize finalize, void* hint) -> napi_value {
46
46
  napi::invoke0(napi_wrap, napi_env{env}, this_arg, instance, finalize, hint, nullptr);
47
47
  return this_arg;
48
48
  });
@@ -13,6 +13,19 @@ class bound_value_for_boolean : public bound_value_next<boolean_tag> {
13
13
  using bound_value_next<boolean_tag>::bound_value_next;
14
14
  [[nodiscard]] explicit operator bool() const;
15
15
  };
16
+
17
+ class bound_value_for_false : public bound_value_next<false_tag> {
18
+ public:
19
+ using bound_value_next<false_tag>::bound_value_next;
20
+ [[nodiscard]] constexpr explicit operator bool() const { return false; }
21
+ };
22
+
23
+ class bound_value_for_true : public bound_value_next<true_tag> {
24
+ public:
25
+ using bound_value_next<true_tag>::bound_value_next;
26
+ [[nodiscard]] constexpr explicit operator bool() const { return true; }
27
+ };
28
+
16
29
  // number
17
30
  class bound_value_for_number : public bound_value_next<number_tag> {
18
31
  public:
@@ -1,77 +0,0 @@
1
- export module napi_js:container;
2
- import :environment;
3
- import nodejs;
4
- import std;
5
- import util;
6
-
7
- namespace js::napi {
8
-
9
- // Map container for napi values
10
- template <class Type>
11
- struct virtual_value_map {
12
- public:
13
- using container_type = std::unordered_map<napi_value, Type>;
14
- using iterator = container_type::iterator;
15
- using key_type = container_type::key_type;
16
- using mapped_type = container_type::mapped_type;
17
-
18
- virtual auto end() const -> iterator = 0;
19
- virtual auto find(napi_value key) const -> iterator = 0;
20
- virtual auto try_emplace(napi_value key, Type value) -> std::pair<iterator, bool> = 0;
21
- };
22
-
23
- template <class Map>
24
- struct concrete_value_map final : virtual_value_map<typename Map::mapped_type> {
25
- public:
26
- using container_type = Map;
27
- using typename virtual_value_map<typename Map::mapped_type>::mapped_type;
28
- using typename virtual_value_map<typename Map::mapped_type>::iterator;
29
-
30
- virtual auto end() const -> iterator {
31
- return std::bit_cast<iterator>(map_.end());
32
- }
33
-
34
- virtual auto find(napi_value key) const -> iterator {
35
- // nb: The iterator type between `std::unordered_map<int, int, left>` and
36
- // `std::unordered_map<int, int, right>` are not technically compatible.
37
- return std::bit_cast<iterator>(map_.find(key));
38
- }
39
-
40
- virtual auto try_emplace(napi_value key, mapped_type value) -> std::pair<iterator, bool> {
41
- auto [ it, inserted ] = map_.try_emplace(key, std::move(value));
42
- return std::pair{std::bit_cast<iterator>(it), inserted};
43
- }
44
-
45
- private:
46
- container_type map_;
47
- };
48
-
49
- export template <class Type>
50
- class value_map {
51
- private:
52
- using direct_map_type = concrete_value_map<std::unordered_map<napi_value, Type, direct_address_hash, direct_address_equal>>;
53
- using indirect_map_type = concrete_value_map<std::unordered_map<napi_value, Type, indirect_address_hash, indirect_address_equal>>;
54
- using virtual_map_type = util::covariant_value<virtual_value_map<Type>, direct_map_type, indirect_map_type>;
55
-
56
- public:
57
- using container_type = virtual_value_map<Type>;
58
- using iterator = container_type::iterator;
59
- using key_type = container_type::key_type;
60
- using mapped_type = container_type::mapped_type;
61
-
62
- explicit value_map(const environment& env) :
63
- map_{
64
- env.uses_direct_handles()
65
- ? virtual_map_type{direct_map_type{}}
66
- : virtual_map_type{indirect_map_type{}}
67
- } {}
68
-
69
- auto end() const -> iterator { return map_->end(); }
70
- auto find(key_type key) const -> iterator { return map_->find(key); }
71
- auto try_emplace(key_type key, mapped_type value) -> std::pair<iterator, bool> { return map_->try_emplace(key, std::move(value)); }
72
-
73
- private:
74
- virtual_map_type map_;
75
- };
76
-
77
- } // namespace js::napi