forked from apache/arrow-nanoarrow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpointers.R
166 lines (153 loc) · 6.65 KB
/
pointers.R
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#' Danger zone: low-level pointer operations
#'
#' The [nanoarrow_schema][as_nanoarrow_schema],
#' [nanoarrow_array][as_nanoarrow_array],
#' and [nanoarrow_array_stream][as_nanoarrow_array_stream] classes are
#' represented in R as external pointers (`EXTPTRSXP`). When these objects
#' go out of scope (i.e., when they are garbage collected or shortly
#' thereafter), the underlying object's `release()` callback is called if
#' the underlying pointer is non-null and if the `release()` callback is
#' non-null.
#'
#' When interacting with other C Data Interface implementations, it is
#' important to keep in mind that the R object wrapping these pointers is
#' always passed by reference (because it is an external pointer) and may
#' be referred to by another R object (e.g., an element in a `list()` or as a
#' variable assigned in a user's environment). When importing a schema,
#' array, or array stream into nanoarrow this is not a problem: the R object
#' takes ownership of the lifecycle and memory is released when the R
#' object is garbage collected. In this case, one can use
#' [nanoarrow_pointer_move()] where `ptr_dst` was created using
#' `nanoarrow_allocate_*()`.
#'
#' The case of exporting is more complicated and as such has a dedicated
#' function, [nanoarrow_pointer_export()], that implements different logic
#' schemas, arrays, and array streams:
#'
#' - Schema objects are (deep) copied such that a fresh copy of the schema
#' is exported and made the responsibility of some other C data interface
#' implementation.
#' - Array objects are exported as a shell around the original array that
#' preserves a reference to the R object. This ensures that the buffers
#' and children pointed to by the array are not copied and that any references
#' to the original array are not invalidated.
#' - Array stream objects are moved: the responsibility for the object is
#' transferred to the other C data interface implementation and any
#' references to the original R object are invalidated. Because these
#' objects are mutable, this is typically what you want (i.e., you should
#' not be pulling arrays from a stream accidentally from two places).
#'
#' If you know the lifecycle of your object (i.e., you created the R object
#' yourself and never passed references to it elsewhere), you can slightly
#' more efficiently call [nanoarrow_pointer_move()] for all three pointer
#' types.
#'
#' @param ptr,ptr_src,ptr_dst An external pointer to a `struct ArrowSchema`,
#' `struct ArrowArray`, or `struct ArrowArrayStream`.
#' @param protected An object whose scope must outlive that of `ptr`. This is
#' useful for array streams since at least two specifications involving the
#' array stream specify that the stream is only valid for the lifecycle of
#' another object (e.g., an AdbcStatement or OGRDataset).
#' @return
#' - `nanoarrow_pointer_is_valid()` returns TRUE if the pointer is non-null
#' and has a non-null release callback.
#' - `nanoarrow_pointer_addr_dbl()` and `nanoarrow_pointer_addr_chr()` return
#' pointer representations that may be helpful to facilitate moving or
#' exporting nanoarrow objects to other libraries.
#' - `nanoarrow_pointer_addr_pretty()` gives a pointer representation suitable
#' for printing or error messages.
#' - `nanoarrow_pointer_release()` returns `ptr`, invisibly.
#' - `nanoarrow_pointer_move()` and `nanoarrow_pointer_export()` reeturn
#' `ptr_dst`, invisibly.
#' - `nanoarrow_allocate_array()`, `nanoarrow_allocate_schema()`, and
#' `nanoarrow_allocate_array_stream()` return an
#' [array][as_nanoarrow_array], a [schema][as_nanoarrow_schema], and an
#' [array stream][as_nanoarrow_array_stream], respectively.
#' @export
#'
nanoarrow_pointer_is_valid <- function(ptr) {
.Call(nanoarrow_c_pointer_is_valid, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_dbl <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_dbl, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_chr <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_chr, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_pretty <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_pretty, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_release <- function(ptr) {
invisible(.Call(nanoarrow_c_pointer_release, ptr))
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_move <- function(ptr_src, ptr_dst) {
invisible(.Call(nanoarrow_c_pointer_move, ptr_src, ptr_dst))
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_export <- function(ptr_src, ptr_dst) {
if (inherits(ptr_src, "nanoarrow_schema")) {
.Call(nanoarrow_c_export_schema, ptr_src, ptr_dst)
} else if (inherits(ptr_src, "nanoarrow_array")) {
.Call(nanoarrow_c_export_array, ptr_src, ptr_dst)
} else if (inherits(ptr_src, "nanoarrow_array_stream")) {
.Call(nanoarrow_c_export_array_stream, ptr_src, ptr_dst)
} else {
stop(
"`ptr_src` must inherit from 'nanoarrow_schema', 'nanoarrow_array', or 'nanoarrow_array_stream'"
)
}
invisible(ptr_dst)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_schema <- function() {
.Call(nanoarrow_c_allocate_schema)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_array <- function() {
.Call(nanoarrow_c_allocate_array)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_array_stream <- function() {
.Call(nanoarrow_c_allocate_array_stream)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_set_protected <- function(ptr_src, protected) {
if (!inherits(ptr_src, c("nanoarrow_schema", "nanoarrow_array", "nanoarrow_array_stream"))) {
stop(
"`ptr_src` must inherit from 'nanoarrow_schema', 'nanoarrow_array', or 'nanoarrow_array_stream'"
)
}
.Call(nanoarrow_c_pointer_set_protected, ptr_src, protected)
invisible(ptr_src)
}