From 5d978bb6e5504afc77d67b5079db5e7f8cd5a82d Mon Sep 17 00:00:00 2001 From: Michael Mulligan Date: Sun, 1 Nov 2015 15:19:06 -0500 Subject: [PATCH] CaseInsensitiveArray rewrite for performance. Storeing the Case-Insensitive/Sensitive Keys separately increases performance. Also, fix for unset and valid, as well as the ability to initialize with a pre-existing Array. --- src/Curl/CaseInsensitiveArray.php | 271 ++++++++++++++++++++++++------ 1 file changed, 221 insertions(+), 50 deletions(-) diff --git a/src/Curl/CaseInsensitiveArray.php b/src/Curl/CaseInsensitiveArray.php index 6aa6147..c42dc86 100644 --- a/src/Curl/CaseInsensitiveArray.php +++ b/src/Curl/CaseInsensitiveArray.php @@ -2,72 +2,243 @@ namespace Curl; -class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator -{ - private $container = array(); +class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator { - public function offsetSet($offset, $value) - { - if ($offset === null) { - $this->container[] = $value; - } else { - $index = array_search(strtolower($offset), array_keys(array_change_key_case($this->container, CASE_LOWER))); - if (!($index === false)) { - $keys = array_keys($this->container); - unset($this->container[$keys[$index]]); + /** + * @var mixed[] Data storage with lower-case keys + * @see offsetSet() + * @see offsetExists() + * @see offsetUnset() + * @see offsetGet() + * @see count() + * @see current() + * @see next() + * @see key() + */ + private $data = array(); + + /** + * @var string[] Case-Sensitive keys. + * @see offsetSet() + * @see offsetUnset() + * @see key() + */ + private $keys = array(); + + /** + * Construct + * + * Allow creating either an empty Array, or convert an existing Array to a + * Case-Insensitive Array. (Caution: Data may be lost when converting Case- + * Sensitive Arrays to Case-Insensitive Arrays) + * + * @param mixed[] $initial (optional) Existing Array to convert. + * + * @return void + * + * @access public + * + * @author Michael Mulligan + */ + public function __construct(Array $initial = NULL) { + if($initial !== NULL) { + foreach($initial as $key => $value) { + $this->offsetSet($key, $value); } - $this->container[$offset] = $value; } } - public function offsetExists($offset) - { - return array_key_exists(strtolower($offset), array_change_key_case($this->container, CASE_LOWER)); - } - - public function offsetUnset($offset) - { - unset($this->container[$offset]); - } - - public function offsetGet($offset) - { - $index = array_search(strtolower($offset), array_keys(array_change_key_case($this->container, CASE_LOWER))); - if ($index === false) { - return null; + /** + * Offset Set + * + * Set data at a specified Offset. Converts the offset to lower-case, and + * stores the Case-Sensitive Offset and the Data at the lower-case indexes + * in $this->keys and @this->data. + * + * @see https://secure.php.net/manual/en/arrayaccess.offseteset.php + * + * @param string $offset The offset to store the data at (case-insensitive). + * @param mixed $value The data to store at the specified offset. + * + * @return void + * + * @access public + * + * @author Michael Mulligan + */ + public function offsetSet($offset, $value) { + if ($offset === null) { + $this->data[] = $value; + } else { + $offsetlower = strtolower($offset); + $this->data[$offsetlower] = $value; + $this->keys[$offsetlower] = $offset; } - - $values = array_values($this->container); - return $values[$index]; } - public function count() - { - return count($this->container); + /** + * Offset Exists + * + * Checks if the Offset exists in data storage. The index is looked up with + * the lower-case version of the provided offset. + * + * @see https://secure.php.net/manual/en/arrayaccess.offsetexists.php + * + * @param string $offset Offset to check + * + * @return bool If the offset exists. + * + * @access public + * + * @author Michael Mulligan + */ + public function offsetExists($offset) { + return (bool) array_key_exists(strtolower($offset), $this->data); } - public function current() - { - return current($this->container); + /** + * Offset Unset + * + * Unsets the specified offset. Converts the provided offset to lowercase, + * and unsets the Case-Sensitive Key, as well as the stored data. + * + * @see https://secure.php.net/manual/en/arrayaccess.offsetunset.php + * + * @param string $offset The offset to unset. + * + * @return void + * + * @access public + * + * @author Michael Mulligan + */ + public function offsetUnset($offset) { + $offsetlower = strtolower($offset); + unset($this->data[$offsetlower]); + unset($this->keys[$offsetlower]); } - public function next() - { - return next($this->container); + /** + * Offset Get + * + * Return the stored data at the provided offset. The offset is converted to + * lowercase and the lookup is done on the Data store directly. + * + * @see https://secure.php.net/manual/en/arrayaccess.offsetget.php + * + * @param string $offset Offset to lookup. + * + * @return mixed The data stored at the offset. + * + * @access public + * + * @author Michael Mulligan + */ + public function offsetGet($offset) { + $offsetlower = strtolower($offset); + return array_key_exists($offsetlower, $this->data) ? $this->data[$offsetlower] : NULL; } - public function key() - { - return key($this->container); + /** + * Count + * + * @see https://secure.php.net/manual/en/countable.count.php + * + * @param void + * + * @return int The number of elements stored in the Array. + * + * @access public + * + * @author Michael Mulligan + */ + public function count() { + return (int) count($this->data); } - public function valid() - { - return !($this->current() === false); + /** + * Current + * + * @see https://secure.php.net/manual/en/iterator.current.php + * + * @param void + * + * @return mixed Data at the current position. + * + * @access public + * + * @author Michael Mulligan + */ + public function current() { + return current($this->data); } - public function rewind() - { - reset($this->container); + /** + * Next + * + * @see https://secure.php.net/manual/en/iterator.next.php + * + * @param void + * + * @return void + * + * @access public + * + * @author Michael Mulligan + */ + public function next() { + next($this->data); } -} + + /** + * Key + * + * @see https://secure.php.net/manual/en/iterator.key.php + * + * @param void + * + * @return mixed Case-Sensitive key at current position. + * + * @access public + * + * @author Michael Mulligan + */ + public function key() { + $key = key($this->data); + return isset($this->keys[$key]) ? $this->keys[$key] : $key; + } + + /** + * Valid + * + * @see https://secure.php.net/manual/en/iterator.valid.php + * + * @param void + * + * @return bool If the current position is valid. + * + * @access public + * + * @author Michael Mulligan + */ + public function valid() { + return (bool) !(key($this->data) === NULL); + } + + /** + * Rewind + * + * @see https://secure.php.net/manual/en/iterator.rewind.php + * + * @param void + * + * @return void + * + * @access public + * + * @author Michael Mulligan + */ + public function rewind() { + reset($this->data); + } +} \ No newline at end of file