summaryrefslogtreecommitdiff
path: root/include/ruby/memory_view.h
blob: e2c5cd9a03ff892d40d2bd01511c8a69d1a4dfc1 (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
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
#ifndef RUBY_MEMORY_VIEW_H
#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/dllexport.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
#include "ruby/intern.h"

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,
};

typedef struct {
    char format;
    unsigned native_size_p: 1;
    unsigned little_endian_p: 1;
    size_t offset;
    size_t size;
    size_t repeat;
} rb_memory_view_item_component_t;

typedef struct {
    /* The original object that have the memory exported via this memory view.
     * The consumer of this memory view has the responsibility to call rb_gc_mark
     * for preventing this obj collected by GC.  */
    VALUE obj;

    /* The pointer to the exported memory. */
    void *data;

    /* The number of bytes in data. */
    ssize_t len;

    /* 1 for readonly memory, 0 for writable memory. */
    bool readonly;

    /* A string to describe the format of an element, or NULL for unsigned byte.
     * The format string is a sequence 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
     * a 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;

    struct {
        /* The array of rb_memory_view_item_component_t that describes the
         * item structure. */
        rb_memory_view_item_component_t *components;

        /* The number of components in an item. */
        ssize_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. */
    ssize_t *shape;

    /* ndim size array indicating the number of bytes to skip to go to the
     * next element in each dimension. */
    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. */
    ssize_t *sub_offsets;

    /* the private data for managing this exported memory */
    void *const private;
} rb_memory_view_t;

typedef int (* rb_memory_view_get_func_t)(VALUE obj, rb_memory_view_t *view, int flags);
typedef int (* rb_memory_view_release_func_t)(VALUE obj, rb_memory_view_t *view);
typedef int (* rb_memory_view_available_p_func_t)(VALUE obj);

typedef struct {
    rb_memory_view_get_func_t get_func;
    rb_memory_view_release_func_t release_func;
    rb_memory_view_available_p_func_t available_p_func;
} rb_memory_view_entry_t;

RBIMPL_SYMBOL_EXPORT_BEGIN()

/* memory_view.c */
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry);

RBIMPL_ATTR_PURE()
bool rb_memory_view_is_row_major_contiguous(const rb_memory_view_t *view);
RBIMPL_ATTR_PURE()
bool rb_memory_view_is_column_major_contiguous(const rb_memory_view_t *view);
RBIMPL_ATTR_NOALIAS()
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()
int rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly);
ssize_t rb_memory_view_parse_item_format(const char *format,
                                         rb_memory_view_item_component_t **members,
                                         ssize_t *n_members, const char **err);
ssize_t rb_memory_view_item_size_from_format(const char *format, const char **err);
void *rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices);

int rb_memory_view_available_p(VALUE obj);
int rb_memory_view_get(VALUE obj, rb_memory_view_t* memory_view, int flags);
int rb_memory_view_release(rb_memory_view_t* memory_view);

/* for testing */
RUBY_EXTERN VALUE rb_memory_view_exported_object_registry;
RUBY_EXTERN const rb_data_type_t rb_memory_view_exported_object_registry_data_type;

RBIMPL_SYMBOL_EXPORT_END()

RBIMPL_ATTR_PURE()
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 */