summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-struct/src/struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-struct/src/struct.c')
-rw-r--r--mrbgems/mruby-struct/src/struct.c89
1 files changed, 61 insertions, 28 deletions
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index 121226717..a15655dbb 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -11,6 +11,8 @@
#include "mruby/string.h"
#include "mruby/class.h"
#include "mruby/variable.h"
+#include "mruby/hash.h"
+#include "mruby/range.h"
#define RSTRUCT_LEN(st) RARRAY_LEN(st)
#define RSTRUCT_PTR(st) RARRAY_PTR(st)
@@ -530,7 +532,7 @@ mrb_struct_init_copy(mrb_state *mrb, mrb_value copy)
}
static mrb_value
-mrb_struct_aref_id(mrb_state *mrb, mrb_value s, mrb_sym id)
+struct_aref_sym(mrb_state *mrb, mrb_value s, mrb_sym id)
{
mrb_value *ptr, members, *ptr_members;
mrb_int i, len;
@@ -548,6 +550,21 @@ mrb_struct_aref_id(mrb_state *mrb, mrb_value s, mrb_sym id)
return mrb_nil_value(); /* not reached */
}
+static mrb_value
+struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i)
+{
+ if (i < 0) i = RSTRUCT_LEN(s) + i;
+ if (i < 0)
+ mrb_raisef(mrb, E_INDEX_ERROR,
+ "offset %S too small for struct(size:%S)",
+ mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
+ if (RSTRUCT_LEN(s) <= i)
+ mrb_raisef(mrb, E_INDEX_ERROR,
+ "offset %S too large for struct(size:%S)",
+ mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
+ return RSTRUCT_PTR(s)[i];
+}
+
/* 15.2.18.4.2 */
/*
* call-seq:
@@ -568,10 +585,11 @@ mrb_struct_aref_id(mrb_state *mrb, mrb_value s, mrb_sym id)
* joe[0] #=> "Joe Smith"
*/
mrb_value
-mrb_struct_aref_n(mrb_state *mrb, mrb_value s, mrb_value idx)
+mrb_struct_aref(mrb_state *mrb, mrb_value s)
{
- mrb_int i;
+ mrb_value idx;
+ mrb_get_args(mrb, "o", &idx);
if (mrb_string_p(idx)) {
mrb_value sym = mrb_check_intern_str(mrb, idx);
@@ -581,33 +599,13 @@ mrb_struct_aref_n(mrb_state *mrb, mrb_value s, mrb_value idx)
idx = sym;
}
if (mrb_symbol_p(idx)) {
- return mrb_struct_aref_id(mrb, s, mrb_symbol(idx));
+ return struct_aref_sym(mrb, s, mrb_symbol(idx));
}
-
- i = mrb_fixnum(idx);
- if (i < 0) i = RSTRUCT_LEN(s) + i;
- if (i < 0)
- mrb_raisef(mrb, E_INDEX_ERROR,
- "offset %S too small for struct(size:%S)",
- mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
- if (RSTRUCT_LEN(s) <= i)
- mrb_raisef(mrb, E_INDEX_ERROR,
- "offset %S too large for struct(size:%S)",
- mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
- return RSTRUCT_PTR(s)[i];
-}
-
-mrb_value
-mrb_struct_aref(mrb_state *mrb, mrb_value s)
-{
- mrb_value idx;
-
- mrb_get_args(mrb, "o", &idx);
- return mrb_struct_aref_n(mrb, s, idx);
+ return struct_aref_int(mrb, s, mrb_int(mrb, idx));
}
static mrb_value
-mrb_struct_aset_id(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val)
+mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val)
{
mrb_value members, *ptr, *ptr_members;
mrb_int i, len;
@@ -662,8 +660,8 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s)
mrb_get_args(mrb, "oo", &idx, &val);
- if (mrb_string_p(idx) || mrb_symbol_p(idx)) {
- return mrb_struct_aset_id(mrb, s, mrb_obj_to_sym(mrb, idx), val);
+ if (mrb_symbol_p(idx)) {
+ return mrb_struct_aset_sym(mrb, s, mrb_symbol(idx), val);
}
i = mrb_fixnum(idx);
@@ -806,6 +804,39 @@ mrb_struct_to_a(mrb_state *mrb, mrb_value self)
}
/*
+ * call-seq:
+ * struct.to_h -> hash
+ *
+ * Create a hash from member names and struct values.
+ */
+static mrb_value
+mrb_struct_to_h(mrb_state *mrb, mrb_value self)
+{
+ mrb_value members, ret;
+ mrb_int i;
+
+ members = mrb_struct_s_members(mrb, mrb_obj_value(mrb_class(mrb, self)));
+ ret = mrb_hash_new_capa(mrb, RARRAY_LEN(members));
+
+ for (i = 0; i < RARRAY_LEN(members); ++i) {
+ mrb_hash_set(mrb, ret, RARRAY_PTR(members)[i], RSTRUCT_PTR(self)[i]);
+ }
+
+ return ret;
+}
+
+static mrb_value
+mrb_struct_values_at(mrb_state *mrb, mrb_value self)
+{
+ mrb_int argc;
+ mrb_value *argv;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+
+ return mrb_get_values_at(mrb, self, RSTRUCT_LEN(self), argc, argv, struct_aref_int);
+}
+
+/*
* A <code>Struct</code> is a convenient way to bundle a number of
* attributes together, using accessor methods, without having to write
* an explicit class.
@@ -842,6 +873,8 @@ mrb_mruby_struct_gem_init(mrb_state* mrb)
mrb_define_method(mrb, st, "length", mrb_struct_len, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE());
+ mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE());
+ mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE());
}
void