[前][次][番号順一覧][スレッド一覧]

ruby-changes:17099

From: mrkn <ko1@a...>
Date: Thu, 26 Aug 2010 09:14:24 +0900 (JST)
Subject: [ruby-changes:17099] Ruby:r29099 (trunk): * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_exception_mode, VpGetException, VpSetException): thread-local exception mode.

mrkn	2010-08-26 09:14:18 +0900 (Thu, 26 Aug 2010)

  New Revision: 29099

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=29099

  Log:
    * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_exception_mode, VpGetException, VpSetException): thread-local exception mode.
    * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_precision_limit, VpGetPrecLimit, VpSetPrecLimit): thread-local precision limit.
    * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_rounding_mode, VpGetRoundMode, VpSetRoundMode, VpException, VpInternalRound): thread-local rounding mode.
    * ext/bigdecimal/bigdecimal.c (BigDecimal_mode, BigDecimal_round, VpIsRoundMode, VpGetRoundMode, VpSetRoundMode, VpActiveRound, VpMidRound, VpLeftRound), ext/bigdecimal/bigdecimal.h: use unsigned short for rounding mode.
    * test/bigdecimal/test_bigdecimal.rb (test_mode): add test for setting rounding mode.
    * test/bigdecimal/test_bigdecimal.rb (test_thread_local_mode): add test for setting mode thread-locally.

  Modified files:
    trunk/ChangeLog
    trunk/ext/bigdecimal/bigdecimal.c
    trunk/ext/bigdecimal/bigdecimal.h
    trunk/test/bigdecimal/test_bigdecimal.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 29098)
+++ ChangeLog	(revision 29099)
@@ -1,3 +1,29 @@
+Tue Aug 26 09:11:40 2010  Kenta Murata  <mrkn@m...>
+
+	* ext/bigdecimal/bigdecimal.c (Init_bigdecimal,
+	  rmpd_set_thread_local_exception_mode, VpGetException,
+	  VpSetException): thread-local exception mode.
+
+	* ext/bigdecimal/bigdecimal.c (Init_bigdecimal,
+	  rmpd_set_thread_local_precision_limit, VpGetPrecLimit,
+	  VpSetPrecLimit): thread-local precision limit.
+
+	* ext/bigdecimal/bigdecimal.c (Init_bigdecimal,
+	  rmpd_set_thread_local_rounding_mode, VpGetRoundMode,
+	  VpSetRoundMode, VpException, VpInternalRound):
+	  thread-local rounding mode.
+
+	* ext/bigdecimal/bigdecimal.c (BigDecimal_mode, BigDecimal_round,
+	  VpIsRoundMode, VpGetRoundMode, VpSetRoundMode, VpActiveRound,
+	  VpMidRound, VpLeftRound), ext/bigdecimal/bigdecimal.h:
+	  use unsigned short for rounding mode.
+
+	* test/bigdecimal/test_bigdecimal.rb (test_mode): add test for
+	  setting rounding mode.
+
+	* test/bigdecimal/test_bigdecimal.rb (test_thread_local_mode):
+	  add test for setting mode thread-locally.
+
 Thu Aug 26 07:29:54 2010  Nobuyoshi Nakada  <nobu@r...>
 
 	* array.c (rb_ary_{shuffle_bang,sample}): use Random class object.
Index: ext/bigdecimal/bigdecimal.c
===================================================================
--- ext/bigdecimal/bigdecimal.c	(revision 29098)
+++ ext/bigdecimal/bigdecimal.c	(revision 29099)
@@ -32,6 +32,10 @@
 
 VALUE rb_cBigDecimal;
 
+static ID id_BigDecimal_exception_mode;
+static ID id_BigDecimal_rounding_mode;
+static ID id_BigDecimal_precision_limit;
+
 /* MACRO's to guard objects from GC by keeping them in stack */
 #define ENTER(n) volatile VALUE vStack[n];int iStack=0
 #define PUSH(x)  vStack[iStack++] = (unsigned long)(x);
@@ -358,11 +362,11 @@
         fo = VpGetRoundMode();
         if(val==Qnil) return INT2FIX(fo);
         Check_Type(val, T_FIXNUM);
-        if(!VpIsRoundMode(FIX2INT(val))) {
+        if(!VpIsRoundMode((unsigned short)FIX2INT(val))) {
             rb_raise(rb_eTypeError, "invalid rounding mode");
             return Qnil;
         }
-        fo = VpSetRoundMode((unsigned long)FIX2INT(val));
+        fo = VpSetRoundMode((unsigned short)FIX2INT(val));
         return INT2FIX(fo);
     }
     rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
@@ -1279,7 +1283,7 @@
     VALUE  vRound;
     size_t mx, pl;
 
-    int    sw = (int)VpGetRoundMode();
+    unsigned short sw = VpGetRoundMode();
 
     int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound);
     switch(na) {
@@ -1294,7 +1298,7 @@
         Check_Type(vLoc, T_FIXNUM);
         iLoc = FIX2INT(vLoc);
         Check_Type(vRound, T_FIXNUM);
-        sw   = FIX2INT(vRound);
+        sw   = (unsigned short)FIX2INT(vRound);
         if(!VpIsRoundMode(sw)) {
             rb_raise(rb_eTypeError, "invalid rounding mode");
             return Qnil;
@@ -2086,6 +2090,10 @@
     rb_define_method(rb_cBigDecimal, "finite?",   BigDecimal_IsFinite, 0);
     rb_define_method(rb_cBigDecimal, "truncate",  BigDecimal_truncate, -1);
     rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
+
+    id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
+    id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode");
+    id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit");
 }
 
 /*
@@ -2104,9 +2112,6 @@
 #endif
 #endif /* BIGDECIMAL_DEBUG */
 
-static size_t gnPrecLimit = 0;  /* Global upper limit of the precision newly allocated */
-static size_t gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation   */
-
 static Real *VpConstOne;    /* constant 1.0 */
 static Real *VpPt5;        /* constant 0.5 */
 #define maxnr 100UL    /* Maximum iterations for calcurating sqrt. */
@@ -2165,57 +2170,127 @@
 /*
  * EXCEPTION Handling.
  */
-static unsigned short gfDoException = 0; /* Exception flag */
 
+#define rmpd_set_thread_local_exception_mode(mode) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_exception_mode, \
+	INT2FIX((int)(mode)) \
+    )
+
 static unsigned short
 VpGetException (void)
 {
-    return gfDoException;
+    VALUE const vmode = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_exception_mode
+    );
+
+    if (NIL_P(vmode)) {
+	rmpd_set_thread_local_exception_mode(RMPD_EXCEPTION_MODE_DEFAULT);
+	return RMPD_EXCEPTION_MODE_DEFAULT;
+    }
+
+    return (unsigned short)FIX2UINT(vmode);
 }
 
 static void
 VpSetException(unsigned short f)
 {
-    gfDoException = f;
+    rmpd_set_thread_local_exception_mode(f);
 }
 
+/*
+ * Precision limit.
+ */
+
+#define rmpd_set_thread_local_precision_limit(limit) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_precision_limit, \
+	SIZET2NUM(limit) \
+    )
+#define RMPD_PRECISION_LIMIT_DEFAULT ((size_t)0)
+
 /* These 2 functions added at v1.1.7 */
 VP_EXPORT size_t
 VpGetPrecLimit(void)
 {
-    return gnPrecLimit;
+    VALUE const vlimit = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_precision_limit
+    );
+
+    if (NIL_P(vlimit)) {
+	rmpd_set_thread_local_precision_limit(RMPD_PRECISION_LIMIT_DEFAULT);
+	return RMPD_PRECISION_LIMIT_DEFAULT;
+    }
+
+    return NUM2SIZET(vlimit);
 }
 
 VP_EXPORT size_t
 VpSetPrecLimit(size_t n)
 {
-    size_t s = gnPrecLimit;
-    gnPrecLimit = n;
+    size_t const s = VpGetPrecLimit();
+    rmpd_set_thread_local_precision_limit(n);
     return s;
 }
 
-VP_EXPORT unsigned long
+/*
+ * Rounding mode.
+ */
+
+#define rmpd_set_thread_local_rounding_mode(mode) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_rounding_mode, \
+	INT2FIX((int)(mode)) \
+    )
+
+VP_EXPORT unsigned short
 VpGetRoundMode(void)
 {
-    return gfRoundMode;
+    VALUE const vmode = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_rounding_mode
+    );
+
+    if (NIL_P(vmode)) {
+	rmpd_set_thread_local_rounding_mode(RMPD_ROUNDING_MODE_DEFAULT);
+	return RMPD_ROUNDING_MODE_DEFAULT;
+    }
+
+    return (unsigned short)FIX2INT(vmode);
 }
 
 VP_EXPORT int
-VpIsRoundMode(unsigned long n)
+VpIsRoundMode(unsigned short n)
 {
-    if(n==VP_ROUND_UP      || n==VP_ROUND_DOWN      ||
-       n==VP_ROUND_HALF_UP || n==VP_ROUND_HALF_DOWN ||
-       n==VP_ROUND_CEIL    || n==VP_ROUND_FLOOR     ||
-       n==VP_ROUND_HALF_EVEN
-      ) return 1;
-    return 0;
+    switch (n) {
+      case VP_ROUND_UP:
+      case VP_ROUND_DOWN:
+      case VP_ROUND_HALF_UP:
+      case VP_ROUND_HALF_DOWN:
+      case VP_ROUND_CEIL:
+      case VP_ROUND_FLOOR:
+      case VP_ROUND_HALF_EVEN:
+	return 1;
+
+      default:
+	return 0;
+    }
 }
 
-VP_EXPORT unsigned long
-VpSetRoundMode(unsigned long n)
+VP_EXPORT unsigned short
+VpSetRoundMode(unsigned short n)
 {
-    if(VpIsRoundMode(n)) gfRoundMode = n;
-    return gfRoundMode;
+    if (VpIsRoundMode(n)) {
+	rmpd_set_thread_local_rounding_mode(n);
+	return n;
+    }
+
+    return VpGetRoundMode();
 }
 
 /*
@@ -2300,10 +2375,11 @@
 {
     VALUE exc;
     int   fatal=0;
+    unsigned short const exception_mode = VpGetException();
 
     if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1;
 
-    if(always||(gfDoException&f)) {
+    if (always || (exception_mode & f)) {
         switch(f)
         {
         /*
@@ -4429,7 +4505,7 @@
  *
  */
 VP_EXPORT int
-VpMidRound(Real *y, int f, ssize_t nf)
+VpMidRound(Real *y, unsigned short f, ssize_t nf)
 /*
  * Round reletively from the decimal point.
  *    f: rounding mode
@@ -4539,7 +4615,7 @@
 }
 
 VP_EXPORT int
-VpLeftRound(Real *y, int f, ssize_t nf)
+VpLeftRound(Real *y, unsigned short f, ssize_t nf)
 /*
  * Round from the left hand side of the digits.
  */
@@ -4554,7 +4630,7 @@
 }
 
 VP_EXPORT int
-VpActiveRound(Real *y, Real *x, int f, ssize_t nf)
+VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
 {
     /* First,assign whole value in truncation mode */
     if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */
@@ -4577,11 +4653,13 @@
 {
     int f = 0;
 
+    unsigned short const rounding_mode = VpGetRoundMode();
+
     if(VpLimitRound(c,ixDigit)) return;
     if(!v)                      return;
 
     v /= BASE1;
-    switch(gfRoundMode) {
+    switch (rounding_mode) {
     case VP_ROUND_DOWN:
         break;
     case VP_ROUND_UP:
Index: ext/bigdecimal/bigdecimal.h
===================================================================
--- ext/bigdecimal/bigdecimal.h	(revision 29098)
+++ ext/bigdecimal/bigdecimal.h	(revision 29099)
@@ -98,6 +98,8 @@
 #define VP_EXCEPTION_OP         ((unsigned short)0x0020)
 #define VP_EXCEPTION_MEMORY     ((unsigned short)0x0040)
 
+#define RMPD_EXCEPTION_MODE_DEFAULT 0U
+
 /* Computation mode */
 #define VP_ROUND_MODE            ((unsigned short)0x0100)
 #define VP_ROUND_UP         1
@@ -108,6 +110,8 @@
 #define VP_ROUND_FLOOR      6
 #define VP_ROUND_HALF_EVEN  7
 
+#define RMPD_ROUNDING_MODE_DEFAULT  VP_ROUND_HALF_UP
+
 #define VP_SIGN_NaN                0 /* NaN                      */
 #define VP_SIGN_POSITIVE_ZERO      1 /* Positive zero            */
 #define VP_SIGN_NEGATIVE_ZERO     -1 /* Negative zero            */
@@ -176,9 +180,9 @@
 VP_EXPORT size_t VpSetPrecLimit(size_t n);
 
 /* Round mode */
-VP_EXPORT int           VpIsRoundMode(unsigned long n);
-VP_EXPORT unsigned long VpGetRoundMode(void);
-VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);
+VP_EXPORT int            VpIsRoundMode(unsigned short n);
+VP_EXPORT unsigned short VpGetRoundMode(void);
+VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
 
 VP_EXPORT int VpException(unsigned short f,const char *str,int always);
 #if 0  /* unused */
@@ -206,9 +210,9 @@
 VP_EXPORT void VpItoV(Real *m,S_INT ival);
 #endif
 VP_EXPORT int VpSqrt(Real *y,Real *x);
-VP_EXPORT int VpActiveRound(Real *y, Real *x, int f, ssize_t il);
-VP_EXPORT int VpMidRound(Real *y, int f, ssize_t nf);
-VP_EXPORT int VpLeftRound(Real *y, int f, ssize_t nf);
+VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
+VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
 VP_EXPORT void VpFrac(Real *y, Real *x);
 VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n);
 
Index: test/bigdecimal/test_bigdecimal.rb
===================================================================
--- test/bigdecimal/test_bigdecimal.rb	(revision 29098)
+++ test/bigdecimal/test_bigdecimal.rb	(revision 29099)
@@ -1,5 +1,7 @@
 require_relative "testbase"
 
+require 'thread'
+
 class TestBigDecimal < Test::Unit::TestCase
   include TestBigDecimalBase
 
@@ -40,8 +42,41 @@
     assert_raise(TypeError) { BigDecimal.mode(BigDecimal::EXCEPTION_ALL, 1) }
     assert_raise(TypeError) { BigDecimal.mode(BigDecimal::ROUND_MODE, 256) }
     assert_raise(TypeError) { BigDecimal.mode(0xf000, true) }
+
+    begin
+      saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE)
+
+      [ BigDecimal::ROUND_UP,
+        BigDecimal::ROUND_DOWN,
+        BigDecimal::ROUND_HALF_UP,
+        BigDecimal::ROUND_HALF_DOWN,
+        BigDecimal::ROUND_CEILING,
+        BigDecimal::ROUND_FLOOR,
+        BigDecimal::ROUND_HALF_EVEN,
+      ].each do |mode|
+        BigDecimal.mode(BigDecimal::ROUND_MODE, mode)
+        assert_equal(mode, BigDecimal.mode(BigDecimal::ROUND_MODE))
+      end
+    ensure
+      BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode)
+    end
   end
 
+  def test_thread_local_mode
+    begin
+      saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE)
+
+      BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_UP)
+      Thread.start {
+        BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_EVEN)
+        assert_equal(BigDecimal::ROUND_HALF_EVEN, BigDecimal.mode(BigDecimal::ROUND_MODE))
+      }.join
+      assert_equal(BigDecimal::ROUND_UP, BigDecimal.mode(BigDecimal::ROUND_MODE))
+    ensure
+      BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode)
+    end
+  end
+
   def test_exception_nan
     _test_mode(BigDecimal::EXCEPTION_NaN) { BigDecimal.new("NaN") }
   end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]