From 081d7a133fc2c2ec20beae366cedf474bb5d5910 Mon Sep 17 00:00:00 2001 From: Alex Palaistras Date: Sun, 18 Oct 2015 01:13:28 +0100 Subject: [PATCH] Return values as copies when converting Previously, value conversions were made on the original value, and thus, calling methods like `Value.Int` had the side-effect of changing the value's type for subsequent calls to `Value.Interface`. Any conversion required happens on value copies, which are automatically destroyed after use. --- value/value.c | 64 ++++++++++++++++++++++++++++++++++---------------- value/value.go | 2 -- value/value.h | 10 ++++++++ 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/value/value.c b/value/value.c index d070baf..c5e7dcf 100644 --- a/value/value.c +++ b/value/value.c @@ -93,43 +93,67 @@ void value_object_add_property(engine_value *obj, const char *key, engine_value } int value_get_long(engine_value *val) { - // Covert value to long if needed. - if (Z_TYPE_P(val->value) != IS_LONG) { - convert_to_long(val->value); - val->kind = Z_TYPE_P(val->value); + // Return value directly if already in correct type. + if (val->kind == IS_LONG) { + return Z_LVAL_P(val->value); } - return Z_LVAL_P(val->value); + zval *tmp = value_copy(val->value); + + convert_to_long(tmp); + long v = Z_LVAL_P(tmp); + + zval_dtor(tmp); + + return v; } double value_get_double(engine_value *val) { - // Covert value to double if needed. - if (Z_TYPE_P(val->value) != IS_DOUBLE) { - convert_to_double(val->value); - val->kind = Z_TYPE_P(val->value); + // Return value directly if already in correct type. + if (val->kind == IS_DOUBLE) { + return Z_DVAL_P(val->value); } - return Z_DVAL_P(val->value); + zval *tmp = value_copy(val->value); + + convert_to_double(tmp); + double v = Z_DVAL_P(tmp); + + zval_dtor(tmp); + + return v; } bool value_get_bool(engine_value *val) { - // Covert value to long if needed. - if (Z_TYPE_P(val->value) != IS_BOOL) { - convert_to_boolean(val->value); - val->kind = Z_TYPE_P(val->value); + // Return value directly if already in correct type. + if (val->kind == IS_BOOL) { + return Z_BVAL_P(val->value); } - return Z_BVAL_P(val->value); + zval *tmp = value_copy(val->value); + + convert_to_boolean(tmp); + bool v = Z_BVAL_P(tmp); + + zval_dtor(tmp); + + return v; } char *value_get_string(engine_value *val) { - // Covert value to string if needed. - if (Z_TYPE_P(val->value) != IS_STRING) { - convert_to_cstring(val->value); - val->kind = Z_TYPE_P(val->value); + // Return value directly if already in correct type. + if (val->kind == IS_STRING) { + return Z_STRVAL_P(val->value); } - return Z_STRVAL_P(val->value); + zval *tmp = value_copy(val->value); + + convert_to_cstring(tmp); + char *v = Z_STRVAL_P(tmp); + + zval_dtor(tmp); + + return v; } void value_destroy(engine_value *val) { diff --git a/value/value.go b/value/value.go index 890cfcb..dcd9c9e 100644 --- a/value/value.go +++ b/value/value.go @@ -55,8 +55,6 @@ func (v *Value) Interface() interface{} { return v.Float() case Bool: return v.Bool() - // case Array: - // return v.Map() case String: return v.String() } diff --git a/value/value.h b/value/value.h index fa8b1fc..3585c41 100644 --- a/value/value.h +++ b/value/value.h @@ -10,6 +10,16 @@ typedef struct _engine_value { int kind; } engine_value; +static inline zval *value_copy(zval *zv) { + zval *tmp; + + ALLOC_ZVAL(tmp); + INIT_PZVAL_COPY(tmp, zv); + zval_copy_ctor(tmp); + + return tmp; +} + engine_value *value_new(zval *zv); int value_kind(engine_value *val); void value_destroy(engine_value *val);