summaryrefslogtreecommitdiff
path: root/internal/struct.h
blob: f205dbd89e23d3bbab81b7d613d9009a080dab76 (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
#ifndef INTERNAL_STRUCT_H /* -*- C -*- */
#define INTERNAL_STRUCT_H
/**
 * @file
 * @brief      Internal header for Struct.
 * @author     \@shyouhei
 * @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.
 */
#include "internal/gc.h"        /* for RB_OBJ_WRITE */
#include "internal/stdbool.h"   /* for bool */
#include "ruby/ruby.h"          /* for struct RBasic */
#include "internal/gc.h"        /* for RB_OBJ_WRITE */

enum {
    RSTRUCT_EMBED_LEN_MAX = RVALUE_EMBED_LEN_MAX,
    RSTRUCT_EMBED_LEN_MASK = (RUBY_FL_USER2|RUBY_FL_USER1),
    RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
    RSTRUCT_TRANSIENT_FLAG = FL_USER3,
};

struct RStruct {
    struct RBasic basic;
    union {
        struct {
            long len;
            const VALUE *ptr;
        } heap;
        const VALUE ary[RSTRUCT_EMBED_LEN_MAX];
    } as;
};

#define RSTRUCT(obj) (R_CAST(RStruct)(obj))

#ifdef RSTRUCT_LEN
# undef RSTRUCT_LEN
#endif

#ifdef RSTRUCT_PTR
# undef RSTRUCT_PTR
#endif

#ifdef RSTRUCT_SET
# undef RSTRUCT_SET
#endif

#ifdef RSTRUCT_GET
# undef RSTRUCT_GET
#endif

/* struct.c */
VALUE rb_struct_init_copy(VALUE copy, VALUE s);
VALUE rb_struct_lookup(VALUE s, VALUE idx);
VALUE rb_struct_s_keyword_init(VALUE klass);
static inline const VALUE *rb_struct_const_heap_ptr(VALUE st);
static inline bool RSTRUCT_TRANSIENT_P(VALUE st);
static inline void RSTRUCT_TRANSIENT_SET(VALUE st);
static inline void RSTRUCT_TRANSIENT_UNSET(VALUE st);
static inline long RSTRUCT_EMBED_LEN(VALUE st);
static inline long RSTRUCT_LEN(VALUE st);
static inline int RSTRUCT_LENINT(VALUE st);
static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st);
static inline void RSTRUCT_SET(VALUE st, long k, VALUE v);
static inline VALUE RSTRUCT_GET(VALUE st, long k);

static inline bool
RSTRUCT_TRANSIENT_P(VALUE st)
{
#if USE_TRANSIENT_HEAP
    return FL_TEST_RAW(st, RSTRUCT_TRANSIENT_FLAG);
#else
    return false;
#endif
}

static inline void
RSTRUCT_TRANSIENT_SET(VALUE st)
{
#if USE_TRANSIENT_HEAP
    FL_SET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
#endif
}

static inline void
RSTRUCT_TRANSIENT_UNSET(VALUE st)
{
#if USE_TRANSIENT_HEAP
    FL_UNSET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
#endif
}

static inline long
RSTRUCT_EMBED_LEN(VALUE st)
{
    long ret = FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK);
    ret >>= RSTRUCT_EMBED_LEN_SHIFT;
    return ret;
}

static inline long
RSTRUCT_LEN(VALUE st)
{
    if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
        return RSTRUCT_EMBED_LEN(st);
    }
    else {
        return RSTRUCT(st)->as.heap.len;
    }
}

static inline int
RSTRUCT_LENINT(VALUE st)
{
    return rb_long2int(RSTRUCT_LEN(st));
}

static inline const VALUE *
RSTRUCT_CONST_PTR(VALUE st)
{
    const struct RStruct *p = RSTRUCT(st);

    if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
        return p->as.ary;
    }
    else {
        return p->as.heap.ptr;
    }
}

static inline void
RSTRUCT_SET(VALUE st, long k,  VALUE v)
{
    RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v);
}

static inline VALUE
RSTRUCT_GET(VALUE st, long k)
{
    return RSTRUCT_CONST_PTR(st)[k];
}

static inline const VALUE *
rb_struct_const_heap_ptr(VALUE st)
{
    /* TODO: check embed on debug mode */
    return RSTRUCT(st)->as.heap.ptr;
}

#endif /* INTERNAL_STRUCT_H */