forked from ruby/ruby
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmemory_view.h
325 lines (274 loc) · 10.8 KB
/
memory_view.h
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#ifndef RUBY_MEMORY_VIEW_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_MEMORY_VIEW_H 1
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Memory View.
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h> /* size_t */
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> /* ssize_t */
#endif
#include "ruby/internal/attr/pure.h" /* RBIMPL_ATTR_PURE */
#include "ruby/internal/core/rtypeddata.h" /* rb_data_type_t */
#include "ruby/internal/dllexport.h" /* RUBY_EXTERN */
#include "ruby/internal/stdbool.h" /* bool */
#include "ruby/internal/value.h" /* VALUE */
/**
* Flags passed to rb_memory_view_get(), then to ::rb_memory_view_get_func_t.
*/
enum ruby_memory_view_flags {
RUBY_MEMORY_VIEW_SIMPLE = 0,
RUBY_MEMORY_VIEW_WRITABLE = (1<<0),
RUBY_MEMORY_VIEW_FORMAT = (1<<1),
RUBY_MEMORY_VIEW_MULTI_DIMENSIONAL = (1<<2),
RUBY_MEMORY_VIEW_STRIDES = (1<<3) | RUBY_MEMORY_VIEW_MULTI_DIMENSIONAL,
RUBY_MEMORY_VIEW_ROW_MAJOR = (1<<4) | RUBY_MEMORY_VIEW_STRIDES,
RUBY_MEMORY_VIEW_COLUMN_MAJOR = (1<<5) | RUBY_MEMORY_VIEW_STRIDES,
RUBY_MEMORY_VIEW_ANY_CONTIGUOUS = RUBY_MEMORY_VIEW_ROW_MAJOR | RUBY_MEMORY_VIEW_COLUMN_MAJOR,
RUBY_MEMORY_VIEW_INDIRECT = (1<<6) | RUBY_MEMORY_VIEW_STRIDES,
};
/** Memory view component metadata. */
typedef struct {
/** @see ::rb_memory_view_t::format */
char format;
/** :FIXME: what is a "native" size is unclear. */
bool native_size_p;
/** Endian of the component */
bool little_endian_p;
/** The component's offset. */
size_t offset;
/** The component's size. */
size_t size;
/**
* How many numbers of components are there. For instance "CCC"'s repeat is
* 3.
*/
size_t repeat;
} rb_memory_view_item_component_t;
/**
* A MemoryView structure, `rb_memory_view_t`, is used for exporting objects'
* MemoryView.
*
* This structure contains the reference of the object, which is the owner of
* the MemoryView, the pointer to the head of exported memory, and the metadata
* that describes the structure of the memory. The metadata can describe
* multidimensional arrays with strides.
*/
typedef struct {
/**
* The original object that has the memory exported via this memory view.
*/
VALUE obj;
/** The pointer to the exported memory. */
void *data;
/** The number of bytes in data. */
ssize_t byte_size;
/** true for readonly memory, false for writable memory. */
bool readonly;
/**
* A string to describe the format of an element, or NULL for unsigned bytes.
* The format string is a sequence of the following pack-template specifiers:
*
* c, C, s, s!, S, S!, n, v, i, i!, I, I!, l, l!, L, L!,
* N, V, f, e, g, q, q!, Q, Q!, d, E, G, j, J, x
*
* For example, "dd" for an element that consists of two double values,
* and "CCC" for an element that consists of three bytes, such as
* an RGB color triplet.
*
* Also, the value endianness can be explicitly specified by '<' or '>'
* following a value type specifier.
*
* The items are packed contiguously. When you emulate the alignment of
* structure members, put '|' at the beginning of the format string,
* like "|iqc". On x86_64 Linux ABI, the size of the item by this format
* is 24 bytes instead of 13 bytes.
*/
const char *format;
/**
* The number of bytes in each element.
* item_size should equal to rb_memory_view_item_size_from_format(format). */
ssize_t item_size;
/** Description of each components. */
struct {
/**
* The array of rb_memory_view_item_component_t that describes the
* item structure. rb_memory_view_prepare_item_desc and
* rb_memory_view_get_item allocate this memory if needed,
* and rb_memory_view_release frees it. */
const rb_memory_view_item_component_t *components;
/** The number of components in an item. */
size_t length;
} item_desc;
/** The number of dimension. */
ssize_t ndim;
/**
* ndim size array indicating the number of elements in each dimension.
* This can be NULL when ndim == 1. */
const ssize_t *shape;
/**
* ndim size array indicating the number of bytes to skip to go to the
* next element in each dimension. */
const ssize_t *strides;
/**
* The offset in each dimension when this memory view exposes a nested array.
* Or, NULL when this memory view exposes a flat array. */
const ssize_t *sub_offsets;
/** The private data for managing this exported memory */
void *private_data;
/** DO NOT TOUCH THIS: The memory view entry for the internal use */
const struct rb_memory_view_entry *_memory_view_entry;
} rb_memory_view_t;
/** Type of function of ::rb_memory_view_entry_t::get_func. */
typedef bool (* rb_memory_view_get_func_t)(VALUE obj, rb_memory_view_t *view, int flags);
/** Type of function of ::rb_memory_view_entry_t::release_func. */
typedef bool (* rb_memory_view_release_func_t)(VALUE obj, rb_memory_view_t *view);
/** Type of function of ::rb_memory_view_entry_t::available_p_func. */
typedef bool (* rb_memory_view_available_p_func_t)(VALUE obj);
/** Operations applied to a specific kind of a memory view. */
typedef struct rb_memory_view_entry {
/**
* Exports a memory view from a Ruby object.
*/
rb_memory_view_get_func_t get_func;
/**
* Releases a memory view that was previously generated using
* ::rb_memory_view_entry_t::get_func.
*/
rb_memory_view_release_func_t release_func;
/**
* Queries if an object understands memory view protocol.
*/
rb_memory_view_available_p_func_t available_p_func;
} rb_memory_view_entry_t;
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* memory_view.c */
/**
* Associates the passed class with the passed memory view entry. This has to
* be called before actually creating a memory view from an instance.
*/
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry);
RBIMPL_ATTR_PURE()
/**
* Return `true` if the data in the MemoryView `view` is row-major contiguous.
*
* Return `false` otherwise.
*/
bool rb_memory_view_is_row_major_contiguous(const rb_memory_view_t *view);
RBIMPL_ATTR_PURE()
/**
* Return `true` if the data in the MemoryView `view` is column-major
* contiguous.
*
* Return `false` otherwise.
*/
bool rb_memory_view_is_column_major_contiguous(const rb_memory_view_t *view);
RBIMPL_ATTR_NOALIAS()
/**
* Fill the `strides` array with byte-Strides of a contiguous array of the
* given shape with the given element size.
*/
void rb_memory_view_fill_contiguous_strides(const ssize_t ndim, const ssize_t item_size, const ssize_t *const shape, const bool row_major_p, ssize_t *const strides);
RBIMPL_ATTR_NOALIAS()
/**
* Fill the members of `view` as an 1-dimensional byte array.
*/
bool rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly);
/**
* Deconstructs the passed format string, as describe in
* ::rb_memory_view_t::format.
*/
ssize_t rb_memory_view_parse_item_format(const char *format,
rb_memory_view_item_component_t **members,
size_t *n_members, const char **err);
/**
* Calculate the number of bytes occupied by an element.
*
* When the calculation fails, the failed location in `format` is stored into
* `err`, and returns `-1`.
*/
ssize_t rb_memory_view_item_size_from_format(const char *format, const char **err);
/**
* Calculate the location of the item indicated by the given `indices`.
*
* The length of `indices` must equal to `view->ndim`.
*
* This function initializes `view->item_desc` if needed.
*/
void *rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices);
/**
* Return a value that consists of item members.
*
* When an item is a single member, the return value is a single value.
*
* When an item consists of multiple members, an array will be returned.
*/
VALUE rb_memory_view_extract_item_members(const void *ptr, const rb_memory_view_item_component_t *members, const size_t n_members);
/** Fill the `item_desc` member of `view`. */
void rb_memory_view_prepare_item_desc(rb_memory_view_t *view);
/** * Return a value that consists of item members in the given memory view. */
VALUE rb_memory_view_get_item(rb_memory_view_t *view, const ssize_t *indices);
/**
* Return `true` if `obj` supports to export a MemoryView. Return `false`
* otherwise.
*
* If this function returns `true`, it doesn't mean the function
* `rb_memory_view_get` will succeed.
*/
bool rb_memory_view_available_p(VALUE obj);
/**
* If the given `obj` supports to export a MemoryView that conforms the given
* `flags`, this function fills `view` by the information of the MemoryView and
* returns `true`. In this case, the reference count of `obj` is increased.
*
* If the given combination of `obj` and `flags` cannot export a MemoryView,
* this function returns `false`. The content of `view` is not touched in this
* case.
*
* The exported MemoryView must be released by `rb_memory_view_release` when
* the MemoryView is no longer needed.
*/
bool rb_memory_view_get(VALUE obj, rb_memory_view_t* memory_view, int flags);
/**
* Release the given MemoryView `view` and decrement the reference count of
* `memory_view->obj`.
*
* Consumers must call this function when the MemoryView is no longer needed.
* Missing to call this function leads memory leak.
*/
bool rb_memory_view_release(rb_memory_view_t* memory_view);
/* for testing */
/** @cond INTERNAL_MACRO */
RUBY_EXTERN VALUE rb_memory_view_exported_object_registry;
RUBY_EXTERN const rb_data_type_t rb_memory_view_exported_object_registry_data_type;
/** @endcond */
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_PURE()
/**
* Return `true` if the data in the MemoryView `view` is row-major or
* column-major contiguous.
*
* Return `false` otherwise.
*/
static inline bool
rb_memory_view_is_contiguous(const rb_memory_view_t *view)
{
if (rb_memory_view_is_row_major_contiguous(view)) {
return true;
}
else if (rb_memory_view_is_column_major_contiguous(view)) {
return true;
}
else {
return false;
}
}
#endif /* RUBY_BUFFER_H */