summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documentation/bubblesort.html46
-rw-r--r--include/hashmember.h11
-rw-r--r--include/value.h151
-rw-r--r--phpcpp.h1
-rw-r--r--src/value.cpp107
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;
}
?&gt;
</code></pre>
@@ -80,11 +83,14 @@ Php::Value native_bubblesort(Php::Parameters &params)
if (input[j-1] &lt;= 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>
+&lt;?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");
+
+?&gt;
+</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
diff --git a/phpcpp.h b/phpcpp.h
index 428e0da..74e65fd 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -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 **)&current) != 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 **)&current) != FAILURE)
+ if (isArray() && zend_hash_index_find(Z_ARRVAL_P(_val), index, (void **)&current) != 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 **)&current) != 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