diff options
-rw-r--r-- | documentation/bubblesort.html | 46 | ||||
-rw-r--r-- | include/hashmember.h | 11 | ||||
-rw-r--r-- | include/value.h | 151 | ||||
-rw-r--r-- | phpcpp.h | 1 | ||||
-rw-r--r-- | src/value.cpp | 107 |
5 files changed, 275 insertions, 41 deletions
diff --git a/documentation/bubblesort.html b/documentation/bubblesort.html index b621d19..c0433be 100644 --- a/documentation/bubblesort.html +++ b/documentation/bubblesort.html @@ -1,4 +1,4 @@ -<h1>How fast is a C++ extension</h1> +<h1>How fast is a C++ extension?</h1> <p> Native extensions are fast. But how fast are they? We can demonstrate this with a very simple extension: bubblesort. @@ -42,6 +42,9 @@ function scripted_bubblesort(array $input) $input[$j-1] = $temp; } } + + // done + return $input; } ?> </code></pre> @@ -80,11 +83,14 @@ Php::Value native_bubblesort(Php::Parameters ¶ms) if (input[j-1] <= input[j]) continue; // swap elements - temp = input[j]; + int temp = input[j]; input[j] = input[j-1]; input[j-1] = temp; } } + + // done + return input; } /** @@ -109,7 +115,7 @@ extern "C" { // extension that the function receives one parameter by value, and // that that parameter must be an array extension.add("native_bubblesort", native_bubblesort, { - ByVal("input", Php::Type::Array) + Php::ByVal("input", Php::Type::Array) }); // return the extension @@ -125,8 +131,34 @@ extern "C" { is simple, and you can easily port your PHP functions to C++. </p> <p> - You also see an additional get_module() function in the extension call. This - is the startup function that is called by the Zend engine when PHP starts up. - It is supposed to return information to the Zend engine about the extension, - so that the "native_bubblesort" function is accessible for PHP scripts. + You also see an additional get_module() function in the source code. This + is the <a href="loading-extensions">startup function</a> that is called by the + Zend engine when PHP starts up. It is supposed to return information to the + Zend engine about the extension, so that the "native_bubblesort" function is + accessible for PHP scripts. +</p> +<p> + Let's run the two functions with an array filled with random numbers. </p> +<p> +<pre class="language-php"><code> +<?php + +// fill an array with random numbers +$count = 10000; +$x = array(); +for ($i=0; $i<$count; $i++) $x[] = rand(0, 1000000); + +// run the native and scripted bubblesort functions +$start = microtime(true); +$y = native_bubblesort($x); +$native = microtime(true); +$x = scripted_bubblesort($x); +$scripted = microtime(true); + +// show the results +echo("Native: ".($native - $start)." seconds\n"); +echo("Scripted: ".($scriped - $native)." seconds\n"); + +?> +</code></pre> diff --git a/include/hashmember.h b/include/hashmember.h index 9933445..65ca23d 100644 --- a/include/hashmember.h +++ b/include/hashmember.h @@ -317,6 +317,17 @@ public: Value operator%(double value) { return this->value() % value; } /** + * Comparison operators + * @param value + */ + template <typename T> bool operator==(const T &value) const { return (T)*this == value; } + template <typename T> bool operator!=(const T &value) const { return (T)*this != value; } + template <typename T> bool operator<=(const T &value) const { return (T)*this <= value; } + template <typename T> bool operator>=(const T &value) const { return (T)*this >= value; } + template <typename T> bool operator< (const T &value) const { return (T)*this < value; } + template <typename T> bool operator> (const T &value) const { return (T)*this > value; } + + /** * Handle calls to the hash member * @param param0 * @param param1 diff --git a/include/value.h b/include/value.h index 7615997..5800c6a 100644 --- a/include/value.h +++ b/include/value.h @@ -58,6 +58,34 @@ public: Value(const std::string &value); Value(const char *value, int size = -1); Value(double value); + + /** + * Construct to a specific type + * @param value + */ + Value(Type type) : Value() { setType(type); } + + /** + * Constructors from a vector (this will create an array) + * @param value + */ + template <typename T> + Value(const std::vector<T> &input) : Value(Type::Array) + { + // set all elements + for (size_t i=0; i<input.size(); i++) setRaw(i, input[i]); + } + + /** + * Constructor from a map (this will create an associative array) + * @param value + */ + template <typename T> + Value(const std::map<std::string,T> &value) + { + // set all elements + for (auto &iter : value) setRaw(iter.first.c_str(), iter.first.size(), iter.second); + } /** * Wrap object around zval @@ -111,7 +139,7 @@ public: Value &operator=(const std::string &value); Value &operator=(const char *value); Value &operator=(double value); - + /** * Add a value to the object * @param value @@ -267,11 +295,11 @@ public: * @param value */ template <typename T> bool operator==(const T &value) const { return (T)*this == value; } - template <typename T> bool operator!=(const T &value) const { return (T)*this == value; } - template <typename T> bool operator<=(const T &value) const { return (T)*this == value; } - template <typename T> bool operator>=(const T &value) const { return (T)*this == value; } - template <typename T> bool operator< (const T &value) const { return (T)*this == value; } - template <typename T> bool operator> (const T &value) const { return (T)*this == value; } + template <typename T> bool operator!=(const T &value) const { return (T)*this != value; } + template <typename T> bool operator<=(const T &value) const { return (T)*this <= value; } + template <typename T> bool operator>=(const T &value) const { return (T)*this >= value; } + template <typename T> bool operator< (const T &value) const { return (T)*this < value; } + template <typename T> bool operator> (const T &value) const { return (T)*this > value; } /** * The type of object @@ -344,6 +372,64 @@ public: double floatValue() const; /** + * Convert the object to a vector + * + * This only works for regular arrays that are indexed by a number, start + * with position 0 and have no empty spaces. + * + * @return std::vector + */ + template <typename T> + std::vector<T> vectorValue() const + { + // only works for arrays, other types return an empty vector + if (!isArray()) return std::vector<T>(); + + // allocate a result + std::vector<T> result; + + // reserve enough space + size_t count = size(); + result.reserve(count); + + // and fill the result vector + for (size_t i = 0; i<count; i++) + { + // check if the index exists, then add it + if (contains(i)) result.push_back((T)get(i)); + } + + // done + return result; + } + + /** + * Convert the object to a map with string index and Php::Value value + * @return std::map + */ + std::map<std::string,Php::Value> mapValue() const; + + /** + * Convert the object to a map with string index and a specific type as value + * @return std::map + */ + template <typename T> + std::map<std::string,T> mapValue() const + { + // must be an array or an object, otherwise the map is empty + if (!isArray() && !isObject()) return std::map<std::string,T>(); + + // get the original map value + std::map<std::string,Php::Value> map(mapValue()); + + // result variable + std::map<std::string,T> result; + + // done + return result; + } + + /** * The number of members in case of an array or object * @return int */ @@ -454,6 +540,35 @@ public: { return floatValue(); } + + /** + * Convert the object to a vector + * @return std::vector + */ + template <typename T> + operator std::vector<T>() const + { + return vectorValue<T>(); + } + + /** + * Convert the object to a map with string index and Php::Value value + * @return std::map + */ + operator std::map<std::string,Php::Value> () const + { + return mapValue(); + } + + /** + * Convert the object to a map with string index and Php::Value value + * @return std::map + */ + template <typename T> + operator std::map<std::string,T> () const + { + return mapValue<T>(); + } /** * Get access to a certain array member @@ -672,12 +787,26 @@ protected: struct _zval_struct *_val; /** - * Validate the value - * This is a overridable function that is implemented in base classes to - * ensure that a value of certain type stays valid - * @return Value + * Set a certain property without running any checks (you must already know + * for sure that this is an array, and that the index is not yet in use) + * + * @param index Index of the property to set + * @param value Value to set + * @return Value The value that was set + */ + const Value &setRaw(int index, const Value &value); + + /** + * Set a certain property without any checks (you must already know for + * sure that this is either an object or an array, and that the index is + * not yet in use) + * + * @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 */ - virtual Value &validate() { return *this; } + const Value &setRaw(const char *key, int size, const Value &value); /** * The Globals and Member classes can access the zval directly @@ -20,6 +20,7 @@ #include <memory> #include <list> #include <exception> +#include <map> /** * Include all headers files that are related to this library diff --git a/src/value.cpp b/src/value.cpp index 53d8c0a..75a67d4 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1405,6 +1405,40 @@ int Value::size() const } /** + * Convert the object to a map with string index and Php::Value value + * @return std::map + */ +std::map<std::string,Php::Value> Value::mapValue() const +{ + // check type + if (isArray()) + { + // result variable + std::map<std::string,Php::Value> result; + + // @todo loop through the zval key/value pairs, and return a map + + // done + return result; + } + else if (isObject()) + { + // result variable + std::map<std::string,Php::Value> result; + + // @todo convert the properties to a map + + // done + return result; + } + else + { + // return an empty map + return std::map<std::string,Php::Value>(); + } +} + +/** * Does the array contain a certain index? * @param index * @return bool @@ -1519,26 +1553,14 @@ Value Value::get(const char *key, int size) const } /** - * Set a certain property + * Set a certain property without performing any checks + * This method can be used when it is already known that the object is an array * @param index * @param value * @return Value */ -const Value &Value::set(int index, const Value &value) +const Value &Value::setRaw(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(Type::Array); - // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); @@ -1552,25 +1574,41 @@ const Value &Value::set(int index, const Value &value) return value; } + /** * Set a certain property - * @param key - * @param size + * @param index * @param value * @return Value */ -const Value &Value::set(const char *key, int size, 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_find(Z_ARRVAL_P(_val), key, size + 1, (void **)¤t) != FAILURE) + 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(Type::Array); + + // set property + return setRaw(index, value); +} + +/** + * Set a certain property without running any checks + * @param key + * @param size + * @param value + * @return Value + */ +const Value &Value::setRaw(const char *key, int size, const Value &value) +{ // is this an object? if (isObject()) { @@ -1585,9 +1623,6 @@ const Value &Value::set(const char *key, int size, const Value &value) } else { - // must be an array - setType(Type::Array); - // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); @@ -1603,6 +1638,32 @@ const Value &Value::set(const char *key, int size, const Value &value) } /** + * Set a certain property + * @param key + * @param size + * @param value + * @return 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; + } + + // this should be an object or an array + if (!isObject()) setType(Type::Array); + + // done + return setRaw(key, size, value); +} + +/** * Array access operator * This can be used for accessing arrays * @param index |