Line | Count | Source |
1 | | /* |
2 | | ** etc.c |
3 | | ** |
4 | | ** See Copyright Notice in mruby.h |
5 | | */ |
6 | | |
7 | | #include <mruby.h> |
8 | | #include <mruby/string.h> |
9 | | #include <mruby/data.h> |
10 | | #include <mruby/class.h> |
11 | | #include <mruby/numeric.h> |
12 | | #include <mruby/internal.h> |
13 | | |
14 | | /* |
15 | | * Allocates an RData structure, initializes it with the given pointer and type, |
16 | | * and assigns it to the given class. |
17 | | */ |
18 | | MRB_API struct RData* |
19 | | mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) |
20 | 3.01k | { |
21 | 3.01k | struct RData *data = MRB_OBJ_ALLOC(mrb, MRB_TT_CDATA, klass); |
22 | | |
23 | 3.01k | data->data = ptr; |
24 | 3.01k | data->type = type; |
25 | | |
26 | 3.01k | return data; |
27 | 3.01k | } |
28 | | |
29 | | /* |
30 | | * Checks if the given mrb_value is a data object (MRB_TT_CDATA) and if its |
31 | | * mrb_data_type matches the provided type. |
32 | | * Raises an error if the checks fail. |
33 | | */ |
34 | | MRB_API void |
35 | | mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) |
36 | 164k | { |
37 | 164k | if (!mrb_data_p(obj)) { |
38 | 0 | mrb_check_type(mrb, obj, MRB_TT_CDATA); |
39 | 0 | } |
40 | 164k | if (DATA_TYPE(obj) != type) { |
41 | 0 | const mrb_data_type *t2 = DATA_TYPE(obj); |
42 | |
|
43 | 0 | if (t2) { |
44 | 0 | mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", |
45 | 0 | t2->struct_name, type->struct_name); |
46 | 0 | } |
47 | 0 | else { |
48 | 0 | mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)", |
49 | 0 | obj, type->struct_name); |
50 | 0 | } |
51 | 0 | } |
52 | 164k | } |
53 | | |
54 | | /* |
55 | | * Checks if the given mrb_value is a data object and if its mrb_data_type |
56 | | * matches the provided type. |
57 | | * Returns a pointer to the data if the checks pass, otherwise returns NULL. |
58 | | */ |
59 | | MRB_API void* |
60 | | mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) |
61 | 354 | { |
62 | 354 | if (!mrb_data_p(obj)) { |
63 | 354 | return NULL; |
64 | 354 | } |
65 | 0 | if (DATA_TYPE(obj) != type) { |
66 | 0 | return NULL; |
67 | 0 | } |
68 | 0 | return DATA_PTR(obj); |
69 | 0 | } |
70 | | |
71 | | /* |
72 | | * Retrieves a pointer to the data within a data object. |
73 | | * Calls `mrb_data_check_type` to ensure the object is of the correct type, |
74 | | * raising an error if the type check fails. |
75 | | */ |
76 | | MRB_API void* |
77 | | mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) |
78 | 164k | { |
79 | 164k | mrb_data_check_type(mrb, obj, type); |
80 | 164k | return DATA_PTR(obj); |
81 | 164k | } |
82 | | |
83 | | /* |
84 | | * Converts an object to a symbol. |
85 | | * If the object is already a symbol, it is returned directly. |
86 | | * If the object is a string, it is interned to a symbol. |
87 | | * Otherwise, a type error is raised. |
88 | | */ |
89 | | MRB_API mrb_sym |
90 | | mrb_obj_to_sym(mrb_state *mrb, mrb_value name) |
91 | 383k | { |
92 | 383k | if (mrb_symbol_p(name)) return mrb_symbol(name); |
93 | 2 | if (mrb_string_p(name)) return mrb_intern_str(mrb, name); |
94 | 2 | mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a symbol nor a string", name); |
95 | 0 | return 0; /* not reached */ |
96 | 2 | } |
97 | | |
98 | | #if !defined(MRB_NO_FLOAT) && !defined(MRB_NAN_BOXING) |
99 | | static mrb_int |
100 | | mrb_float_id(mrb_float f) |
101 | 0 | { |
102 | | /* normalize -0.0 to 0.0 */ |
103 | 0 | if (f == 0) f = 0.0; |
104 | 0 | return (mrb_int)mrb_byte_hash((uint8_t*)&f, sizeof(f)); |
105 | 0 | } |
106 | | #endif |
107 | | |
108 | | /* |
109 | | * Returns a unique identifier (mrb_int) for the given object. |
110 | | * The method of generating the ID varies based on the object's type and |
111 | | * boxing model (NaN boxing, word boxing, or no boxing). |
112 | | */ |
113 | | MRB_API mrb_int |
114 | | mrb_obj_id(mrb_value obj) |
115 | 7.05k | { |
116 | | #if defined(MRB_NAN_BOXING) |
117 | | #ifdef MRB_INT64 |
118 | | return obj.u; |
119 | | #else |
120 | | uint64_t u = obj.u; |
121 | | return (mrb_int)(u>>32)^u; |
122 | | #endif |
123 | | #elif defined(MRB_WORD_BOXING) |
124 | 7.05k | if (!mrb_immediate_p(obj)) { |
125 | 6.16k | if (mrb_integer_p(obj)) return mrb_integer(obj); |
126 | 6.16k | #ifndef MRB_NO_FLOAT |
127 | 6.16k | if (mrb_float_p(obj)) { |
128 | 0 | return mrb_float_id(mrb_float(obj)); |
129 | 0 | } |
130 | 6.16k | #endif |
131 | 6.16k | } |
132 | 7.05k | return (mrb_int)obj.w; |
133 | | #else /* MRB_NO_BOXING */ |
134 | | |
135 | | #define MakeID(p,t) (mrb_int)(((intptr_t)(p))^(t)) |
136 | | |
137 | | enum mrb_vtype tt = mrb_type(obj); |
138 | | |
139 | | switch (tt) { |
140 | | case MRB_TT_FREE: |
141 | | case MRB_TT_UNDEF: |
142 | | return MakeID(0, tt); /* should not happen */ |
143 | | case MRB_TT_FALSE: |
144 | | if (mrb_nil_p(obj)) |
145 | | return MakeID(4, tt); |
146 | | else |
147 | | return MakeID(0, tt); |
148 | | case MRB_TT_TRUE: |
149 | | return MakeID(2, tt); |
150 | | case MRB_TT_SYMBOL: |
151 | | return MakeID(mrb_symbol(obj), tt); |
152 | | case MRB_TT_INTEGER: |
153 | | return MakeID(mrb_integer(obj), tt); |
154 | | #ifndef MRB_NO_FLOAT |
155 | | case MRB_TT_FLOAT: |
156 | | return MakeID(mrb_float_id(mrb_float(obj)), tt); |
157 | | #endif |
158 | | case MRB_TT_STRING: |
159 | | case MRB_TT_OBJECT: |
160 | | case MRB_TT_CLASS: |
161 | | case MRB_TT_MODULE: |
162 | | case MRB_TT_ICLASS: |
163 | | case MRB_TT_SCLASS: |
164 | | case MRB_TT_PROC: |
165 | | case MRB_TT_ARRAY: |
166 | | case MRB_TT_HASH: |
167 | | case MRB_TT_RANGE: |
168 | | case MRB_TT_EXCEPTION: |
169 | | case MRB_TT_CDATA: |
170 | | case MRB_TT_ISTRUCT: |
171 | | default: |
172 | | return MakeID(mrb_ptr(obj), tt); |
173 | | } |
174 | | #endif |
175 | 7.05k | } |
176 | | |
177 | | #ifdef MRB_WORD_BOXING |
178 | | #ifndef MRB_NO_FLOAT |
179 | | /* |
180 | | * Boxes a `mrb_float` into an `mrb_value` using word boxing. |
181 | | * - If `MRB_WORDBOX_NO_FLOAT_TRUNCATE` is defined, it allocates a new |
182 | | * RFloat object on the heap. |
183 | | * - If `MRB_64BIT` and `MRB_USE_FLOAT32` are defined, it stores the float |
184 | | * in the lower bits of the word, shifted and tagged. |
185 | | * - Otherwise, it stores the float directly in the word, tagged. |
186 | | */ |
187 | | MRB_API mrb_value |
188 | | mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) |
189 | 618k | { |
190 | 618k | union mrb_value_ v; |
191 | | |
192 | | #ifdef MRB_WORDBOX_NO_FLOAT_TRUNCATE |
193 | | v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); |
194 | | v.fp->f = f; |
195 | | v.bp->frozen = 1; |
196 | | #elif defined(MRB_64BIT) && defined(MRB_USE_FLOAT32) |
197 | | v.w = 0; |
198 | | v.f = f; |
199 | | v.w = (v.w<<2) | 2; |
200 | | #else |
201 | 618k | v.f = f; |
202 | 618k | v.w = (v.w & ~3) | 2; |
203 | 618k | #endif |
204 | 618k | return v.value; |
205 | 618k | } |
206 | | |
207 | | |
208 | | #ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE |
209 | | /* |
210 | | * Unboxes an `mrb_value` to an `mrb_float` when word boxing is used and |
211 | | * float truncation (`MRB_WORDBOX_NO_FLOAT_TRUNCATE`) is not disabled. |
212 | | * The function extracts the float value from the `mrb_value`'s union |
213 | | * representation (`u.value`). |
214 | | * - If `MRB_64BIT` and `MRB_USE_FLOAT32` are defined, the word (`u.w`) |
215 | | * is right-shifted by 2 bits to retrieve the float. |
216 | | * - Otherwise, the lower 2 bits of the word (`u.w`) are cleared to |
217 | | * retrieve the float. |
218 | | */ |
219 | | MRB_API mrb_float |
220 | | mrb_word_boxing_value_float(mrb_value v) |
221 | 684k | { |
222 | 684k | union mrb_value_ u; |
223 | 684k | u.value = v; |
224 | | #if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32) |
225 | | u.w >>= 2; |
226 | | #else |
227 | 684k | u.w &= ~3; |
228 | 684k | #endif |
229 | 684k | return u.f; |
230 | 684k | } |
231 | | #endif |
232 | | #endif /* MRB_NO_FLOAT */ |
233 | | |
234 | | /* |
235 | | * Boxes a C pointer (void*) into an `mrb_value` using word boxing. |
236 | | * It allocates an `RCptr` object, sets its internal pointer `p` to the |
237 | | * given C pointer, and then sets the `mrb_value` to this `RCptr` object. |
238 | | */ |
239 | | MRB_API mrb_value |
240 | | mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) |
241 | 2.68k | { |
242 | 2.68k | struct RCptr *cptr = MRB_OBJ_ALLOC(mrb, MRB_TT_CPTR, mrb->object_class); |
243 | 2.68k | mrb_value v; |
244 | | |
245 | 2.68k | SET_OBJ_VALUE(v, cptr); |
246 | 2.68k | cptr->p = p; |
247 | 2.68k | return v; |
248 | 2.68k | } |
249 | | #endif /* MRB_WORD_BOXING */ |
250 | | |
251 | | #if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_INT64)) |
252 | | /* |
253 | | * Boxes an `mrb_int` into an `mrb_value`. |
254 | | * If the integer `n` can be represented as a fixnum (checked by `FIXABLE(n)`), |
255 | | * it returns a fixnum-tagged `mrb_value`. Otherwise, it allocates an |
256 | | * `RInteger` object on the heap, stores `n` in it, marks the object as |
257 | | * frozen, and returns an object-tagged `mrb_value`. |
258 | | * This function is used when word boxing is enabled or when NaN boxing is |
259 | | * enabled for 64-bit integers. |
260 | | */ |
261 | | MRB_API mrb_value |
262 | | mrb_boxing_int_value(mrb_state *mrb, mrb_int n) |
263 | 3.96M | { |
264 | 3.96M | if (FIXABLE(n)) return mrb_fixnum_value(n); |
265 | 16.0k | else { |
266 | 16.0k | mrb_value v; |
267 | 16.0k | struct RInteger *p = (struct RInteger*)mrb_obj_alloc(mrb, MRB_TT_INTEGER, mrb->integer_class); |
268 | 16.0k | p->i = n; |
269 | 16.0k | p->frozen = 1; |
270 | 16.0k | SET_OBJ_VALUE(v, p); |
271 | 16.0k | return v; |
272 | 16.0k | } |
273 | 3.96M | } |
274 | | #endif |
275 | | |
276 | | #if defined _MSC_VER && _MSC_VER < 1900 |
277 | | |
278 | | #ifndef va_copy |
279 | | static void |
280 | | mrb_msvc_va_copy(va_list *dest, va_list src) |
281 | | { |
282 | | *dest = src; |
283 | | } |
284 | | #define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src) |
285 | | #endif |
286 | | |
287 | | MRB_API int |
288 | | mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg) |
289 | | { |
290 | | int cnt; |
291 | | va_list argcp; |
292 | | va_copy(argcp, arg); |
293 | | if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) { |
294 | | cnt = _vscprintf(format, arg); |
295 | | } |
296 | | va_end(argcp); |
297 | | return cnt; |
298 | | } |
299 | | |
300 | | MRB_API int |
301 | | mrb_msvc_snprintf(char *s, size_t n, const char *format, ...) |
302 | | { |
303 | | va_list arg; |
304 | | va_start(arg, format); |
305 | | |
306 | | int ret = mrb_msvc_vsnprintf(s, n, format, arg); |
307 | | va_end(arg); |
308 | | return ret; |
309 | | } |
310 | | |
311 | | #endif /* defined _MSC_VER && _MSC_VER < 1900 */ |