diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | include/member.h | 251 | ||||
-rw-r--r-- | include/type.h | 2 | ||||
-rw-r--r-- | include/value.h | 154 | ||||
-rw-r--r-- | phpcpp.h | 4 | ||||
-rw-r--r-- | src/callable.cpp | 43 | ||||
-rw-r--r-- | src/value.cpp | 294 |
7 files changed, 407 insertions, 345 deletions
@@ -3,14 +3,14 @@ INCLUDE_DIR = ${PREFIX}/include LIBRARY_DIR = ${PREFIX}/lib all: - cd src; $(MAKE) + cd src; $(MAKE) -j tests: cd tests; $(MAKE) clean: cd src; $(MAKE) clean - cd tests; $(MAKE) clean +# cd tests; $(MAKE) clean install: mkdir -p ${INCLUDE_DIR}/phpcpp diff --git a/include/member.h b/include/member.h index 49ac246..d56b495 100644 --- a/include/member.h +++ b/include/member.h @@ -1,23 +1,23 @@ /** - * Member.h + * Member.h * - * When you're accessing members in an array or an object, you're - * doing so via an internal member object. This is an object that - * keeps track of the array to which it belonged, and that updates - * the class when the object is modified + * When you're accessing members in an array or an object, you're + * doing this via an internal member object. This is an object that + * keeps track of the array to which it belongs, and that will update + * the array when the member is modified * - * This is an abstract class. You are not supposed to instantiate it - * yourself. An instance of it is created when you call Value::operator[] + * You are not supposed to instantiate this class. An instance of it is + * created when you call Value::operator[] * - * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> - * @copyright 2013 Copernica BV + * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com> + * @copyright 2013 Copernica BV */ /** - * Set up namespace + * Set up namespace */ namespace PhpCpp { - + /** * Forward definitions */ @@ -26,52 +26,49 @@ class Value; /** * Member class */ -template <class Type> +template <typename Type> class Member { public: - /** - * Destructor - */ - virtual ~Member() {} + /** + * Destructor + */ + virtual ~Member() {} - /** - * Assign a value object to the array - * @param value - * @return Member - */ - Member &operator=(const Value &value) - { - // set property in parent array - _value->set(_index, value); - - // leap out if this is not a nested array access - //if (!_parent) return *this; - - // nested array access, we need to update the parent too - //_parent->operator=(*_value); - - // done - return *this; - } + /** + * Assign a value object to the array + * @param value + * @return Member + */ + Member &operator=(const Value &value) + { + // set property in parent array + _base.set(_index, value); - /** - * Retrieve the original value - * @return Value - */ - Value value() const - { - return _value->get(_index); - } + // if there is a parent, it should sets its value too + if (_parent) _parent->operator=(_base); + + // done + return *this; + } - /** - * Cast to a value object - * @return Value - */ - operator Value () const - { - return _value->get(_index); - } + /** + * Retrieve the original value + * @return Value + */ + Value value() const + { + return _base.get(_index); + } + + /** + * Cast to a value object + * @return Value + */ + operator Value () const + { + return _base.get(_index); + } /** * Cast to a long @@ -79,8 +76,8 @@ public: */ operator long () const { - return _value->get(_index).longValue(); - } + return _base.get(_index).longValue(); + } /** * Cast to a boolean @@ -88,8 +85,8 @@ public: */ operator bool () const { - return _value->get(_index).boolValue(); - } + return _base.get(_index).boolValue(); + } /** * Cast to a string @@ -97,8 +94,8 @@ public: */ operator std::string () const { - return _value->get(_index).stringValue(); - } + return _base.get(_index).stringValue(); + } /** * Cast to byte array @@ -106,8 +103,8 @@ public: */ operator const char * () const { - return _value->get(_index).rawValue(); - } + return _base.get(_index).rawValue(); + } /** * Cast to a floating point @@ -115,9 +112,9 @@ public: */ operator double () const { - return _value->get(_index).decimalValue(); - } - + return _base.get(_index).decimalValue(); + } + /** * Array access operator * This can be used for accessing arrays @@ -126,8 +123,8 @@ public: */ Member operator[](int index) { - return _value->get(_index)[index]; - } + return _base.get(_index)[index].add(this); + } /** * Array access operator @@ -137,76 +134,72 @@ public: */ Member operator[](const std::string &key) { - return _value->get(_index)[key]; - } + return _base.get(_index)[key].add(this); + } - /** - * Array access operator - * This can be used for accessing associative arrays - * @param key - * @return Member - */ - Member operator[](const char *key) - { - return _value->get(_index)[key]; - } + /** + * Array access operator + * This can be used for accessing associative arrays + * @param key + * @return Member + */ + Member operator[](const char *key) + { + return _base.get(_index)[key].add(this); + } private: - /** - * Constructor - * @param value Parent element - * @param index Index in the array - */ - Member(Value *value, Type index) : _value(value), _index(index) {} - - /** - * Private copy constructor - * @param value Other element - */ - Member(const Member<Type> &member) : _value(member._value), _index(member._index) {} - - /** - * Set the member - * @param member - */ - Member<Type> &add(Member *parent) - { - _parent = parent; - return *this; - } - - /** - * The array of which this is a member - * @var Value - */ - Value *_value; - - /** - * The original index - * @var Type - */ - Type _index; - - /** - * Parent member - * - * When accessing nested arrays a["a"]["b"] = 'true', the member - * object that represents the "b" entry holds a pointer to the member - * object that represents "a", so that it can tell its parent to - * store itself in the top array too - * - * @var Member - */ - Member *_parent = nullptr; - - /** - * Value objects may create members - */ - friend class Value; + /** + * Constructor + * @param base Base value + * @param index Index in the array + */ + Member(const Value *base, Type index) : _base(*base), _index(index) {} + + /** + * Protected copy constructor + * @param value Other element + */ + Member(const Member<Type> &member) : _base(member._base), _index(member._index), _parent(member._parent) {} + + /** + * Add parent + * @param parent + * @return Member + */ + Member &add(Member *parent) + { + _parent = parent; + return *this; + } + + /** + * The original index + * @var Type + */ + Type _index; + + /** + * Base value + * @var Value + */ + Value _base; + + /** + * Parent member (in case of nested members) + * @var Member + */ + Member *_parent = nullptr; + + /** + * Only value objects may construct members + */ + friend class Value; + }; - + /** - * End of namespace + * End of namespace */ } diff --git a/include/type.h b/include/type.h index f3e357f..200d658 100644 --- a/include/type.h +++ b/include/type.h @@ -19,7 +19,7 @@ namespace PhpCpp { */ typedef enum _Type { nullType = 0, - intType = 1, + longType = 1, decimalType = 2, boolType = 3, arrayType = 4, diff --git a/include/value.h b/include/value.h index 6619dcb..2cc9029 100644 --- a/include/value.h +++ b/include/value.h @@ -63,6 +63,12 @@ public: Value(bool value); /** + * Constructor based on single character + * @param value + */ + Value(char value); + + /** * Constructor based on string value * @param value */ @@ -95,6 +101,12 @@ public: Value(const Value &that); /** + * Move constructor + * @param value + */ + Value(Value &&that); + + /** * Destructor */ virtual ~Value(); @@ -132,6 +144,13 @@ public: * @param value * @return Value */ + Value &operator=(char value); + + /** + * Assignment operator + * @param value + * @return Value + */ Value &operator=(const std::string &value); /** @@ -158,49 +177,83 @@ public: * Change the internal type of the variable * @param Type */ - void setType(Type type); + Value &setType(Type type); + + /** + * Make a clone of the value with the same type + * @return Value + */ + Value clone() const; + + /** + * Make a clone of the value with a different type + * @param type + * @return Value + */ + Value clone(Type type) const; /** * Is this a NULL value? * @return bool */ - bool isNull() const; + bool isNull() const + { + return type() == nullType; + } /** * Is this an integer value? * @return bool */ - bool isLong() const; + bool isLong() const + { + return type() == longType; + } /** * Is this a boolean value? * @return bool */ - bool isBool() const; + bool isBool() const + { + return type() == boolType; + } /** * Is this a string value? * @return bool */ - bool isString() const; + bool isString() const + { + return type() == stringType; + } /** * Is this a decimal value? * @return bool */ - bool isDecimal() const; + bool isDecimal() const + { + return type() == decimalType; + } /** * Is this an object value? * @return bool */ - bool isObject() const; + bool isObject() const + { + return type() == objectType; + } /** * Is this an array value? * @return bool */ - bool isArray() const; + bool isArray() const + { + return type() == arrayType; + } /** * Retrieve the value as integer @@ -217,7 +270,7 @@ public: /** * Retrieve the raw string value * Warning: Only use this for NULL terminated strings, or use it in combination - * with the string size to prevent that you access data outside the buffer + * with the string size to prevent that you access data outside the buffer * @return const char * */ const char *rawValue() const; @@ -270,12 +323,15 @@ public: * @param key * @return bool */ - bool contains(const std::string &key) const; + bool contains(const std::string &key) const + { + return contains(key.c_str(), key.size()); + } /** * Is a certain key set in the array * @param key - * @param size + * @param size * @return bool */ bool contains(const char *key, int size) const; @@ -313,8 +369,8 @@ public: */ operator const char * () const { - return rawValue(); - } + return rawValue(); + } /** * Cast to a floating point @@ -327,63 +383,71 @@ public: /** * Get access to a certain array member - * @param index + * @param index * @return Value */ Value get(int index) const; /** * Get access to a certain assoc member - * @param key - * @param size - * @return Value + * @param key + * @param size + * @return Value */ Value get(const char *key, int size=-1) const; /** * Get access to a certain assoc member - * @param key - * @return Value + * @param key + * @return Value */ Value get(const std::string &key) const { - return get(key.c_str(), key.size()); - } + return get(key.c_str(), key.size()); + } /** * Set a certain property - * @param index - * @param value + * Calling this method will turn the value into an array + * @param index Index of the property to set + * @param value Value to set + * @return Value The value that was set */ - void set(int index, const Value &value); + const Value &set(int index, const Value &value); /** * Set a certain property - * @param key - * @param value + * Calling this method will turn the value into an array + * @param key Key of the property to set + * @param size Size of the key + * @param value Value to set + * @return Value The value that was set */ - void set(const char *key, int size, const Value &value); + const Value &set(const char *key, int size, const Value &value); /** * Set a certain property - * @param key - * @param size - * @param value + * Calling this method will turn the object into an array + * @param key Key to set + * @param value Value to set + * @return Value The value that was set */ - void set(const char *key, const Value &value) + const Value &set(const char *key, const Value &value) { - set(key, strlen(key), value); - } + return set(key, strlen(key), value); + } /** * Set a certain property - * @param key - * @param value + * Calling this method will turn the object into an array + * @param key Key to set + * @param value Value to set + * @return Value The value that was set */ - void set(const std::string &key, const Value &value) + const Value &set(const std::string &key, const Value &value) { - set(key.c_str(), key.size(), value); - } + return set(key.c_str(), key.size(), value); + } /** * Array access operator @@ -401,13 +465,13 @@ public: */ Member<std::string> operator[](const std::string &key); - /** - * Array access operator - * This can be used for accessing associative arrays - * @param key - * @return Member - */ - Member<std::string> operator[](const char *key); + /** + * Array access operator + * This can be used for accessing associative arrays + * @param key + * @return Member + */ + Member<std::string> operator[](const char *key); protected: @@ -31,9 +31,9 @@ * Macro to export a function */ #if defined(__GNUC__) && __GNUC__ >= 4 -# define PHPCPP_EXPORT __attribute__ ((visibility("default"))) +# define PHPCPP_EXPORT __attribute__ ((visibility("default"))) #else -# define PHPCPP_EXPORT +# define PHPCPP_EXPORT #endif /** diff --git a/src/callable.cpp b/src/callable.cpp index 7cba919..b9f67d0 100644 --- a/src/callable.cpp +++ b/src/callable.cpp @@ -136,43 +136,32 @@ int Callable::invoke(INTERNAL_FUNCTION_PARAMETERS) // number of arguments on the stack int arg_count = (int)(zend_uintptr_t) *(zend_vm_stack_top(TSRMLS_C) - 1); - // loop through the arguments - Arguments args(ZEND_NUM_ARGS()); - - for (auto iter = args.begin(); iter != args.end(); iter++) - { - Value val = *iter; - - val = 1234; - - std::cout << "argument: " << iter->stringValue() << std::endl; - } - - int result = do_test(args[1], args[2]); - +// // loop through the arguments +// Arguments args(ZEND_NUM_ARGS()); +// +// for (auto iter = args.begin(); iter != args.end(); iter++) +// { +// Value val = *iter; +// +// val = 1234; +// } +// +// int result = do_test(args[1], args[2]); +// Value ret(return_value, true); std::cout << "set property 1" << std::endl; - ret["a"] = 1; - - std::cout << "set property 2" << std::endl; - - ret["2"] = 3; - -// ret["hmm"]["s"] = 456; - - Value sub; - sub["something"] = "yes"; - - ret["b"] = sub; +// ret["b"] = "hallo"; + ret["x"]["c"]["d"] = "test 123"; + std::cout << "done setting properties" << std::endl; // // // done -// return SUCCESS; + return SUCCESS; } diff --git a/src/value.cpp b/src/value.cpp index a4dcb25..9224162 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -75,6 +75,17 @@ Value::Value(bool value) } /** + * Constructor based on single character + * @param value + */ +Value::Value(char value) +{ + // create a string zval + MAKE_STD_ZVAL(_val); + ZVAL_STRINGL(_val, &value, 1, 1); +} + +/** * Constructor based on string value * @param value */ @@ -134,11 +145,28 @@ Value::Value(struct _zval_struct *zval, bool ref) */ Value::Value(const Value &that) { - // just copy the zval, and the refcounter + // just copy the zval _val = that._val; - // and we have one more reference + // and we have one more reference Z_ADDREF_P(_val); + + // two value objects are both sharing the same zval, we turn the zval into a reference + // @todo this is not necessarily correct + Z_SET_ISREF_P(_val); +} + +/** + * Move constructor + * @param value + */ +Value::Value(Value &&that) +{ + // just copy the zval + _val = that._val; + + // clear the other object + that._val = nullptr; } /** @@ -146,6 +174,14 @@ Value::Value(const Value &that) */ Value::~Value() { + // ignore if moved + if (!_val) return; + + // if there were two references or less, we're going to remove a reference + // and only one reference will remain, the object will then impossible be + // a reference + if (Z_REFCOUNT_P(_val) <= 2) Z_UNSET_ISREF_P(_val); + // destruct the zval (this function will decrement the reference counter, // and only destruct if there are no other references left) zval_ptr_dtor(&_val); @@ -240,6 +276,26 @@ Value &Value::operator=(bool value) * @param value * @return Value */ +Value &Value::operator=(char value) +{ + // if this is not a reference variable, we should detach it to implement copy on write + SEPARATE_ZVAL_IF_NOT_REF(&_val); + + // deallocate current zval (without cleaning the zval structure) + zval_dtor(_val); + + // set new value + ZVAL_STRINGL(_val, &value, 1, 1); + + // done + return *this; +} + +/** + * Assignment operator + * @param value + * @return Value + */ Value &Value::operator=(const std::string &value) { // if this is not a reference variable, we should detach it to implement copy on write @@ -307,11 +363,12 @@ Type Value::type() const /** * Change the internal type * @param type + * @return Value */ -void Value::setType(Type type) +Value &Value::setType(Type type) { // skip if nothing changes - if (this->type() == type) return; + if (this->type() == type) return *this; // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); @@ -319,76 +376,52 @@ void Value::setType(Type type) // run the conversion switch (type) { case nullType: convert_to_null(_val); break; - case intType: convert_to_long(_val); break; + case longType: convert_to_long(_val); break; case decimalType: convert_to_double(_val); break; case boolType: convert_to_boolean(_val); break; case arrayType: convert_to_array(_val); break; case objectType: convert_to_object(_val); break; case stringType: convert_to_string(_val); break; } + + // done + return *this; } /** - * Is this a NULL value? - * @return bool - */ -bool Value::isNull() const -{ - return Z_TYPE_P(_val) == IS_NULL; -} - -/** - * Is this a long value? - * @return bool - */ -bool Value::isLong() const -{ - return Z_TYPE_P(_val) == IS_LONG; -} - -/** - * Is this a boolean value? - * @return bool - */ -bool Value::isBool() const -{ - return Z_TYPE_P(_val) == IS_BOOL; -} - -/** - * Is this a string value? - * @return bool + * Make a clone of the type + * @return Value */ -bool Value::isString() const +Value Value::clone() const { - return Z_TYPE_P(_val) == IS_STRING; + // the zval that will hold the copy + zval *copy; + + // allocate memory + ALLOC_ZVAL(copy); + + // copy the data + INIT_PZVAL_COPY(copy, _val); + + // run the copy constructor to ensure that everything gets copied + zval_copy_ctor(copy); + + // done + return Value(copy); } /** - * Is this a decimal value? - * @return bool + * Clone the zval to a different type + * @param type + * @return Value */ -bool Value::isDecimal() const +Value Value::clone(Type type) const { - return Z_TYPE_P(_val) == IS_DOUBLE; -} + // regular clone if nothing changes + if (this->type() == type) return clone(); -/** - * Is this an object value? - * @return bool - */ -bool Value::isObject() const -{ - return Z_TYPE_P(_val) == IS_OBJECT; -} - -/** - * Is this an array value? - * @return bool - */ -bool Value::isArray() const -{ - return Z_TYPE_P(_val) == IS_ARRAY; + // make a clone + return clone().setType(type); } /** @@ -400,14 +433,8 @@ long Value::longValue() const // already a long? if (isLong()) return Z_LVAL_P(_val); - // make a copy - Value copy(*this); - - // convert the copy to an int - copy.setType(intType); - - // return the long value - return copy.longValue(); + // make a clone + return clone(longType).longValue(); } /** @@ -419,14 +446,8 @@ bool Value::boolValue() const // already a bool? if (isBool()) return Z_BVAL_P(_val); - // make a copy - Value copy(*this); - - // convert the copy to an int - copy.setType(boolType); - - // return the bool value - return copy.boolValue(); + // make a clone + return clone(boolType).boolValue(); } /** @@ -438,14 +459,8 @@ std::string Value::stringValue() const // already a string? if (isString()) return std::string(Z_STRVAL_P(_val), Z_STRLEN_P(_val)); - // make a copy - Value copy(*this); - - // convert the copy to an string - copy.setType(stringType); - - // return the string value - return copy.stringValue(); + // make a clone + return clone(stringType).stringValue(); } /** @@ -457,14 +472,8 @@ const char *Value::rawValue() const // already a string? if (isString()) return Z_STRVAL_P(_val); - // make a copy - Value copy(*this); - - // convert the copy to an string - copy.setType(stringType); - - // return the string value - return copy.rawValue(); + // make a clone + return clone(stringType).rawValue(); } /** @@ -476,14 +485,8 @@ double Value::decimalValue() const // already a double if (isDecimal()) return Z_DVAL_P(_val); - // make a copy - Value copy(*this); - - // convert the copy to an double - copy.setType(decimalType); - - // return the decimal value - return copy.decimalValue(); + // make a clone + return clone(decimalType).decimalValue(); } /** @@ -528,23 +531,6 @@ bool Value::contains(int index) const /** * Does the array contain a certain key * @param key - * @return bool - */ -bool Value::contains(const std::string &key) const -{ - // must be an array - if (!isArray()) return false; - - // unused variable - zval **result; - - // check if index is already in the array - return zend_hash_find(Z_ARRVAL_P(_val), key.c_str(), key.size() + 1, (void **)&result) != FAILURE; -} - -/** - * Does the array contain a certain key - * @param key * @param size * @return boolean */ @@ -565,14 +551,14 @@ bool Value::contains(const char *key, int size) const /** * Get access to a certain array member - * @param index + * @param index * @return Value */ Value Value::get(int index) const { - // must be an array - if (!isArray()) return Value(); - + // must be an array + if (!isArray()) return Value(); + // zval to retrieve zval **result; @@ -585,12 +571,15 @@ Value Value::get(int index) const /** * Get access to a certain assoc member - * @param key - * @param size - * @return Value + * @param key + * @param size + * @return Value */ Value Value::get(const char *key, int size) const { + // must be an array + if (!isArray()) return Value(); + // calculate size if (size < 0) size = strlen(key); @@ -606,46 +595,73 @@ Value Value::get(const char *key, int size) const /** * Set a certain property - * @param index - * @param value + * @param index + * @param value + * @return Value */ -void Value::set(int index, const Value &value) +const Value &Value::set(int index, const Value &value) { + // the current value + zval **current; + + // check if this index is already in the array, otherwise we return NULL + if (isArray() && zend_hash_index_find(Z_ARRVAL_P(_val), index, (void **)¤t) != FAILURE) + { + // skip if nothing is going to change + if (value._val == *current) return value; + } + // must be an array setType(arrayType); // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); - // add the value + // add the value (this will decrement refcount on any current variable) add_index_zval(_val, index, value._val); // the variable has one more reference (the array entry) Z_ADDREF_P(value._val); + + // done + return value; } /** * Set a certain property - * @param key - * @param size - * @param value + * @param key + * @param size + * @param value + * @return Value */ -void Value::set(const char *key, int size, const Value &value) +const Value &Value::set(const char *key, int size, const Value &value) { + // the current value + zval **current; + + // check if this index is already in the array, otherwise we return NULL + if (isArray() && zend_hash_find(Z_ARRVAL_P(_val), key, size + 1, (void **)¤t) != FAILURE) + { + // skip if nothing is going to change + if (value._val == *current) return value; + } + // must be an array setType(arrayType); - + // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); - - // add the value + + // add the value (this will reduce the refcount of the current value) add_assoc_zval_ex(_val, key, size+1, value._val); // the variable has one more reference (the array entry) Z_ADDREF_P(value._val); + + // done + return value; } - /** * Array access operator * This can be used for accessing arrays @@ -654,29 +670,29 @@ void Value::set(const char *key, int size, const Value &value) */ Member<int> Value::operator[](int index) { - return Member<int>(this, index); + return Member<int>(this, index); } /** - * Array access operator + * Array access operato * This can be used for accessing associative arrays * @param key * @return Member */ Member<std::string> Value::operator[](const std::string &key) { - return Member<std::string>(this, key); + return Member<std::string>(this, key); } /** * Array access operator * This can be used for accessing associative arrays - * @param key - * @return Member + * @param key + * @return Member */ Member<std::string> Value::operator[](const char *key) { - return Member<std::string>(this, key); + return Member<std::string>(this, key); } /** |