@@ -52,6 +52,94 @@ static decContext dec_context = {
52
52
0 , /*no clamping*/
53
53
};
54
54
55
+ static decContext dec_context_to_double = {
56
+ BIN64_DEC_PRECISION ,
57
+ DEC_MAX_EMAX ,
58
+ DEC_MIN_EMAX ,
59
+ DEC_ROUND_HALF_UP ,
60
+ 0 , /*no errors*/
61
+ 0 , /*status*/
62
+ 0 , /*no clamping*/
63
+ };
64
+
65
+ #include <pthread.h>
66
+
67
+ static pthread_key_t dec_ctx_key ;
68
+ static pthread_key_t dec_ctx_dbl_key ;
69
+ static pthread_once_t dec_ctx_once = PTHREAD_ONCE_INIT ;
70
+
71
+ #define DEC_CONTEXT tsd_dec_ctx_get(&dec_ctx_key)
72
+ #define DEC_CONTEXT_TO_DOUBLE tsd_dec_ctx_get(&dec_ctx_dbl_key)
73
+
74
+ static void tsd_dec_ctx_init () {
75
+ if (pthread_key_create (& dec_ctx_key , jv_mem_free ) != 0 ) {
76
+ fprintf (stderr , "error: cannot create thread specific key" );
77
+ abort ();
78
+ }
79
+ decContext * ctx = calloc (1 , sizeof (decContext ));
80
+ * ctx = dec_context ;
81
+ if (pthread_setspecific (dec_ctx_key , ctx ) != 0 ) {
82
+ fprintf (stderr , "error: cannot set thread specific data" );
83
+ abort ();
84
+ }
85
+
86
+ if (pthread_key_create (& dec_ctx_dbl_key , jv_mem_free ) != 0 ) {
87
+ fprintf (stderr , "error: cannot create thread specific key" );
88
+ abort ();
89
+ }
90
+ ctx = calloc (1 , sizeof (decContext ));
91
+ * ctx = dec_context_to_double ;
92
+ if (pthread_setspecific (dec_ctx_dbl_key , ctx ) != 0 ) {
93
+ fprintf (stderr , "error: cannot set thread specific data" );
94
+ abort ();
95
+ }
96
+ }
97
+
98
+ static decContext * tsd_dec_ctx_get (pthread_key_t * key ) {
99
+ pthread_once (& dec_ctx_once , tsd_dec_ctx_init ); // cannot fail
100
+ return (decContext * )pthread_getspecific (* key );
101
+ }
102
+
103
+
104
+ static pthread_key_t dtoa_ctx_key ;
105
+ static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT ;
106
+
107
+ static struct dtoa_context * tsd_dtoa_context ();
108
+
109
+ static void tsd_dtoa_ctx_dtor (void * ptr ) {
110
+ if (ptr ) {
111
+ jvp_dtoa_context_free ((struct dtoa_context * )ptr );
112
+ jv_mem_free (ptr );
113
+ }
114
+ }
115
+ static void tsd_dtoa_ctx_fini () {
116
+ struct dtoa_context * ctx = tsd_dtoa_context ();
117
+ tsd_dtoa_ctx_dtor (ctx );
118
+ pthread_setspecific (dtoa_ctx_key , NULL );
119
+ }
120
+
121
+ static void tsd_dtoa_ctx_init () {
122
+ if (pthread_key_create (& dtoa_ctx_key , tsd_dtoa_ctx_fini ) != 0 ) {
123
+ fprintf (stderr , "error: cannot create thread specific key" );
124
+ abort ();
125
+ }
126
+ atexit (tsd_dtoa_ctx_fini );
127
+ }
128
+
129
+ static inline struct dtoa_context * tsd_dtoa_context () {
130
+ pthread_once (& dtoa_ctx_once , tsd_dtoa_ctx_init ); // cannot fail
131
+ struct dtoa_context * ctx = (struct dtoa_context * )pthread_getspecific (dtoa_ctx_key );
132
+ if (!ctx ) {
133
+ ctx = malloc (sizeof (struct dtoa_context ));
134
+ jvp_dtoa_context_init (ctx );
135
+ if (pthread_setspecific (dtoa_ctx_key , ctx ) != 0 ) {
136
+ fprintf (stderr , "error: cannot set thread specific data" );
137
+ abort ();
138
+ }
139
+ }
140
+ return ctx ;
141
+ }
142
+
55
143
typedef struct {
56
144
jv_refcnt refcnt ;
57
145
double num_double ;
@@ -69,34 +157,6 @@ typedef struct {
69
157
decNumberUnit units [BIN64_DEC_PRECISION ];
70
158
} decNumberDoublePrecision ;
71
159
72
- static decContext dec_context_to_double = {
73
- BIN64_DEC_PRECISION ,
74
- DEC_MAX_EMAX ,
75
- DEC_MIN_EMAX ,
76
- DEC_ROUND_HALF_UP ,
77
- 0 , /*no errors*/
78
- 0 , /*status*/
79
- 0 , /*no clamping*/
80
- };
81
-
82
- static struct {
83
- uint64_t refcnt ;
84
- struct dtoa_context C ;
85
- } shared_dtoa_context ;
86
-
87
- static void jvp_number_dtoa_ctx_require () {
88
- if (shared_dtoa_context .refcnt == 0 ) {
89
- jvp_dtoa_context_init (& shared_dtoa_context .C );
90
- }
91
- shared_dtoa_context .refcnt ++ ;
92
- }
93
-
94
- static void jvp_number_dtoa_ctx_release () {
95
- assert (shared_dtoa_context .refcnt > 0 );
96
- if (-- shared_dtoa_context .refcnt == 0 ) {
97
- jvp_dtoa_context_free (& shared_dtoa_context .C );
98
- }
99
- }
100
160
101
161
static inline int jvp_number_is_literal (jv n ) {
102
162
assert (JVP_HAS_KIND (n , JV_KIND_NUMBER ));
@@ -130,15 +190,12 @@ static jv jvp_literal_number_new(const char * literal) {
130
190
131
191
jvp_literal_number * n = jvp_literal_number_alloc (strlen (literal ));
132
192
133
- // make sure that the dtoa context is somewhere around
134
- jvp_number_dtoa_ctx_require ();
135
-
136
193
n -> refcnt = JV_REFCNT_INIT ;
137
194
n -> literal_data = NULL ;
138
- decNumberFromString (& n -> num_decimal , literal , & dec_context );
195
+ decNumberFromString (& n -> num_decimal , literal , DEC_CONTEXT );
139
196
n -> num_double = NAN ;
140
197
141
- if (dec_context . status & DEC_Conversion_syntax ) {
198
+ if (DEC_CONTEXT -> status & DEC_Conversion_syntax ) {
142
199
jv_mem_free (n );
143
200
return JV_INVALID ;
144
201
}
@@ -157,12 +214,12 @@ static double jvp_literal_number_to_double(jv j) {
157
214
// reduce the number to the shortest possible form
158
215
// while also making sure than no more than BIN64_DEC_PRECISION
159
216
// digits are used (dec_context_to_double)
160
- decNumberReduce (& dec_double .number , p_dec_number , & dec_context_to_double );
217
+ decNumberReduce (& dec_double .number , p_dec_number , DEC_CONTEXT_TO_DOUBLE );
161
218
162
219
decNumberToString (& dec_double .number , literal );
163
220
164
221
char * end ;
165
- return jvp_strtod (& shared_dtoa_context . C , literal , & end );
222
+ return jvp_strtod (tsd_dtoa_context () , literal , & end );
166
223
}
167
224
168
225
@@ -219,7 +276,6 @@ const char* jv_number_get_literal(jv n) {
219
276
void jvp_number_free (jv j ) {
220
277
assert (JVP_HAS_KIND (j , JV_KIND_NUMBER ));
221
278
if (JVP_HAS_FLAGS (j , JVP_FLAGS_NUMBER_LITERAL ) && jvp_refcnt_dec (j .u .ptr )) {
222
- jvp_number_dtoa_ctx_release ();
223
279
jvp_literal_number * n = jvp_literal_number_ptr (j );
224
280
if (n -> literal_data ) {
225
281
jv_mem_free (n -> literal_data );
@@ -286,7 +342,7 @@ int jvp_number_cmp(jv a, jv b) {
286
342
decNumberCompare (& res .number ,
287
343
jvp_dec_number_ptr (a ),
288
344
jvp_dec_number_ptr (b ),
289
- & dec_context
345
+ DEC_CONTEXT
290
346
);
291
347
if (decNumberIsZero (& res .number )) {
292
348
return 0 ;
0 commit comments