~ubuntu-branches/debian/sid/php-cassandra/sid

« back to all changes in this revision

Viewing changes to cassandra-1.3.0/src/Decimal.c

  • Committer: Package Import Robot
  • Author(s): Ondřej Surý
  • Date: 2017-04-18 17:16:30 UTC
  • Revision ID: package-import@ubuntu.com-20170418171630-fw8udixss0879s32
Tags: upstream-1.3.0
Import upstream version 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright 2015-2016 DataStax, Inc.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 * http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include "php_driver.h"
 
18
#include "php_driver_types.h"
 
19
#include "util/hash.h"
 
20
#include "util/math.h"
 
21
#include "util/types.h"
 
22
 
 
23
#include <gmp.h>
 
24
#include <float.h>
 
25
#include <math.h>
 
26
#include <ext/spl/spl_exceptions.h>
 
27
 
 
28
zend_class_entry *php_driver_decimal_ce = NULL;
 
29
 
 
30
static void
 
31
to_mpf(mpf_t result, php_driver_numeric *decimal)
 
32
{
 
33
  mpf_t scale_factor;
 
34
  long scale;
 
35
  /* result = unscaled * pow(10, -scale) */
 
36
  mpf_set_z(result, decimal->data.decimal.value);
 
37
 
 
38
  scale = decimal->data.decimal.scale;
 
39
  mpf_init_set_si(scale_factor, 10);
 
40
  mpf_pow_ui(scale_factor, scale_factor, scale < 0 ? -scale : scale);
 
41
 
 
42
  if (scale > 0) {
 
43
    mpf_ui_div(scale_factor, 1, scale_factor);
 
44
  }
 
45
 
 
46
  mpf_mul(result, result, scale_factor);
 
47
 
 
48
  mpf_clear(scale_factor);
 
49
}
 
50
 
 
51
/*
 
52
 * IEEE 754 double precision floating point representation:
 
53
 *
 
54
 *  S   EEEEEEEEEEE  MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
 
55
 * [63][  62 - 52  ][                    51 - 0                          ]
 
56
 *
 
57
 * S = sign bit
 
58
 * E = exponent
 
59
 * M = mantissa
 
60
 */
 
61
#define DOUBLE_MANTISSA_BITS 52
 
62
#define DOUBLE_MANTISSA_MASK (cass_int64_t) ((1LL << DOUBLE_MANTISSA_BITS) - 1)
 
63
#define DOUBLE_EXPONENT_BITS 11
 
64
#define DOUBLE_EXPONENT_MASK (cass_int64_t) ((1LL << DOUBLE_EXPONENT_BITS) - 1)
 
65
 
 
66
static void
 
67
from_double(php_driver_numeric *result, double value)
 
68
{
 
69
  int denormal;
 
70
  char mantissa_str[32];
 
71
  cass_int64_t raw, mantissa, exponent;
 
72
 
 
73
  // Copy the bits of value into an int64 so that we can do bit manipulations on it.
 
74
  memcpy(&raw, &value, 8);
 
75
 
 
76
  mantissa = raw & DOUBLE_MANTISSA_MASK;
 
77
  exponent = (raw >> DOUBLE_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK;
 
78
 
 
79
  /* This exponent is offset using 1023 unless it's a denormal value then its value
 
80
   * is the minimum value -1022
 
81
   */
 
82
  if (exponent == 0) {
 
83
    /* If the exponent is a zero then we have a denormal (subnormal) number. These are numbers
 
84
     * that represent small values around 0.0. The mantissa has the form of 0.xxxxxxxx...
 
85
     *
 
86
     * http://en.wikipedia.org/wiki/Denormal_number
 
87
     */
 
88
    denormal = 1;
 
89
    exponent = -1022;
 
90
  } else {
 
91
    /* Normal number The mantissa has the form of 1.xxxxxxx... */
 
92
    denormal = 0;
 
93
    exponent -= 1023;
 
94
  }
 
95
 
 
96
  /* Move the factional parts in the mantissa to the exponent. The significand
 
97
   * represents fractional parts:
 
98
   *
 
99
   * S = 1 + B51 * 2^-51 + B50 * 2^-52 ... + B0
 
100
   *
 
101
   */
 
102
  exponent -= DOUBLE_MANTISSA_BITS;
 
103
 
 
104
  if (!denormal) {
 
105
    /* Normal numbers have an implied one i.e. 1.xxxxxx... */
 
106
    mantissa |= (1LL << DOUBLE_MANTISSA_BITS);
 
107
  }
 
108
 
 
109
  /* Remove trailing zeros and move them to the exponent */
 
110
  while (exponent < 0 && (mantissa & 1) == 0) {
 
111
    ++exponent;
 
112
    mantissa >>= 1;
 
113
  }
 
114
 
 
115
  /* There isn't any "long long" setter method  */
 
116
#ifdef _WIN32
 
117
  sprintf(mantissa_str, "%I64d", mantissa);
 
118
#else
 
119
  sprintf(mantissa_str, "%lld", mantissa);
 
120
#endif
 
121
  mpz_set_str(result->data.decimal.value, mantissa_str, 10);
 
122
 
 
123
  /* Change the sign if negative */
 
124
  if (raw < 0) {
 
125
    mpz_neg(result->data.decimal.value, result->data.decimal.value);
 
126
  }
 
127
 
 
128
  if (exponent < 0) {
 
129
    /* Convert from pow(2, exponent) to pow(10, exponent):
 
130
     *
 
131
     * mantissa * pow(2, exponent) equals
 
132
     * mantissa * (pow(10, exponent) / pow(5, exponent))
 
133
     */
 
134
    mpz_t pow_5;
 
135
    mpz_init(pow_5);
 
136
    mpz_ui_pow_ui(pow_5, 5, -exponent);
 
137
    mpz_mul(result->data.decimal.value, result->data.decimal.value, pow_5);
 
138
    mpz_clear(pow_5);
 
139
    result->data.decimal.scale = -exponent;
 
140
  } else {
 
141
    mpz_mul_2exp(result->data.decimal.value, result->data.decimal.value, exponent);
 
142
    result->data.decimal.scale = 0;
 
143
  }
 
144
}
 
145
 
 
146
static int
 
147
to_double(zval* result, php_driver_numeric *decimal TSRMLS_DC)
 
148
{
 
149
  mpf_t value;
 
150
  mpf_init(value);
 
151
  to_mpf(value, decimal);
 
152
 
 
153
  if (mpf_cmp_d(value, -DBL_MAX) < 0) {
 
154
    zend_throw_exception_ex(php_driver_range_exception_ce, 0 TSRMLS_CC, "Value is too small");
 
155
    mpf_clear(value);
 
156
    return FAILURE;
 
157
  }
 
158
 
 
159
  if (mpf_cmp_d(value, DBL_MAX) > 0) {
 
160
    zend_throw_exception_ex(php_driver_range_exception_ce, 0 TSRMLS_CC, "Value is too big");
 
161
    mpf_clear(value);
 
162
    return FAILURE;
 
163
  }
 
164
 
 
165
  ZVAL_DOUBLE(result, mpf_get_d(value));
 
166
  mpf_clear(value);
 
167
  return SUCCESS;
 
168
}
 
169
 
 
170
static int
 
171
to_long(zval* result, php_driver_numeric *decimal TSRMLS_DC)
 
172
{
 
173
  mpf_t value;
 
174
  mpf_init(value);
 
175
  to_mpf(value, decimal);
 
176
 
 
177
  if (mpf_cmp_si(value, LONG_MIN) < 0) {
 
178
    zend_throw_exception_ex(php_driver_range_exception_ce, 0 TSRMLS_CC, "Value is too small");
 
179
    mpf_clear(value);
 
180
    return FAILURE;
 
181
  }
 
182
 
 
183
  if (mpf_cmp_si(value, LONG_MAX) > 0) {
 
184
    zend_throw_exception_ex(php_driver_range_exception_ce, 0 TSRMLS_CC, "Value is too big");
 
185
    mpf_clear(value);
 
186
    return FAILURE;
 
187
  }
 
188
 
 
189
  ZVAL_LONG(result, mpf_get_si(value));
 
190
  mpf_clear(value);
 
191
  return SUCCESS;
 
192
}
 
193
 
 
194
static int
 
195
to_string(zval* result, php_driver_numeric *decimal TSRMLS_DC)
 
196
{
 
197
  char* string;
 
198
  int string_len;
 
199
  php_driver_format_decimal(decimal->data.decimal.value, decimal->data.decimal.scale, &string, &string_len);
 
200
 
 
201
  PHP5TO7_ZVAL_STRINGL(result, string, string_len);
 
202
  efree(string);
 
203
 
 
204
  return SUCCESS;
 
205
}
 
206
 
 
207
static void
 
208
align_decimals(php_driver_numeric *lhs, php_driver_numeric *rhs)
 
209
{
 
210
  mpz_t pow_10;
 
211
  mpz_init(pow_10);
 
212
  if (lhs->data.decimal.scale < rhs->data.decimal.scale) {
 
213
    mpz_ui_pow_ui(pow_10, 10, rhs->data.decimal.scale - lhs->data.decimal.scale);
 
214
    mpz_mul(lhs->data.decimal.value, lhs->data.decimal.value, pow_10);
 
215
  } else if (lhs->data.decimal.scale > rhs->data.decimal.scale) {
 
216
    mpz_ui_pow_ui(pow_10, 10, lhs->data.decimal.scale - rhs->data.decimal.scale);
 
217
    mpz_mul(rhs->data.decimal.value, rhs->data.decimal.value, pow_10);
 
218
  }
 
219
  mpz_clear(pow_10);
 
220
}
 
221
 
 
222
void
 
223
php_driver_decimal_init(INTERNAL_FUNCTION_PARAMETERS)
 
224
{
 
225
  php_driver_numeric *self;
 
226
  zval* value;
 
227
 
 
228
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
 
229
    return;
 
230
  }
 
231
 
 
232
  if (getThis() && instanceof_function(Z_OBJCE_P(getThis()), php_driver_decimal_ce TSRMLS_CC)) {
 
233
    self = PHP_DRIVER_GET_NUMERIC(getThis());
 
234
  } else {
 
235
    object_init_ex(return_value, php_driver_decimal_ce);
 
236
    self = PHP_DRIVER_GET_NUMERIC(return_value);
 
237
  }
 
238
 
 
239
  if (Z_TYPE_P(value) == IS_LONG) {
 
240
    mpz_set_si(self->data.decimal.value, Z_LVAL_P(value));
 
241
    self->data.decimal.scale = 0;
 
242
  } else if (Z_TYPE_P(value) == IS_DOUBLE) {
 
243
    double val = Z_DVAL_P(value);
 
244
    if (zend_isnan(val) || zend_isinf(val)) {
 
245
      zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
 
246
                              "Value of NaN or +/- infinity is not supported");
 
247
      return;
 
248
    }
 
249
    from_double(self, val);
 
250
  } else if (Z_TYPE_P(value) == IS_STRING) {
 
251
    if (!php_driver_parse_decimal(Z_STRVAL_P(value), Z_STRLEN_P(value),
 
252
                                     &self->data.decimal.value, &self->data.decimal.scale TSRMLS_CC)) {
 
253
      return;
 
254
    }
 
255
  } else if (Z_TYPE_P(value) == IS_OBJECT &&
 
256
             instanceof_function(Z_OBJCE_P(value), php_driver_decimal_ce TSRMLS_CC)) {
 
257
    php_driver_numeric *decimal = PHP_DRIVER_GET_NUMERIC(value);
 
258
    mpz_set(self->data.decimal.value, decimal->data.decimal.value);
 
259
    self->data.decimal.scale = decimal->data.decimal.scale;
 
260
  } else {
 
261
    INVALID_ARGUMENT(value, "a long, a double, a numeric string or a " \
 
262
                            PHP_DRIVER_NAMESPACE "\\Decimal");
 
263
  }
 
264
}
 
265
 
 
266
/* {{{ Decimal::__construct(string) */
 
267
PHP_METHOD(Decimal, __construct)
 
268
{
 
269
  php_driver_decimal_init(INTERNAL_FUNCTION_PARAM_PASSTHRU);
 
270
}
 
271
/* }}} */
 
272
 
 
273
/* {{{ Decimal::__toString() */
 
274
PHP_METHOD(Decimal, __toString)
 
275
{
 
276
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
277
 
 
278
  to_string(return_value, self TSRMLS_CC);
 
279
}
 
280
/* }}} */
 
281
 
 
282
/* {{{ Decimal::type() */
 
283
PHP_METHOD(Decimal, type)
 
284
{
 
285
  php5to7_zval type = php_driver_type_scalar(CASS_VALUE_TYPE_DECIMAL TSRMLS_CC);
 
286
  RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(type), 1, 1);
 
287
}
 
288
/* }}} */
 
289
 
 
290
/* {{{ Decimal::value() */
 
291
PHP_METHOD(Decimal, value)
 
292
{
 
293
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
294
 
 
295
  char* string;
 
296
  int string_len;
 
297
  php_driver_format_integer(self->data.decimal.value, &string, &string_len);
 
298
 
 
299
  PHP5TO7_RETVAL_STRINGL(string, string_len);
 
300
  efree(string);
 
301
}
 
302
/* }}} */
 
303
 
 
304
PHP_METHOD(Decimal, scale)
 
305
{
 
306
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
307
 
 
308
  RETURN_LONG(self->data.decimal.scale);
 
309
}
 
310
 
 
311
/* {{{ Decimal::add() */
 
312
PHP_METHOD(Decimal, add)
 
313
{
 
314
  zval* num;
 
315
  php_driver_numeric *result = NULL;
 
316
 
 
317
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &num) == FAILURE) {
 
318
    return;
 
319
  }
 
320
 
 
321
  if (Z_TYPE_P(num) == IS_OBJECT &&
 
322
      instanceof_function(Z_OBJCE_P(num), php_driver_decimal_ce TSRMLS_CC)) {
 
323
    php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
324
    php_driver_numeric *decimal = PHP_DRIVER_GET_NUMERIC(num);
 
325
 
 
326
    object_init_ex(return_value, php_driver_decimal_ce);
 
327
    result = PHP_DRIVER_GET_NUMERIC(return_value);
 
328
 
 
329
    align_decimals(self, decimal);
 
330
    mpz_add(result->data.decimal.value, self->data.decimal.value, decimal->data.decimal.value);
 
331
    result->data.decimal.scale = MAX(self->data.decimal.scale, decimal->data.decimal.scale);
 
332
  } else {
 
333
    INVALID_ARGUMENT(num, "a " PHP_DRIVER_NAMESPACE "\\Decimal");
 
334
  }
 
335
}
 
336
/* }}} */
 
337
 
 
338
/* {{{ Decimal::sub() */
 
339
PHP_METHOD(Decimal, sub)
 
340
{
 
341
  zval* num;
 
342
  php_driver_numeric *result = NULL;
 
343
 
 
344
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &num) == FAILURE) {
 
345
    return;
 
346
  }
 
347
 
 
348
  if (Z_TYPE_P(num) == IS_OBJECT &&
 
349
      instanceof_function(Z_OBJCE_P(num), php_driver_decimal_ce TSRMLS_CC)) {
 
350
    php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
351
    php_driver_numeric *decimal = PHP_DRIVER_GET_NUMERIC(num);
 
352
 
 
353
    object_init_ex(return_value, php_driver_decimal_ce);
 
354
    result = PHP_DRIVER_GET_NUMERIC(return_value);
 
355
 
 
356
    align_decimals(self, decimal);
 
357
    mpz_sub(result->data.decimal.value, self->data.decimal.value, decimal->data.decimal.value);
 
358
    result->data.decimal.scale = MAX(self->data.decimal.scale, decimal->data.decimal.scale);
 
359
  } else {
 
360
    INVALID_ARGUMENT(num, "a " PHP_DRIVER_NAMESPACE "\\Decimal");
 
361
  }
 
362
}
 
363
/* }}} */
 
364
 
 
365
/* {{{ Decimal::mul() */
 
366
PHP_METHOD(Decimal, mul)
 
367
{
 
368
  zval* num;
 
369
  php_driver_numeric *result = NULL;
 
370
 
 
371
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &num) == FAILURE) {
 
372
    return;
 
373
  }
 
374
 
 
375
  if (Z_TYPE_P(num) == IS_OBJECT &&
 
376
      instanceof_function(Z_OBJCE_P(num), php_driver_decimal_ce TSRMLS_CC)) {
 
377
    php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
378
    php_driver_numeric *decimal = PHP_DRIVER_GET_NUMERIC(num);
 
379
 
 
380
    object_init_ex(return_value, php_driver_decimal_ce);
 
381
    result = PHP_DRIVER_GET_NUMERIC(return_value);
 
382
 
 
383
    mpz_mul(result->data.decimal.value, self->data.decimal.value, decimal->data.decimal.value);
 
384
    result->data.decimal.scale = self->data.decimal.scale + decimal->data.decimal.scale;
 
385
  } else {
 
386
    INVALID_ARGUMENT(num, "a " PHP_DRIVER_NAMESPACE "\\Decimal");
 
387
  }
 
388
}
 
389
/* }}} */
 
390
 
 
391
/* {{{ Decimal::div() */
 
392
PHP_METHOD(Decimal, div)
 
393
{
 
394
  /* TODO: Implementation of this a bit more difficult than anticipated. */
 
395
  zend_throw_exception_ex(php_driver_runtime_exception_ce, 0 TSRMLS_CC, "Not implemented");
 
396
}
 
397
/* }}} */
 
398
 
 
399
/* {{{ Decimal::mod() */
 
400
PHP_METHOD(Decimal, mod)
 
401
{
 
402
  /* TODO: We could implement a remainder method */
 
403
  zend_throw_exception_ex(php_driver_runtime_exception_ce, 0 TSRMLS_CC, "Not implemented");
 
404
}
 
405
 
 
406
/* {{{ Decimal::abs() */
 
407
PHP_METHOD(Decimal, abs)
 
408
{
 
409
  php_driver_numeric *result = NULL;
 
410
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
411
 
 
412
  object_init_ex(return_value, php_driver_decimal_ce);
 
413
  result = PHP_DRIVER_GET_NUMERIC(return_value);
 
414
 
 
415
  mpz_abs(result->data.decimal.value, self->data.decimal.value);
 
416
  result->data.decimal.scale = self->data.decimal.scale;
 
417
}
 
418
/* }}} */
 
419
 
 
420
/* {{{ Decimal::neg() */
 
421
PHP_METHOD(Decimal, neg)
 
422
{
 
423
  php_driver_numeric *result = NULL;
 
424
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
425
 
 
426
  object_init_ex(return_value, php_driver_decimal_ce);
 
427
  result = PHP_DRIVER_GET_NUMERIC(return_value);
 
428
 
 
429
  mpz_neg(result->data.decimal.value, self->data.decimal.value);
 
430
  result->data.decimal.scale = self->data.decimal.scale;
 
431
}
 
432
/* }}} */
 
433
 
 
434
/* {{{ Decimal::sqrt() */
 
435
PHP_METHOD(Decimal, sqrt)
 
436
{
 
437
  zend_throw_exception_ex(php_driver_runtime_exception_ce, 0 TSRMLS_CC, "Not implemented");
 
438
#if 0
 
439
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
440
 
 
441
  mpf_t value;
 
442
  mpf_init(value);
 
443
  to_mpf(value, self);
 
444
 
 
445
  mpf_sqrt(value, value);
 
446
 
 
447
  mp_exp_t exponent;
 
448
  char* mantissa = mpf_get_str(NULL, &exponent, 10, 0, value);
 
449
 
 
450
  object_init_ex(return_value, php_driver_decimal_ce);
 
451
  php_driver_numeric *result = PHP_DRIVER_GET_NUMERIC(return_value);
 
452
 
 
453
  mpz_set_str(result->value.decimal_value, mantissa, 10);
 
454
  mp_bitcnt_t prec = mpf_get_prec(value);
 
455
  exponent -= prec;
 
456
  result->value.decimal_scale = -exponent;
 
457
 
 
458
  free(mantissa);
 
459
  mpf_clear(value);
 
460
#endif
 
461
}
 
462
/* }}} */
 
463
 
 
464
/* {{{ Decimal::toInt() */
 
465
PHP_METHOD(Decimal, toInt)
 
466
{
 
467
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
468
 
 
469
  to_long(return_value, self TSRMLS_CC);
 
470
}
 
471
/* }}} */
 
472
 
 
473
/* {{{ Decimal::toDouble() */
 
474
PHP_METHOD(Decimal, toDouble)
 
475
{
 
476
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(getThis());
 
477
 
 
478
  to_double(return_value, self TSRMLS_CC);
 
479
}
 
480
/* }}} */
 
481
 
 
482
ZEND_BEGIN_ARG_INFO_EX(arginfo__construct, 0, ZEND_RETURN_VALUE, 1)
 
483
  ZEND_ARG_INFO(0, value)
 
484
ZEND_END_ARG_INFO()
 
485
 
 
486
ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, ZEND_RETURN_VALUE, 0)
 
487
ZEND_END_ARG_INFO()
 
488
 
 
489
ZEND_BEGIN_ARG_INFO_EX(arginfo_num, 0, ZEND_RETURN_VALUE, 1)
 
490
  ZEND_ARG_INFO(0, num)
 
491
ZEND_END_ARG_INFO()
 
492
 
 
493
static zend_function_entry php_driver_decimal_methods[] = {
 
494
  PHP_ME(Decimal, __construct, arginfo__construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
 
495
  PHP_ME(Decimal, __toString, arginfo_none, ZEND_ACC_PUBLIC)
 
496
  PHP_ME(Decimal, type, arginfo_none, ZEND_ACC_PUBLIC)
 
497
  PHP_ME(Decimal, value, arginfo_none, ZEND_ACC_PUBLIC)
 
498
  PHP_ME(Decimal, scale, arginfo_none, ZEND_ACC_PUBLIC)
 
499
  PHP_ME(Decimal, add, arginfo_num, ZEND_ACC_PUBLIC)
 
500
  PHP_ME(Decimal, sub, arginfo_num, ZEND_ACC_PUBLIC)
 
501
  PHP_ME(Decimal, mul, arginfo_num, ZEND_ACC_PUBLIC)
 
502
  PHP_ME(Decimal, div, arginfo_num, ZEND_ACC_PUBLIC)
 
503
  PHP_ME(Decimal, mod, arginfo_num, ZEND_ACC_PUBLIC)
 
504
  PHP_ME(Decimal, abs, arginfo_none, ZEND_ACC_PUBLIC)
 
505
  PHP_ME(Decimal, neg, arginfo_none, ZEND_ACC_PUBLIC)
 
506
  PHP_ME(Decimal, sqrt, arginfo_none, ZEND_ACC_PUBLIC)
 
507
  PHP_ME(Decimal, toInt, arginfo_none, ZEND_ACC_PUBLIC)
 
508
  PHP_ME(Decimal, toDouble, arginfo_none, ZEND_ACC_PUBLIC)
 
509
  PHP_FE_END
 
510
};
 
511
 
 
512
static php_driver_value_handlers php_driver_decimal_handlers;
 
513
 
 
514
static HashTable*
 
515
php_driver_decimal_gc(zval *object, php5to7_zval_gc table, int *n TSRMLS_DC)
 
516
{
 
517
  *table = NULL;
 
518
  *n = 0;
 
519
  return zend_std_get_properties(object TSRMLS_CC);
 
520
}
 
521
 
 
522
static HashTable*
 
523
php_driver_decimal_properties(zval *object TSRMLS_DC)
 
524
{
 
525
  char* string;
 
526
  int string_len;
 
527
  php5to7_zval type;
 
528
  php5to7_zval value;
 
529
  php5to7_zval scale;
 
530
 
 
531
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(object);
 
532
  HashTable         *props = zend_std_get_properties(object TSRMLS_CC);
 
533
 
 
534
  type = php_driver_type_scalar(CASS_VALUE_TYPE_DECIMAL TSRMLS_CC);
 
535
  PHP5TO7_ZEND_HASH_UPDATE(props, "type", sizeof("type"), PHP5TO7_ZVAL_MAYBE_P(type), sizeof(zval));
 
536
 
 
537
  php_driver_format_integer(self->data.decimal.value, &string, &string_len);
 
538
  PHP5TO7_ZVAL_MAYBE_MAKE(PHP5TO7_ZVAL_MAYBE_P(value));
 
539
  PHP5TO7_ZVAL_STRINGL(PHP5TO7_ZVAL_MAYBE_P(value), string, string_len);
 
540
  efree(string);
 
541
  PHP5TO7_ZEND_HASH_UPDATE(props, "value", sizeof("value"), PHP5TO7_ZVAL_MAYBE_P(value), sizeof(zval));
 
542
 
 
543
  PHP5TO7_ZVAL_MAYBE_MAKE(scale);
 
544
  ZVAL_LONG(PHP5TO7_ZVAL_MAYBE_P(scale), self->data.decimal.scale);
 
545
  PHP5TO7_ZEND_HASH_UPDATE(props, "scale", sizeof("scale"), PHP5TO7_ZVAL_MAYBE_P(scale), sizeof(zval));
 
546
 
 
547
  return props;
 
548
}
 
549
 
 
550
static int
 
551
php_driver_decimal_compare(zval *obj1, zval *obj2 TSRMLS_DC)
 
552
{
 
553
  php_driver_numeric *decimal1 = NULL;
 
554
  php_driver_numeric *decimal2 = NULL;
 
555
 
 
556
  if (Z_OBJCE_P(obj1) != Z_OBJCE_P(obj2))
 
557
    return 1; /* different classes */
 
558
 
 
559
  decimal1 = PHP_DRIVER_GET_NUMERIC(obj1);
 
560
  decimal2 = PHP_DRIVER_GET_NUMERIC(obj2);
 
561
 
 
562
  if (decimal1->data.decimal.scale == decimal2->data.decimal.scale) {
 
563
    return mpz_cmp(decimal1->data.decimal.value, decimal2->data.decimal.value);
 
564
  } else if (decimal1->data.decimal.scale < decimal2->data.decimal.scale) {
 
565
    return -1;
 
566
  } else {
 
567
    return 1;
 
568
  }
 
569
}
 
570
 
 
571
static unsigned
 
572
php_driver_decimal_hash_value(zval *obj TSRMLS_DC)
 
573
{
 
574
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(obj);
 
575
  return php_driver_mpz_hash((unsigned)self->data.decimal.scale, self->data.decimal.value);
 
576
}
 
577
 
 
578
static int
 
579
php_driver_decimal_cast(zval *object, zval *retval, int type TSRMLS_DC)
 
580
{
 
581
  php_driver_numeric *self = PHP_DRIVER_GET_NUMERIC(object);
 
582
 
 
583
  switch (type) {
 
584
  case IS_LONG:
 
585
      return to_long(retval, self TSRMLS_CC);
 
586
  case IS_DOUBLE:
 
587
      return to_double(retval, self TSRMLS_CC);
 
588
  case IS_STRING:
 
589
      return to_string(retval, self TSRMLS_CC);
 
590
  default:
 
591
     return FAILURE;
 
592
  }
 
593
 
 
594
  return SUCCESS;
 
595
}
 
596
 
 
597
static void
 
598
php_driver_decimal_free(php5to7_zend_object_free *object TSRMLS_DC)
 
599
{
 
600
  php_driver_numeric *self = PHP5TO7_ZEND_OBJECT_GET(numeric, object);
 
601
 
 
602
  mpz_clear(self->data.decimal.value);
 
603
 
 
604
  zend_object_std_dtor(&self->zval TSRMLS_CC);
 
605
  PHP5TO7_MAYBE_EFREE(self);
 
606
}
 
607
 
 
608
static php5to7_zend_object
 
609
php_driver_decimal_new(zend_class_entry *ce TSRMLS_DC)
 
610
{
 
611
  php_driver_numeric *self =
 
612
      PHP5TO7_ZEND_OBJECT_ECALLOC(numeric, ce);
 
613
 
 
614
  self->type = PHP_DRIVER_DECIMAL;
 
615
  self->data.decimal.scale = 0;
 
616
  mpz_init(self->data.decimal.value);
 
617
 
 
618
  PHP5TO7_ZEND_OBJECT_INIT_EX(numeric, decimal, self, ce);
 
619
}
 
620
 
 
621
void php_driver_define_Decimal(TSRMLS_D)
 
622
{
 
623
  zend_class_entry ce;
 
624
 
 
625
  INIT_CLASS_ENTRY(ce, PHP_DRIVER_NAMESPACE "\\Decimal", php_driver_decimal_methods);
 
626
  php_driver_decimal_ce = zend_register_internal_class(&ce TSRMLS_CC);
 
627
  zend_class_implements(php_driver_decimal_ce TSRMLS_CC, 2, php_driver_value_ce, php_driver_numeric_ce);
 
628
  php_driver_decimal_ce->ce_flags     |= PHP5TO7_ZEND_ACC_FINAL;
 
629
  php_driver_decimal_ce->create_object = php_driver_decimal_new;
 
630
 
 
631
  memcpy(&php_driver_decimal_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
 
632
  php_driver_decimal_handlers.std.get_properties  = php_driver_decimal_properties;
 
633
#if PHP_VERSION_ID >= 50400
 
634
  php_driver_decimal_handlers.std.get_gc          = php_driver_decimal_gc;
 
635
#endif
 
636
  php_driver_decimal_handlers.std.compare_objects = php_driver_decimal_compare;
 
637
  php_driver_decimal_handlers.std.cast_object     = php_driver_decimal_cast;
 
638
 
 
639
  php_driver_decimal_handlers.hash_value = php_driver_decimal_hash_value;
 
640
  php_driver_decimal_handlers.std.clone_obj = NULL;
 
641
}