From 3bcd6e21d1142b5ec35f99c4bdcd925bf7ae5083 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sat, 15 Mar 2014 18:31:42 +0100 Subject: added empty() function, and added HardCoded class --- include/call.h | 10 +++++-- include/hashmember.h | 20 +++++++++++++ include/init.h | 23 +++++++-------- include/value.h | 57 +++++++++++++++++++++++++----------- phpcpp.h | 1 + src/arithmetic.h | 13 ++++++++- src/classbase.cpp | 6 ++-- src/includes.h | 1 + src/value.cpp | 81 ++++++++++++++++++++++++++++++++++++---------------- 9 files changed, 152 insertions(+), 60 deletions(-) diff --git a/include/call.h b/include/call.h index bae0a0a..7cf68bb 100644 --- a/include/call.h +++ b/include/call.h @@ -44,8 +44,14 @@ Value call(const char *name, Params&&... params) * make the code run on the highway), it is not expected that these functions * are going to be used very often anyway. */ -inline Value array_keys(const Value &value) { return call("array_keys", value); } -inline Value array_values(const Value &value) { return call("array_values", value); } +inline Value array_keys(const Value &value) { return call("array_keys", value); } +inline Value array_values(const Value &value) { return call("array_values", value); } +inline Value empty(const Value &value) { return call("empty", value); } +inline Value empty(const HashMember &member) { return !member.exists() || empty(member.value()); } +inline Value empty(const HashMember &member) { return !member.exists() || empty(member.value()); } +//inline Value isset(const Value &value) { return call("isset", value); } +//inline Value isset(const HashMember &member) { return member.exists() && isset(member.value()); } +//inline Value isset(const HashMember &member) { return member.exists() && isset(member.value()); } /** * End of namespace diff --git a/include/hashmember.h b/include/hashmember.h index 41c40d3..d61e5c9 100644 --- a/include/hashmember.h +++ b/include/hashmember.h @@ -52,6 +52,16 @@ public: return *this; } + /** + * Is this an existing hash member (true) or only one that is ready + * to be assigned a new value to, but that is not yet in the hashtable + * @return bool + */ + bool exists() const + { + return _base->contains(_index); + } + /** * Retrieve the original value * @return Value @@ -179,6 +189,7 @@ public: HashMember &operator+=(char value) { return operator=(this->value() + value); } HashMember &operator+=(const std::string &value) { return operator=(this->value() + value); } HashMember &operator+=(const char *value) { return operator=(this->value() + value); } + HashMember &operator+=(const HardCoded &value) { return operator=(this->value() + value); } HashMember &operator+=(double value) { return operator=(this->value() + value); } /** @@ -194,6 +205,7 @@ public: HashMember &operator-=(char value) { return operator=(this->value() - value); } HashMember &operator-=(const std::string &value) { return operator=(this->value() - value); } HashMember &operator-=(const char *value) { return operator=(this->value() - value); } + HashMember &operator-=(const HardCoded &value) { return operator=(this->value() - value); } HashMember &operator-=(double value) { return operator=(this->value() - value); } /** @@ -209,6 +221,7 @@ public: HashMember &operator*=(char value) { return operator=(this->value() * value); } HashMember &operator*=(const std::string &value) { return operator=(this->value() * value); } HashMember &operator*=(const char *value) { return operator=(this->value() * value); } + HashMember &operator*=(const HardCoded &value) { return operator=(this->value() * value); } HashMember &operator*=(double value) { return operator=(this->value() * value); } /** @@ -224,6 +237,7 @@ public: HashMember &operator/=(char value) { return operator=(this->value() / value); } HashMember &operator/=(const std::string &value) { return operator=(this->value() / value); } HashMember &operator/=(const char *value) { return operator=(this->value() / value); } + HashMember &operator/=(const HardCoded &value) { return operator=(this->value() / value); } HashMember &operator/=(double value) { return operator=(this->value() / value); } /** @@ -239,6 +253,7 @@ public: HashMember &operator%=(char value) { return operator=(this->value() % value); } HashMember &operator%=(const std::string &value) { return operator=(this->value() % value); } HashMember &operator%=(const char *value) { return operator=(this->value() % value); } + HashMember &operator%=(const HardCoded &value) { return operator=(this->value() % value); } HashMember &operator%=(double value) { return operator=(this->value() % value); } /** @@ -254,6 +269,7 @@ public: Value operator+(char value) { return this->value() + value; } Value operator+(const std::string &value) { return this->value() + value; } Value operator+(const char *value) { return this->value() + value; } + Value operator+(const HardCoded &value) { return this->value() + value; } Value operator+(double value) { return this->value() + value; } /** @@ -269,6 +285,7 @@ public: Value operator-(char value) { return this->value() - value; } Value operator-(const std::string &value) { return this->value() - value; } Value operator-(const char *value) { return this->value() - value; } + Value operator-(const HardCoded &value) { return this->value() - value; } Value operator-(double value) { return this->value() - value; } /** @@ -284,6 +301,7 @@ public: Value operator*(char value) { return this->value() * value; } Value operator*(const std::string &value) { return this->value() * value; } Value operator*(const char *value) { return this->value() * value; } + Value operator*(const HardCoded &value) { return this->value() * value; } Value operator*(double value) { return this->value() * value; } /** @@ -299,6 +317,7 @@ public: Value operator/(char value) { return this->value() / value; } Value operator/(const std::string &value) { return this->value() / value; } Value operator/(const char *value) { return this->value() / value; } + Value operator/(const HardCoded &value) { return this->value() / value; } Value operator/(double value) { return this->value() / value; } /** @@ -314,6 +333,7 @@ public: Value operator%(char value) { return this->value() % value; } Value operator%(const std::string &value) { return this->value() % value; } Value operator%(const char *value) { return this->value() % value; } + Value operator%(const HardCoded &value) { return this->value() % value; } Value operator%(double value) { return this->value() % value; } /** diff --git a/include/init.h b/include/init.h index ca6ff65..8f914f5 100644 --- a/include/init.h +++ b/include/init.h @@ -14,26 +14,23 @@ namespace Php { /** - * The way how PHP C API deals with "global" variables is stupid. + * The way how PHP C API deals with "global" variables is peculiar. * - * This is supposed to turn into a structure that is going to be - * instantiated for each parallel running request, and for which the - * PHP engine allocates a certain amount of memory, and a magic - * pointer that is passed and should be forwarded to every thinkable - * PHP function. + * The following macros are supposed to turn into a structure that is going + * to be instantiated for each parallel running request, and for which the + * PHP engine allocates a certain amount of memory, and a magic pointer that + * is passed and should be forwarded to every thinkable PHP function. * - * We don't like this architecture. We have our own environment object - * that makes much more sense, and that we use. However, we need - * to assign this object somewhere, so that's what we do in this - * one and only global variable + * We don't use this architecture. We have our own environment object + * that makes much more sense, and that we use. However, the Zend engine + * expects this structure and this structure to exist. */ ZEND_BEGIN_MODULE_GLOBALS(phpcpp) ZEND_END_MODULE_GLOBALS(phpcpp) /** - * And now we're going to define a macro. This also is a ridiculous - * architecture from PHP to get access to a variable from the - * structure above. + * And now we're going to define a macro. This also is a uncommon architecture + * from PHP to get access to a variable from the structure above. */ #ifdef ZTS #define PHPCPP_G(v) TSRMG(phpcpp_globals_id, phpcpp_globals *, v) diff --git a/include/value.h b/include/value.h index fce8750..13cea38 100644 --- a/include/value.h +++ b/include/value.h @@ -57,6 +57,7 @@ public: Value(char value); Value(const std::string &value); Value(const char *value, int size = -1); + Value(const HardCoded &value); Value(double value); /** @@ -161,6 +162,7 @@ public: Value &operator=(char value); Value &operator=(const std::string &value); Value &operator=(const char *value); + Value &operator=(const HardCoded &value); Value &operator=(double value); /** @@ -176,6 +178,7 @@ public: Value &operator+=(char value); Value &operator+=(const std::string &value); Value &operator+=(const char *value); + Value &operator+=(const HardCoded &value); Value &operator+=(double value); /** @@ -191,6 +194,7 @@ public: Value &operator-=(char value); Value &operator-=(const std::string &value); Value &operator-=(const char *value); + Value &operator-=(const HardCoded &value); Value &operator-=(double value); /** @@ -206,6 +210,7 @@ public: Value &operator*=(char value); Value &operator*=(const std::string &value); Value &operator*=(const char *value); + Value &operator*=(const HardCoded &value); Value &operator*=(double value); /** @@ -221,6 +226,7 @@ public: Value &operator/=(char value); Value &operator/=(const std::string &value); Value &operator/=(const char *value); + Value &operator/=(const HardCoded &value); Value &operator/=(double value); /** @@ -236,6 +242,7 @@ public: Value &operator%=(char value); Value &operator%=(const std::string &value); Value &operator%=(const char *value); + Value &operator%=(const HardCoded &value); Value &operator%=(double value); /** @@ -251,6 +258,7 @@ public: Value operator+(char value); Value operator+(const std::string &value); Value operator+(const char *value); + Value operator+(const HardCoded &value); Value operator+(double value); /** @@ -266,6 +274,7 @@ public: Value operator-(char value); Value operator-(const std::string &value); Value operator-(const char *value); + Value operator-(const HardCoded &value); Value operator-(double value); /** @@ -281,6 +290,7 @@ public: Value operator*(char value); Value operator*(const std::string &value); Value operator*(const char *value); + Value operator*(const HardCoded &value); Value operator*(double value); /** @@ -296,6 +306,7 @@ public: Value operator/(char value); Value operator/(const std::string &value); Value operator/(const char *value); + Value operator/(const HardCoded &value); Value operator/(double value); /** @@ -311,18 +322,19 @@ public: Value operator%(char value); Value operator%(const std::string &value); Value operator%(const char *value); + Value operator%(const HardCoded &value); Value operator%(double value); /** * Comparison operators for hardcoded strings * @param value */ - bool operator==(const char *value) const { return stringValue() == value; } - bool operator!=(const char *value) const { return stringValue() != value; } - bool operator<=(const char *value) const { return stringValue() <= value; } - bool operator>=(const char *value) const { return stringValue() >= value; } - bool operator< (const char *value) const { return stringValue() < value; } - bool operator> (const char *value) const { return stringValue() > value; } + bool operator==(const char *value) const { return ::strcmp(rawValue(), value) == 0; } + bool operator!=(const char *value) const { return ::strcmp(rawValue(), value) != 0; } + bool operator<=(const char *value) const { return ::strcmp(rawValue(), value) <= 0; } + bool operator>=(const char *value) const { return ::strcmp(rawValue(), value) >= 0; } + bool operator< (const char *value) const { return ::strcmp(rawValue(), value) < 0; } + bool operator> (const char *value) const { return ::strcmp(rawValue(), value) > 0; } /** * Comparison operators @@ -372,12 +384,20 @@ public: bool isObject() const { return type() == Type::Object; } bool isArray() const { return type() == Type::Array; } bool isCallable() const; + + /** + * Get access to the raw buffer - you can use this for direct reading and + * writing to and from the buffer. Note that this only works for string + * variables - other variables return nullptr + * @return char * + */ + char *buffer() const; /** - * Is the variable empty? - * @return bool + * Get access to the raw buffer for read operationrs. + * @return const char * */ - bool isEmpty() const; + const char *rawValue() const; /** * Retrieve the value as number @@ -397,14 +417,6 @@ public: */ bool boolValue() const; - /** - * 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 - * @return const char * - */ - const char *rawValue() const; - /** * Retrieve the value as a string * @return string @@ -529,6 +541,17 @@ public: * @return bool */ bool contains(const char *key, int size) const; + + /** + * Is a certain key set in the array + * @param key + * @param size + * @return bool + */ + bool contains(const char *key) const + { + return contains(key, strlen(key)); + } /** * Cast to a number diff --git a/phpcpp.h b/phpcpp.h index f58eb8d..83ac804 100644 --- a/phpcpp.h +++ b/phpcpp.h @@ -27,6 +27,7 @@ */ #include #include +#include #include #include #include diff --git a/src/arithmetic.h b/src/arithmetic.h index 21343d1..00d5641 100644 --- a/src/arithmetic.h +++ b/src/arithmetic.h @@ -127,7 +127,7 @@ public: // convert string to integer return apply(atoi(value.c_str())); } - + /** * Apply a string (representing a number), and return a new value object after running the arithmetic function * @param value @@ -138,6 +138,17 @@ public: // convert string to integer return apply(atoi(value)); } + + /** + * Apply a string (representing a number), and return a new value object after running the arithmetic function + * @param value + * @return Value + */ + Value apply(const HardCoded &value) + { + // convert string to integer + return apply(atoi(value.buffer())); + } /** * Apply a string (representing a number), and return a new value object after running the arithmetic function diff --git a/src/classbase.cpp b/src/classbase.cpp index 0de62dd..fbc6ed2 100644 --- a/src/classbase.cpp +++ b/src/classbase.cpp @@ -739,9 +739,9 @@ int ClassBase::hasDimension(zval *object, zval *member, int check_empty) // we know for certain that the offset exists, but should we check // more, like whether the value is empty or not? if (!check_empty) return true; - - // it should not be empty - return !arrayaccess->offsetGet(member).isEmpty(); + + // the user wants to know if the property is empty + return empty(arrayaccess->offsetGet(member)); } catch (Exception &exception) { diff --git a/src/includes.h b/src/includes.h index 0c00df3..55aa103 100644 --- a/src/includes.h +++ b/src/includes.h @@ -46,6 +46,7 @@ */ #include "../include/exception.h" #include "../include/type.h" +#include "../include/hardcoded.h" #include "../include/value.h" #include "../include/array.h" #include "../include/object.h" diff --git a/src/value.cpp b/src/value.cpp index 9af2d14..7ce49fe 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -129,6 +129,17 @@ Value::Value(const char *value, int size) ZVAL_STRINGL(_val, value, size < 0 ? strlen(value) : size, 1); } +/** + * Contructor based on hardcoded string that does not have to be copied + * @param value + */ +Value::Value(const HardCoded &value) +{ + // create a string zval + MAKE_STD_ZVAL(_val); + ZVAL_STRINGL(_val, value.buffer(), value.size(), 0); +} + /** * Constructor based on decimal value * @param value @@ -663,6 +674,26 @@ Value &Value::operator=(const char *value) return *this; } +/** + * Assignment operator + * @param value + * @return Value + */ +Value &Value::operator=(const HardCoded &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 non-duplicated value + ZVAL_STRINGL(_val, value.buffer(), value.size(), 0); + + // update the object + return *this; +} + /** * Assignment operator * @param value @@ -696,6 +727,7 @@ Value &Value::operator+=(bool value) { return Arithmetic(this).assign(value); } Value &Value::operator+=(const std::string &value) { return Arithmetic(this).assign(value); } Value &Value::operator+=(const char *value) { return Arithmetic(this).assign(value); } +Value &Value::operator+=(const HardCoded &value) { return Arithmetic(this).assign(value); } Value &Value::operator+=(double value) { return Arithmetic(this).assign(value); } /** @@ -711,6 +743,7 @@ Value &Value::operator-=(bool value) { return Arithmetic(this).assign(value); } Value &Value::operator-=(const std::string &value) { return Arithmetic(this).assign(value); } Value &Value::operator-=(const char *value) { return Arithmetic(this).assign(value); } +Value &Value::operator-=(const HardCoded &value) { return Arithmetic(this).assign(value); } Value &Value::operator-=(double value) { return Arithmetic(this).assign(value); } /** @@ -726,6 +759,7 @@ Value &Value::operator*=(bool value) { return Arithmetic(this).assign(value); } Value &Value::operator*=(const std::string &value) { return Arithmetic(this).assign(value); } Value &Value::operator*=(const char *value) { return Arithmetic(this).assign(value); } +Value &Value::operator*=(const HardCoded &value) { return Arithmetic(this).assign(value); } Value &Value::operator*=(double value) { return Arithmetic(this).assign(value); } /** @@ -741,6 +775,7 @@ Value &Value::operator/=(bool value) { return Arithmetic(this).assign(value); } Value &Value::operator/=(const std::string &value) { return Arithmetic(this).assign(value); } Value &Value::operator/=(const char *value) { return Arithmetic(this).assign(value); } +Value &Value::operator/=(const HardCoded &value) { return Arithmetic(this).assign(value); } Value &Value::operator/=(double value) { return Arithmetic(this).assign(value); } /** @@ -757,6 +792,7 @@ Value &Value::operator%=(bool value) { return operator=(numericVa Value &Value::operator%=(char value) { return operator=(numericValue() % value); } Value &Value::operator%=(const std::string &value) { return operator=(numericValue() % atoi(value.c_str())); } Value &Value::operator%=(const char *value) { return operator=(numericValue() % atoi(value)); } +Value &Value::operator%=(const HardCoded &value) { return operator=(numericValue() % atoi(value.buffer())); } Value &Value::operator%=(double value) { return operator=(numericValue() % (int)value); } /** @@ -772,6 +808,7 @@ Value Value::operator+(bool value) { return Arithmetic(this).apply(value); } Value Value::operator+(const std::string &value) { return Arithmetic(this).apply(value); } Value Value::operator+(const char *value) { return Arithmetic(this).apply(value); } +Value Value::operator+(const HardCoded &value) { return Arithmetic(this).apply(value); } Value Value::operator+(double value) { return Arithmetic(this).apply(value); } /** @@ -787,6 +824,7 @@ Value Value::operator-(bool value) { return Arithmetic(this).apply(value); } Value Value::operator-(const std::string &value) { return Arithmetic(this).apply(value); } Value Value::operator-(const char *value) { return Arithmetic(this).apply(value); } +Value Value::operator-(const HardCoded &value) { return Arithmetic(this).apply(value); } Value Value::operator-(double value) { return Arithmetic(this).apply(value); } /** @@ -802,6 +840,7 @@ Value Value::operator*(bool value) { return Arithmetic(this).apply(value); } Value Value::operator*(const std::string &value) { return Arithmetic(this).apply(value); } Value Value::operator*(const char *value) { return Arithmetic(this).apply(value); } +Value Value::operator*(const HardCoded &value) { return Arithmetic(this).apply(value); } Value Value::operator*(double value) { return Arithmetic(this).apply(value); } /** @@ -817,6 +856,7 @@ Value Value::operator/(bool value) { return Arithmetic(this).apply(value); } Value Value::operator/(const std::string &value) { return Arithmetic(this).apply(value); } Value Value::operator/(const char *value) { return Arithmetic(this).apply(value); } +Value Value::operator/(const HardCoded &value) { return Arithmetic(this).apply(value); } Value Value::operator/(double value) { return Arithmetic(this).apply(value); } /** @@ -832,6 +872,7 @@ Value Value::operator%(bool value) { return Value(numericValue( Value Value::operator%(char value) { return Value(numericValue() % value); } Value Value::operator%(const std::string &value) { return Value(numericValue() % atoi(value.c_str())); } Value Value::operator%(const char *value) { return Value(numericValue() % atoi(value)); } +Value Value::operator%(const HardCoded &value) { return Value(numericValue() % atoi(value.buffer())); } Value Value::operator%(double value) { return Value(numericValue() % (int)value); } /** @@ -1354,27 +1395,6 @@ bool Value::isCallable() const return zend_is_callable(_val, 0, NULL); } -/** - * Is the variable empty? - * @return bool - */ -bool Value::isEmpty() const -{ - switch (type()) { - case Type::Null: return true; - case Type::Numeric: return numericValue() == 0; - case Type::Float: return floatValue() == 0.0; - case Type::Bool: return boolValue() == false; - case Type::Array: return size() == 0; - case Type::Object: return false; - case Type::String: return size() == 0; - case Type::Callable: return false; - default: return false; - } - - // for the time being we consider resources and consts to be not-empty -} - /** * Make a clone of the type * @return Value @@ -1451,15 +1471,28 @@ std::string Value::stringValue() const } /** - * Retrieve raw string value + * Access to the raw buffer + * @return char * + */ +char *Value::buffer() const +{ + // must be a string + if (!isString()) return nullptr; + + // already a string? + return Z_STRVAL_P(_val); +} + +/** + * Access to the raw buffer * @return const char * */ const char *Value::rawValue() const { - // already a string? + // must be a string if (isString()) return Z_STRVAL_P(_val); - // make a clone + // make a clone and return that buffer return clone(Type::String).rawValue(); } -- cgit v1.2.3