-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathArrayBuffer.hpp
148 lines (132 loc) · 5.23 KB
/
ArrayBuffer.hpp
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// ArrayBuffer.hpp
// react-native-nitro
//
// Created by Marc Rousavy on 14.07.24.
//
#pragma once
#include "OwningReference.hpp"
#include <jsi/jsi.h>
#include <thread>
#include <vector>
namespace margelo::nitro {
using namespace facebook;
using DeleteFn = std::function<void()>;
/**
* Represents a raw byte buffer that can be read from-, and
* written to- from both JavaScript and C++.
* `ArrayBuffer` is not thread-safe and does not lock multi-thread access.
*
* `ArrayBuffer` can either be a `JSArrayBuffer`, or a `NativeArrayBuffer`.
* - `NativeArrayBuffer`: Created from native (C++), and can either own the memory (`isOwner()`), or borrow it.
* - `JSArrayBuffer`: Received from JS, and will only be alive for as long as the JS Runtime is actually alive.
*
* Also, an `ArrayBuffer` can either own it's memory, or just borrow it's memory.
* - Owning = the `ArrayBuffer`'s `data()` is alive as long as the `ArrayBuffer` is alive.
* When this `ArrayBuffer` gets deleted, it will free the memory.
* - Borrowed = the `ArrayBuffer`'s `data()` might be deleted at any point from an external source (e.g. the JS garbage collector).
* When this `ArrayBuffer` gets deleted, the memory will not be freed explicitly, as someone else owns it.
*/
class ArrayBuffer : public jsi::MutableBuffer {
public:
ArrayBuffer() = default;
ArrayBuffer(const ArrayBuffer&) = delete;
ArrayBuffer(ArrayBuffer&&) = delete;
virtual ~ArrayBuffer() = default;
public:
/**
* Returns whether this `ArrayBuffer` is actually owning the data,
* or if it is just borrowed from an external source (either a native
* memory that we didn't allocate, or from JS - which can be deleted at any point).
*/
virtual bool isOwner() const noexcept = 0;
public:
/**
* Create a new `NativeArrayBuffer` that wraps the given data (without copy) of the given size,
* and calls `deleteFunc` in which `data` should be deleted.
*/
static std::shared_ptr<ArrayBuffer> wrap(uint8_t* data, size_t size, DeleteFn&& deleteFunc);
/**
* Create a new `NativeArrayBuffer` that copies the given data of the given size
* into a newly allocated buffer.
*/
static std::shared_ptr<ArrayBuffer> copy(uint8_t* data, size_t size);
/**
* Create a new `NativeArrayBuffer` that copies the given `std::vector`.
*/
static std::shared_ptr<ArrayBuffer> copy(std::vector<uint8_t>& data);
/**
* Create a new `NativeArrayBuffer` that allocates a new buffer of the given size.
*/
static std::shared_ptr<ArrayBuffer> allocate(size_t size);
[[deprecated("Use wrapBuffer(...) instead.")]]
static std::shared_ptr<ArrayBuffer> makeBuffer(uint8_t* data, size_t size, DeleteFn&& deleteFunc) {
return ArrayBuffer::wrap(data, size, std::move(deleteFunc));
}
};
/**
* Represents an `ArrayBuffer` that is allocated on the native (C++) side.
* It can either be "owning" or "borrowing".
*
* - Owning = the `ArrayBuffer`'s `data()` is alive as long as the `ArrayBuffer` is alive.
* When this `ArrayBuffer` gets deleted, it will free the memory.
* - Borrowed = the `ArrayBuffer`'s `data()` might be deleted at any point from an external source (e.g. the JS garbage collector).
* When this `ArrayBuffer` gets deleted, the memory will not be freed explicitly, as someone else owns it.
*
* It is safe to access `data()` and `size()` from any Thread, but there are no synchronization/mutexes implemented by default.
*/
class NativeArrayBuffer final : public ArrayBuffer {
public:
/**
* Create a new **owning** `ArrayBuffer`.
* The `ArrayBuffer` can be kept in memory, as C++ owns the data
* and will only delete it once this `ArrayBuffer` gets deleted.
*
* Once this `ArrayBuffer` goes out of scope, `deleteFunc` will be called.
* The caller is responsible for deleting the memory (`data`) here.
*/
NativeArrayBuffer(uint8_t* data, size_t size, DeleteFn&& deleteFunc);
~NativeArrayBuffer();
public:
uint8_t* data() override;
size_t size() const override;
bool isOwner() const noexcept override;
private:
uint8_t* _data;
size_t _size;
DeleteFn _deleteFunc;
};
/**
* Represents a JS-based `ArrayBuffer`.
*
* While it's underlying data might have been allocated on the native side (`NativeArrayBuffer`),
* we only have a JS reference to the `ArrayBuffer` object so it is considered a "borrowed"-resource.
*
* `data()` and `size()` can only be accessed synchronously on the JS Runtime Thread.
* If you want to access it elsewhere, copy the buffer first.
*
* If the JS ArrayBuffer (or it's JS Runtime) have already been deleted, `data()` returns `nullptr`.
*/
class JSArrayBuffer final : public ArrayBuffer {
public:
explicit JSArrayBuffer(jsi::Runtime* runtime, OwningReference<jsi::ArrayBuffer> jsReference);
~JSArrayBuffer();
public:
/**
* Gets the data this `ArrayBuffer` points to, or `nullptr` if it has already been deleted.
*/
uint8_t* data() override;
/**
* Gets the size of the data this `ArrayBuffer` points to, or `0` if it has already been deleted.
*/
size_t size() const override;
/**
* Returns `false` for JS-based ArrayBuffers.
*/
bool isOwner() const noexcept override;
private:
jsi::Runtime* _runtime;
OwningReference<jsi::ArrayBuffer> _jsReference;
std::thread::id _initialThreadId;
};
} // namespace margelo::nitro