Merge pull request #6288 from dearblue/closing
[mruby.git] / src / etc.c
blobe20422f53a57667fc0b3a48aaf60ba02ac7c5045
1 /*
2 ** etc.c
3 **
4 ** See Copyright Notice in mruby.h
5 */
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>
14 MRB_API struct RData*
15 mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type)
17 struct RData *data = MRB_OBJ_ALLOC(mrb, MRB_TT_CDATA, klass);
19 data->data = ptr;
20 data->type = type;
22 return data;
25 MRB_API void
26 mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
28 if (!mrb_data_p(obj)) {
29 mrb_check_type(mrb, obj, MRB_TT_CDATA);
31 if (DATA_TYPE(obj) != type) {
32 const mrb_data_type *t2 = DATA_TYPE(obj);
34 if (t2) {
35 mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)",
36 t2->struct_name, type->struct_name);
38 else {
39 mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)",
40 obj, type->struct_name);
45 MRB_API void*
46 mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
48 if (!mrb_data_p(obj)) {
49 return NULL;
51 if (DATA_TYPE(obj) != type) {
52 return NULL;
54 return DATA_PTR(obj);
57 MRB_API void*
58 mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type)
60 mrb_data_check_type(mrb, obj, type);
61 return DATA_PTR(obj);
64 MRB_API mrb_sym
65 mrb_obj_to_sym(mrb_state *mrb, mrb_value name)
67 if (mrb_symbol_p(name)) return mrb_symbol(name);
68 if (mrb_string_p(name)) return mrb_intern_str(mrb, name);
69 mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a symbol nor a string", name);
70 return 0; /* not reached */
73 #if !defined(MRB_NO_FLOAT) && !defined(MRB_NAN_BOXING)
74 static mrb_int
75 mrb_float_id(mrb_float f)
77 /* normalize -0.0 to 0.0 */
78 if (f == 0) f = 0.0;
79 return (mrb_int)mrb_byte_hash((uint8_t*)&f, sizeof(f));
81 #endif
83 MRB_API mrb_int
84 mrb_obj_id(mrb_value obj)
86 #if defined(MRB_NAN_BOXING)
87 #ifdef MRB_INT64
88 return obj.u;
89 #else
90 uint64_t u = obj.u;
91 return (mrb_int)(u>>32)^u;
92 #endif
93 #elif defined(MRB_WORD_BOXING)
94 if (!mrb_immediate_p(obj)) {
95 if (mrb_integer_p(obj)) return mrb_integer(obj);
96 #ifndef MRB_NO_FLOAT
97 if (mrb_float_p(obj)) {
98 return mrb_float_id(mrb_float(obj));
100 #endif
102 return (mrb_int)obj.w;
103 #else /* MRB_NO_BOXING */
105 #define MakeID(p,t) (mrb_int)(((intptr_t)(p))^(t))
107 enum mrb_vtype tt = mrb_type(obj);
109 switch (tt) {
110 case MRB_TT_FREE:
111 case MRB_TT_UNDEF:
112 return MakeID(0, tt); /* should not happen */
113 case MRB_TT_FALSE:
114 if (mrb_nil_p(obj))
115 return MakeID(4, tt);
116 else
117 return MakeID(0, tt);
118 case MRB_TT_TRUE:
119 return MakeID(2, tt);
120 case MRB_TT_SYMBOL:
121 return MakeID(mrb_symbol(obj), tt);
122 case MRB_TT_INTEGER:
123 return MakeID(mrb_integer(obj), tt);
124 #ifndef MRB_NO_FLOAT
125 case MRB_TT_FLOAT:
126 return MakeID(mrb_float_id(mrb_float(obj)), tt);
127 #endif
128 case MRB_TT_STRING:
129 case MRB_TT_OBJECT:
130 case MRB_TT_CLASS:
131 case MRB_TT_MODULE:
132 case MRB_TT_ICLASS:
133 case MRB_TT_SCLASS:
134 case MRB_TT_PROC:
135 case MRB_TT_ARRAY:
136 case MRB_TT_HASH:
137 case MRB_TT_RANGE:
138 case MRB_TT_EXCEPTION:
139 case MRB_TT_CDATA:
140 case MRB_TT_ISTRUCT:
141 default:
142 return MakeID(mrb_ptr(obj), tt);
144 #endif
147 #ifdef MRB_WORD_BOXING
148 #ifndef MRB_NO_FLOAT
149 MRB_API mrb_value
150 mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)
152 union mrb_value_ v;
154 #ifdef MRB_WORDBOX_NO_FLOAT_TRUNCATE
155 v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);
156 v.fp->f = f;
157 MRB_SET_FROZEN_FLAG(v.bp);
158 #elif defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)
159 v.w = 0;
160 v.f = f;
161 v.w = (v.w<<2) | 2;
162 #else
163 v.f = f;
164 v.w = (v.w & ~3) | 2;
165 #endif
166 return v.value;
170 #ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE
171 MRB_API mrb_float
172 mrb_word_boxing_value_float(mrb_value v)
174 union mrb_value_ u;
175 u.value = v;
176 #if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)
177 u.w >>= 2;
178 #else
179 u.w &= ~3;
180 #endif
181 return u.f;
183 #endif
184 #endif /* MRB_NO_FLOAT */
186 MRB_API mrb_value
187 mrb_word_boxing_cptr_value(mrb_state *mrb, void *p)
189 mrb_value v;
190 struct RCptr *cptr = MRB_OBJ_ALLOC(mrb, MRB_TT_CPTR, mrb->object_class);
192 SET_OBJ_VALUE(v, cptr);
193 cptr->p = p;
194 return v;
196 #endif /* MRB_WORD_BOXING */
198 #if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_INT64))
199 MRB_API mrb_value
200 mrb_boxing_int_value(mrb_state *mrb, mrb_int n)
202 if (FIXABLE(n)) return mrb_fixnum_value(n);
203 else {
204 mrb_value v;
205 struct RInteger *p = (struct RInteger*)mrb_obj_alloc(mrb, MRB_TT_INTEGER, mrb->integer_class);
206 p->i = n;
207 MRB_SET_FROZEN_FLAG((struct RBasic*)p);
208 SET_OBJ_VALUE(v, p);
209 return v;
212 #endif
214 #if defined _MSC_VER && _MSC_VER < 1900
216 #ifndef va_copy
217 static void
218 mrb_msvc_va_copy(va_list *dest, va_list src)
220 *dest = src;
222 #define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src)
223 #endif
225 MRB_API int
226 mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg)
228 int cnt;
229 va_list argcp;
230 va_copy(argcp, arg);
231 if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) {
232 cnt = _vscprintf(format, arg);
234 va_end(argcp);
235 return cnt;
238 MRB_API int
239 mrb_msvc_snprintf(char *s, size_t n, const char *format, ...)
241 va_list arg;
242 va_start(arg, format);
244 int ret = mrb_msvc_vsnprintf(s, n, format, arg);
245 va_end(arg);
246 return ret;
249 #endif /* defined _MSC_VER && _MSC_VER < 1900 */