summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-complex/src/complex.c
blob: 5371332cd5820deb84caa354ac67cb98d6199df5 (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
#include <mruby.h>
#include <mruby/class.h>
#include <mruby/numeric.h>

struct mrb_complex {
  mrb_float real;
  mrb_float imaginary;
};

#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT)

#define COMPLEX_USE_ISTRUCT
/* use TT_ISTRUCT */
#include <mruby/istruct.h>

#define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v)

static mrb_value
complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary)
{
  struct RClass *c = mrb_class_get(mrb, "Complex");
  struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
  mrb_value comp = mrb_obj_value(s);
  struct mrb_complex *p = complex_ptr(mrb, comp);
  p->real = real;
  p->imaginary = imaginary;
  MRB_SET_FROZEN_FLAG(s);

  return comp;
}

#else
/* use TT_DATA */
#include <mruby/data.h>

static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free};

static mrb_value
complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary)
{
  struct RClass *c = mrb_class_get(mrb, "Complex");
  struct mrb_complex *p;

  p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex));
  p->real = real;
  p->imaginary = imaginary;

  return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p));
}

static struct mrb_complex*
complex_ptr(mrb_state *mrb, mrb_value v)
{
  struct mrb_complex *p;

  p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex);
  if (!p) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex");
  }
  return p;
}
#endif

static mrb_value
complex_real(mrb_state *mrb, mrb_value self)
{
  struct mrb_complex *p = complex_ptr(mrb, self);
  return mrb_float_value(mrb, p->real);
}

static mrb_value
complex_imaginary(mrb_state *mrb, mrb_value self)
{
  struct mrb_complex *p = complex_ptr(mrb, self);
  return mrb_float_value(mrb, p->imaginary);
}

static mrb_value
complex_s_rect(mrb_state *mrb, mrb_value self)
{
  mrb_float real, imaginary = 0.0;

  mrb_get_args(mrb, "f|f", &real, &imaginary);
  return complex_new(mrb, real, imaginary);
}

#ifndef MRB_WITHOUT_FLOAT
static mrb_value
complex_to_f(mrb_state *mrb, mrb_value self)
{
  struct mrb_complex *p = complex_ptr(mrb, self);

  if (p->imaginary != 0) {
    mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self);
  }

  return mrb_float_value(mrb, p->real);
}
#endif

static mrb_value
complex_to_i(mrb_state *mrb, mrb_value self)
{
  struct mrb_complex *p = complex_ptr(mrb, self);

  if (p->imaginary != 0) {
    mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self);
  }
  return mrb_int_value(mrb, p->real);
}

static mrb_value
complex_to_c(mrb_state *mrb, mrb_value self)
{
  return self;
}

void mrb_mruby_complex_gem_init(mrb_state *mrb)
{
  struct RClass *comp;

#ifdef COMPLEX_USE_ISTRUCT
  mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE);
#endif
  comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric"));
  //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT);
  mrb_undef_class_method(mrb, comp, "new");
  mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
  mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
  mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
  mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE());
  mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE());
#ifndef MRB_WITHOUT_FLOAT
  mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE());
#endif
  mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE());
  mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE());
}

void
mrb_mruby_complex_gem_final(mrb_state* mrb)
{
}