summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/bigdecimal/bigdecimal.c89
-rw-r--r--ext/bigdecimal/bigdecimal.h7
-rw-r--r--test/bigdecimal/test_bigdecimal.rb23
4 files changed, 95 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 255cc8dac8..0f45340c9b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed Dec 21 12:35:24 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_s_allocate): follow
+ Allocation Framework. [Bug #5775]
+
Wed Dec 21 02:25:36 2011 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/emitter.c: fixing clang warnings. Thanks Joey!
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index ce1feeb090..8cb02d07e9 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -131,7 +131,7 @@ static unsigned short VpGetException(void);
static void VpSetException(unsigned short f);
static void VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v);
static int VpLimitRound(Real *c, size_t ixDigit);
-static Real *VpDup(Real const* const x);
+static Real *VpCopy(Real *pv, Real const* const x);
/*
* **** BigDecimal part ****
@@ -561,15 +561,14 @@ VpCreateRbObject(size_t mx, const char *str)
}
#define VpAllocReal(prec) (Real *)VpMemAlloc(offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
+#define VpReallocReal(ptr, prec) (Real *)VpMemRealloc((ptr), offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
static Real *
-VpDup(Real const* const x)
+VpCopy(Real *pv, Real const* const x)
{
- Real *pv;
-
assert(x != NULL);
- pv = VpAllocReal(x->MaxPrec);
+ pv = VpReallocReal(pv, x->MaxPrec);
pv->MaxPrec = x->MaxPrec;
pv->Prec = x->Prec;
pv->exponent = x->exponent;
@@ -577,9 +576,6 @@ VpDup(Real const* const x)
pv->flag = x->flag;
MEMCPY(pv->frac, x->frac, BDIGIT, pv->MaxPrec);
- pv->obj = TypedData_Wrap_Struct(
- rb_obj_class(x->obj), &BigDecimal_data_type, pv);
-
return pv;
}
@@ -2254,6 +2250,14 @@ BigDecimal_power_op(VALUE self, VALUE exp)
return BigDecimal_power(1, &exp, self);
}
+static VALUE
+BigDecimal_s_allocate(VALUE klass)
+{
+ return VpNewRbClass(0, NULL, klass)->obj;
+}
+
+static Real *BigDecimal_new(int argc, VALUE *argv);
+
/* call-seq:
* new(initial, digits)
*
@@ -2272,10 +2276,36 @@ BigDecimal_power_op(VALUE self, VALUE exp)
* larger than the specified number.
*/
static VALUE
-BigDecimal_new(int argc, VALUE *argv, VALUE self)
+BigDecimal_initialize(int argc, VALUE *argv, VALUE self)
+{
+ Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
+ Real *x = BigDecimal_new(argc, argv);
+
+ if (ToValue(x)) {
+ pv = VpCopy(pv, x);
+ }
+ else {
+ VpFree(pv);
+ pv = x;
+ }
+ DATA_PTR(self) = pv;
+ pv->obj = self;
+ return self;
+}
+
+static VALUE
+BigDecimal_initialize_copy(VALUE self, VALUE other)
+{
+ Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
+ Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
+
+ DATA_PTR(self) = VpCopy(pv, x);
+ return self;
+}
+
+static Real *
+BigDecimal_new(int argc, VALUE *argv)
{
- ENTER(5);
- Real *pv;
size_t mf;
VALUE nFig;
VALUE iniValue;
@@ -2290,15 +2320,14 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self)
switch (TYPE(iniValue)) {
case T_DATA:
if (is_kind_of_BigDecimal(iniValue)) {
- pv = VpDup(DATA_PTR(iniValue));
- return ToValue(pv);
+ return DATA_PTR(iniValue);
}
break;
case T_FIXNUM:
/* fall through */
case T_BIGNUM:
- return ToValue(GetVpValue(iniValue, 1));
+ return GetVpValue(iniValue, 1);
case T_FLOAT:
if (mf > DBL_DIG+1) {
@@ -2309,23 +2338,25 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self)
if (NIL_P(nFig)) {
rb_raise(rb_eArgError, "can't omit precision for a Rational.");
}
- return ToValue(GetVpValueWithPrec(iniValue, mf, 1));
+ return GetVpValueWithPrec(iniValue, mf, 1);
case T_STRING:
/* fall through */
default:
break;
}
- SafeStringValue(iniValue);
- GUARD_OBJ(pv, VpNewRbClass(mf, RSTRING_PTR(iniValue),self));
-
- return ToValue(pv);
+ StringValueCStr(iniValue);
+ rb_check_safe_obj(iniValue);
+ return VpAlloc(mf, RSTRING_PTR(iniValue));
}
static VALUE
BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
{
- return BigDecimal_new(argc, argv, rb_cBigDecimal);
+ Real *pv = BigDecimal_new(argc, argv);
+ if (ToValue(pv)) pv = VpCopy(NULL, pv);
+ pv->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv);
+ return pv->obj;
}
/* call-seq:
@@ -2830,16 +2861,12 @@ Init_bigdecimal(void)
/* Class and method registration */
rb_cBigDecimal = rb_define_class("BigDecimal",rb_cNumeric);
- rb_undef_alloc_func(rb_cBigDecimal); /* TODO: define alloc func */
+ rb_define_alloc_func(rb_cBigDecimal, BigDecimal_s_allocate);
/* Global function */
rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
/* Class methods */
-#if 1
- /* TODO: follow allocation framework */
- rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1);
-#endif
rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
@@ -2963,6 +2990,8 @@ Init_bigdecimal(void)
/* instance methods */
+ rb_define_method(rb_cBigDecimal, "initialize", BigDecimal_initialize, -1);
+ rb_define_method(rb_cBigDecimal, "initialize_copy", BigDecimal_initialize_copy, 1);
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
@@ -3093,6 +3122,16 @@ VpMemAlloc(size_t mb)
return p;
}
+VP_EXPORT void *
+VpMemRealloc(void *ptr, size_t mb)
+{
+ void *p = xrealloc(ptr, mb);
+ if (!p) {
+ VpException(VP_EXCEPTION_MEMORY, "failed to allocate memory", 1);
+ }
+ return p;
+}
+
VP_EXPORT void
VpFree(Real *pv)
{
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
index 80d2af20d7..b1dfd9c371 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -21,6 +21,9 @@
#if defined(__cplusplus)
extern "C" {
+#if 0
+}
+#endif
#endif
#ifndef HAVE_LABS
@@ -197,6 +200,7 @@ VP_EXPORT int VpIsNegDoubleZero(double v);
VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
VP_EXPORT size_t VpInit(BDIGIT BaseVal);
VP_EXPORT void *VpMemAlloc(size_t mb);
+VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb);
VP_EXPORT void VpFree(Real *pv);
VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal);
VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
@@ -279,6 +283,9 @@ VP_EXPORT int VPrint(FILE *fp,const char *cntl_chr,Real *a);
#endif /* BIGDECIMAL_DEBUG */
#if defined(__cplusplus)
+#if 0
+{
+#endif
} /* extern "C" { */
#endif
#endif /* RUBY_BIG_DECIMAL_H */
diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb
index e855d5617d..51dcb8e29b 100644
--- a/test/bigdecimal/test_bigdecimal.rb
+++ b/test/bigdecimal/test_bigdecimal.rb
@@ -19,10 +19,6 @@ class TestBigDecimal < Test::Unit::TestCase
[ BigDecimal::ROUND_FLOOR, :floor],
]
- def assert_allocate
- assert_raise(TypeError) {BigDecimal.allocate}
- end
-
def assert_nan(x)
assert(x.nan?, "Expected #{x.inspect} to be NaN")
end
@@ -47,6 +43,10 @@ class TestBigDecimal < Test::Unit::TestCase
"Expected #{x.inspect} to be negative zero")
end
+ def test_not_equal
+ assert_not_equal BigDecimal("1"), BigDecimal.allocate
+ end
+
def test_global_new
assert_equal(1, BigDecimal("1"))
assert_equal(1, BigDecimal("1", 1))
@@ -1288,4 +1288,19 @@ class TestBigDecimal < Test::Unit::TestCase
end
end
end
+
+ def test_dup
+ [1, -1, 2**100, -2**100].each do |i|
+ x = BigDecimal(i)
+ assert_equal(x, x.dup)
+ end
+ end
+
+ def test_dup_subclass
+ c = Class.new(BigDecimal)
+ x = c.new(1)
+ y = x.dup
+ assert_equal(1, y)
+ assert_kind_of(c, y)
+ end
end