struct.c
DEFINITIONS
This source file includes following functions.
- rb_struct_iv_get
- rb_struct_s_members
- rb_struct_members
- rb_struct_getmember
- rb_struct_ref
- rb_struct_ref0
- rb_struct_ref1
- rb_struct_ref2
- rb_struct_ref3
- rb_struct_ref4
- rb_struct_ref5
- rb_struct_ref6
- rb_struct_ref7
- rb_struct_ref8
- rb_struct_ref9
- rb_struct_modify
- rb_struct_set
- make_struct
- rb_struct_define
- rb_struct_s_def
- rb_struct_initialize
- struct_alloc
- rb_struct_alloc
- rb_struct_new
- rb_struct_each
- rb_struct_each_pair
- rb_struct_to_s
- inspect_struct
- rb_struct_inspect
- rb_struct_to_a
- rb_struct_become
- rb_struct_aref_id
- rb_struct_aref
- rb_struct_aset_id
- rb_struct_aset
- rb_struct_select
- rb_struct_equal
- rb_struct_size
- Init_Struct
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14
15 VALUE rb_cStruct;
16
17 static VALUE struct_alloc _((VALUE));
18
19 VALUE
20 rb_struct_iv_get(c, name)
21 VALUE c;
22 char *name;
23 {
24 ID id;
25
26 id = rb_intern(name);
27 for (;;) {
28 if (rb_ivar_defined(c, id))
29 return rb_ivar_get(c, id);
30 c = RCLASS(c)->super;
31 if (c == 0 || c == rb_cStruct)
32 return Qnil;
33 }
34 }
35
36 static VALUE
37 rb_struct_s_members(obj)
38 VALUE obj;
39 {
40 VALUE member, ary;
41 VALUE *p, *pend;
42
43 member = rb_struct_iv_get(obj, "__member__");
44 if (NIL_P(member)) {
45 rb_bug("uninitialized struct");
46 }
47 ary = rb_ary_new2(RARRAY(member)->len);
48 p = RARRAY(member)->ptr; pend = p + RARRAY(member)->len;
49 while (p < pend) {
50 rb_ary_push(ary, rb_str_new2(rb_id2name(SYM2ID(*p))));
51 p++;
52 }
53
54 return ary;
55 }
56
57 static VALUE
58 rb_struct_members(obj)
59 VALUE obj;
60 {
61 return rb_struct_s_members(rb_obj_class(obj));
62 }
63
64 VALUE
65 rb_struct_getmember(obj, id)
66 VALUE obj;
67 ID id;
68 {
69 VALUE member, slot;
70 long i;
71
72 member = rb_struct_iv_get(rb_obj_class(obj), "__member__");
73 if (NIL_P(member)) {
74 rb_bug("uninitialized struct");
75 }
76 slot = ID2SYM(id);
77 for (i=0; i<RARRAY(member)->len; i++) {
78 if (RARRAY(member)->ptr[i] == slot) {
79 return RSTRUCT(obj)->ptr[i];
80 }
81 }
82 rb_name_error(id, "%s is not struct member", rb_id2name(id));
83 return Qnil;
84 }
85
86 static VALUE
87 rb_struct_ref(obj)
88 VALUE obj;
89 {
90 return rb_struct_getmember(obj, rb_frame_last_func());
91 }
92
93 static VALUE rb_struct_ref0(obj) VALUE obj; {return RSTRUCT(obj)->ptr[0];}
94 static VALUE rb_struct_ref1(obj) VALUE obj; {return RSTRUCT(obj)->ptr[1];}
95 static VALUE rb_struct_ref2(obj) VALUE obj; {return RSTRUCT(obj)->ptr[2];}
96 static VALUE rb_struct_ref3(obj) VALUE obj; {return RSTRUCT(obj)->ptr[3];}
97 static VALUE rb_struct_ref4(obj) VALUE obj; {return RSTRUCT(obj)->ptr[4];}
98 static VALUE rb_struct_ref5(obj) VALUE obj; {return RSTRUCT(obj)->ptr[5];}
99 static VALUE rb_struct_ref6(obj) VALUE obj; {return RSTRUCT(obj)->ptr[6];}
100 static VALUE rb_struct_ref7(obj) VALUE obj; {return RSTRUCT(obj)->ptr[7];}
101 static VALUE rb_struct_ref8(obj) VALUE obj; {return RSTRUCT(obj)->ptr[8];}
102 static VALUE rb_struct_ref9(obj) VALUE obj; {return RSTRUCT(obj)->ptr[9];}
103
104 static VALUE (*ref_func[10])() = {
105 rb_struct_ref0,
106 rb_struct_ref1,
107 rb_struct_ref2,
108 rb_struct_ref3,
109 rb_struct_ref4,
110 rb_struct_ref5,
111 rb_struct_ref6,
112 rb_struct_ref7,
113 rb_struct_ref8,
114 rb_struct_ref9,
115 };
116
117 static void
118 rb_struct_modify(s)
119 VALUE s;
120 {
121 if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
122 if (!OBJ_TAINTED(s) && rb_safe_level() >= 4)
123 rb_raise(rb_eSecurityError, "Insecure: can't modify Struct");
124 }
125
126 static VALUE
127 rb_struct_set(obj, val)
128 VALUE obj, val;
129 {
130 VALUE member, slot;
131 long i;
132
133 member = rb_struct_iv_get(rb_obj_class(obj), "__member__");
134 if (NIL_P(member)) {
135 rb_bug("uninitialized struct");
136 }
137 rb_struct_modify(obj);
138 for (i=0; i<RARRAY(member)->len; i++) {
139 slot = RARRAY(member)->ptr[i];
140 if (rb_id_attrset(SYM2ID(slot)) == rb_frame_last_func()) {
141 return RSTRUCT(obj)->ptr[i] = val;
142 }
143 }
144 rb_name_error(rb_frame_last_func(), "`%s' is not a struct member",
145 rb_id2name(rb_frame_last_func()));
146 return Qnil;
147 }
148
149 static VALUE
150 make_struct(name, member, klass)
151 VALUE name, member, klass;
152 {
153 VALUE nstr;
154 ID id;
155 long i;
156
157 if (NIL_P(name)) {
158 nstr = rb_class_new(klass);
159 rb_class_inherited(klass, nstr);
160 }
161 else {
162 char *cname = StringValuePtr(name);
163 id = rb_intern(cname);
164 if (!rb_is_const_id(id)) {
165 rb_name_error(id, "identifier %s needs to be constant", cname);
166 }
167 nstr = rb_define_class_under(klass, cname, klass);
168 }
169 rb_iv_set(nstr, "__size__", LONG2NUM(RARRAY(member)->len));
170 rb_iv_set(nstr, "__member__", member);
171
172 rb_define_singleton_method(nstr, "allocate", struct_alloc, 0);
173 rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1);
174 rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1);
175 rb_define_singleton_method(nstr, "members", rb_struct_s_members, 0);
176 for (i=0; i< RARRAY(member)->len; i++) {
177 ID id = SYM2ID(RARRAY(member)->ptr[i]);
178 if (i<10) {
179 rb_define_method_id(nstr, id, ref_func[i], 0);
180 }
181 else {
182 rb_define_method_id(nstr, id, rb_struct_ref, 0);
183 }
184 rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1);
185 }
186
187 return nstr;
188 }
189
190 #ifdef HAVE_STDARG_PROTOTYPES
191 #include <stdarg.h>
192 #define va_init_list(a,b) va_start(a,b)
193 #else
194 #include <varargs.h>
195 #define va_init_list(a,b) va_start(a)
196 #endif
197
198 VALUE
199 #ifdef HAVE_STDARG_PROTOTYPES
200 rb_struct_define(const char *name, ...)
201 #else
202 rb_struct_define(name, va_alist)
203 const char *name;
204 va_dcl
205 #endif
206 {
207 va_list ar;
208 VALUE nm, ary;
209 char *mem;
210
211 if (!name) nm = Qnil;
212 else nm = rb_str_new2(name);
213 ary = rb_ary_new();
214
215 va_init_list(ar, name);
216 while (mem = va_arg(ar, char*)) {
217 ID slot = rb_intern(mem);
218 rb_ary_push(ary, ID2SYM(slot));
219 }
220 va_end(ar);
221
222 return make_struct(nm, ary, rb_cStruct);
223 }
224
225 static VALUE
226 rb_struct_s_def(argc, argv, klass)
227 int argc;
228 VALUE *argv;
229 VALUE klass;
230 {
231 VALUE name, rest;
232 long i;
233 VALUE st;
234 ID id;
235
236 rb_scan_args(argc, argv, "1*", &name, &rest);
237 for (i=0; i<RARRAY(rest)->len; i++) {
238 id = rb_to_id(RARRAY(rest)->ptr[i]);
239 RARRAY(rest)->ptr[i] = ID2SYM(id);
240 }
241 if (!NIL_P(name) && TYPE(name) != T_STRING) {
242 id = rb_to_id(name);
243 rb_ary_unshift(rest, ID2SYM(id));
244 name = Qnil;
245 }
246 st = make_struct(name, rest, klass);
247
248 return st;
249 }
250
251 static VALUE
252 rb_struct_initialize(self, values)
253 VALUE self, values;
254 {
255 VALUE klass = rb_obj_class(self);
256 VALUE size;
257 long n;
258
259 rb_struct_modify(self);
260 size = rb_struct_iv_get(klass, "__size__");
261 n = FIX2LONG(size);
262 if (n < RARRAY(values)->len) {
263 rb_raise(rb_eArgError, "struct size differs");
264 }
265 MEMCPY(RSTRUCT(self)->ptr, RARRAY(values)->ptr, VALUE, RARRAY(values)->len);
266 if (n > RARRAY(values)->len) {
267 rb_mem_clear(RSTRUCT(self)->ptr+RARRAY(values)->len,
268 n-RARRAY(values)->len);
269 }
270 return Qnil;
271 }
272
273 static VALUE
274 struct_alloc(klass)
275 VALUE klass;
276 {
277 VALUE size;
278 long n;
279 NEWOBJ(st, struct RStruct);
280 OBJSETUP(st, klass, T_STRUCT);
281
282 size = rb_struct_iv_get(klass, "__size__");
283 n = FIX2LONG(size);
284
285 st->ptr = ALLOC_N(VALUE, n);
286 rb_mem_clear(st->ptr, n);
287 st->len = n;
288
289 return (VALUE)st;
290 }
291
292 VALUE
293 rb_struct_alloc(klass, values)
294 VALUE klass, values;
295 {
296 return rb_class_new_instance(RARRAY(values)->len, RARRAY(values)->ptr, klass);
297 }
298
299 VALUE
300 #ifdef HAVE_STDARG_PROTOTYPES
301 rb_struct_new(VALUE klass, ...)
302 #else
303 rb_struct_new(klass, va_alist)
304 VALUE klass;
305 va_dcl
306 #endif
307 {
308 VALUE sz, *mem;
309 long size, i;
310 va_list args;
311
312 sz = rb_struct_iv_get(klass, "__size__");
313 size = FIX2LONG(sz);
314 mem = ALLOCA_N(VALUE, size);
315 va_init_list(args, klass);
316 for (i=0; i<size; i++) {
317 mem[i] = va_arg(args, VALUE);
318 }
319 va_end(args);
320
321 return rb_class_new_instance(size, mem, klass);
322 }
323
324 static VALUE
325 rb_struct_each(s)
326 VALUE s;
327 {
328 long i;
329
330 for (i=0; i<RSTRUCT(s)->len; i++) {
331 rb_yield(RSTRUCT(s)->ptr[i]);
332 }
333 return s;
334 }
335
336 static VALUE
337 rb_struct_each_pair(s)
338 VALUE s;
339 {
340 VALUE member;
341 long i;
342
343 member = rb_struct_iv_get(rb_obj_class(s), "__member__");
344 if (NIL_P(member)) {
345 rb_bug("non-initialized struct");
346 }
347 for (i=0; i<RSTRUCT(s)->len; i++) {
348 rb_yield(rb_assoc_new(RARRAY(member)->ptr[i], RSTRUCT(s)->ptr[i]));
349 }
350 return s;
351 }
352
353 static VALUE
354 rb_struct_to_s(s)
355 VALUE s;
356 {
357 char *cname = rb_class2name(rb_obj_class(s));
358 VALUE str = rb_str_new(0, strlen(cname) + 4);
359
360 sprintf(RSTRING(str)->ptr, "#<%s>", cname);
361 RSTRING(str)->len = strlen(RSTRING(str)->ptr);
362 return str;
363 }
364
365 static VALUE
366 inspect_struct(s)
367 VALUE s;
368 {
369 char *cname = rb_class2name(rb_obj_class(s));
370 VALUE str, member;
371 long i;
372
373 member = rb_struct_iv_get(rb_obj_class(s), "__member__");
374 if (NIL_P(member)) {
375 rb_bug("non-initialized struct");
376 }
377
378 str = rb_str_buf_new2("#<");
379 rb_str_cat2(str, cname);
380 rb_str_cat2(str, " ");
381 for (i=0; i<RSTRUCT(s)->len; i++) {
382 VALUE str2, slot;
383 char *p;
384
385 if (i > 0) {
386 rb_str_cat2(str, ", ");
387 }
388 slot = RARRAY(member)->ptr[i];
389 p = rb_id2name(SYM2ID(slot));
390 rb_str_cat2(str, p);
391 rb_str_cat2(str, "=");
392 str2 = rb_inspect(RSTRUCT(s)->ptr[i]);
393 rb_str_append(str, str2);
394 }
395 rb_str_cat2(str, ">");
396 OBJ_INFECT(str, s);
397
398 return str;
399 }
400
401 static VALUE
402 rb_struct_inspect(s)
403 VALUE s;
404 {
405 if (rb_inspecting_p(s)) {
406 char *cname = rb_class2name(rb_obj_class(s));
407 VALUE str = rb_str_new(0, strlen(cname) + 8);
408
409 sprintf(RSTRING(str)->ptr, "#<%s:...>", cname);
410 RSTRING(str)->len = strlen(RSTRING(str)->ptr);
411 return str;
412 }
413 return rb_protect_inspect(inspect_struct, s, 0);
414 }
415
416 static VALUE
417 rb_struct_to_a(s)
418 VALUE s;
419 {
420 return rb_ary_new4(RSTRUCT(s)->len, RSTRUCT(s)->ptr);
421 }
422
423 static VALUE
424 rb_struct_become(copy, s)
425 VALUE copy, s;
426 {
427 if (copy == s) return copy;
428 rb_check_frozen(copy);
429 if (!rb_obj_is_instance_of(s, rb_obj_class(copy))) {
430 rb_raise(rb_eTypeError, "wrong argument class");
431 }
432 RSTRUCT(copy)->ptr = ALLOC_N(VALUE, RSTRUCT(s)->len);
433 RSTRUCT(copy)->len = RSTRUCT(s)->len;
434 MEMCPY(RSTRUCT(copy)->ptr, RSTRUCT(s)->ptr, VALUE, RSTRUCT(copy)->len);
435
436 return copy;
437 }
438
439 static VALUE
440 rb_struct_aref_id(s, id)
441 VALUE s;
442 ID id;
443 {
444 VALUE member;
445 long i, len;
446
447 member = rb_struct_iv_get(rb_obj_class(s), "__member__");
448 if (NIL_P(member)) {
449 rb_bug("non-initialized struct");
450 }
451
452 len = RARRAY(member)->len;
453 for (i=0; i<len; i++) {
454 if (SYM2ID(RARRAY(member)->ptr[i]) == id) {
455 return RSTRUCT(s)->ptr[i];
456 }
457 }
458 rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
459 return Qnil;
460 }
461
462 VALUE
463 rb_struct_aref(s, idx)
464 VALUE s, idx;
465 {
466 long i;
467
468 if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
469 return rb_struct_aref_id(s, rb_to_id(idx));
470 }
471
472 i = NUM2LONG(idx);
473 if (i < 0) i = RSTRUCT(s)->len + i;
474 if (i < 0)
475 rb_raise(rb_eIndexError, "offset %d too small for struct(size:%d)",
476 i, RSTRUCT(s)->len);
477 if (RSTRUCT(s)->len <= i)
478 rb_raise(rb_eIndexError, "offset %d too large for struct(size:%d)",
479 i, RSTRUCT(s)->len);
480 return RSTRUCT(s)->ptr[i];
481 }
482
483 static VALUE
484 rb_struct_aset_id(s, id, val)
485 VALUE s, val;
486 ID id;
487 {
488 VALUE member;
489 long i, len;
490
491 member = rb_struct_iv_get(rb_obj_class(s), "__member__");
492 if (NIL_P(member)) {
493 rb_bug("non-initialized struct");
494 }
495
496 rb_struct_modify(s);
497 len = RARRAY(member)->len;
498 for (i=0; i<len; i++) {
499 if (SYM2ID(RARRAY(member)->ptr[i]) == id) {
500 RSTRUCT(s)->ptr[i] = val;
501 return val;
502 }
503 }
504 rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
505 }
506
507 VALUE
508 rb_struct_aset(s, idx, val)
509 VALUE s, idx, val;
510 {
511 long i;
512
513 if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
514 return rb_struct_aset_id(s, rb_to_id(idx), val);
515 }
516
517 i = NUM2LONG(idx);
518 if (i < 0) i = RSTRUCT(s)->len + i;
519 if (i < 0) {
520 rb_raise(rb_eIndexError, "offset %d too small for struct(size:%d)",
521 i, RSTRUCT(s)->len);
522 }
523 if (RSTRUCT(s)->len <= i) {
524 rb_raise(rb_eIndexError, "offset %d too large for struct(size:%d)",
525 i, RSTRUCT(s)->len);
526 }
527 rb_struct_modify(s);
528 return RSTRUCT(s)->ptr[i] = val;
529 }
530
531
532 static VALUE
533 rb_struct_select(argc, argv, s)
534 int argc;
535 VALUE *argv;
536 VALUE s;
537 {
538 VALUE result = rb_ary_new();
539 long i;
540
541 if (rb_block_given_p()) {
542 if (argc > 0) {
543 rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
544 }
545 for (i = 0; i < RSTRUCT(s)->len; i++) {
546 if (RTEST(rb_yield(RSTRUCT(s)->ptr[i]))) {
547 rb_ary_push(result, RSTRUCT(s)->ptr[i]);
548 }
549 }
550 }
551 else {
552 for (i=0; i<argc; i++) {
553 rb_ary_push(result, rb_struct_aref(s, argv[i]));
554 }
555 }
556 return result;
557 }
558
559 static VALUE
560 rb_struct_equal(s, s2)
561 VALUE s, s2;
562 {
563 long i;
564
565 if (s == s2) return Qtrue;
566 if (TYPE(s2) != T_STRUCT) return Qfalse;
567 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
568 if (RSTRUCT(s)->len != RSTRUCT(s2)->len) {
569 rb_bug("inconsistent struct");
570 }
571
572 for (i=0; i<RSTRUCT(s)->len; i++) {
573 if (!rb_equal(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return Qfalse;
574 }
575 return Qtrue;
576 }
577
578 static VALUE
579 rb_struct_size(s)
580 VALUE s;
581 {
582 return LONG2FIX(RSTRUCT(s)->len);
583 }
584
585 void
586 Init_Struct()
587 {
588 rb_cStruct = rb_define_class("Struct", rb_cObject);
589 rb_include_module(rb_cStruct, rb_mEnumerable);
590
591 rb_undef_method(CLASS_OF(rb_cStruct), "allocate");
592 rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1);
593
594 rb_define_method(rb_cStruct, "initialize", rb_struct_initialize, -2);
595 rb_define_method(rb_cStruct, "become", rb_struct_become, 1);
596
597 rb_define_method(rb_cStruct, "==", rb_struct_equal, 1);
598
599 rb_define_method(rb_cStruct, "to_s", rb_struct_to_s, 0);
600 rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
601 rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
602 rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
603 rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
604 rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
605
606 rb_define_method(rb_cStruct, "each", rb_struct_each, 0);
607 rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0);
608 rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1);
609 rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2);
610 rb_define_method(rb_cStruct, "select", rb_struct_select, -1);
611
612 rb_define_method(rb_cStruct, "members", rb_struct_members, 0);
613 }