summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjavalizard <>2011-06-25 04:56:12 +0000
committerjavalizard <>2011-06-25 04:56:12 +0000
commit87e7366d4d9d3de79772b851f8772a4011d6227d (patch)
tree804e43ee4ec0f7177459f0ffb7ea654f7bfff00b
parent15f6747485b5912f657c2c0fce8f41c01c70d2ad (diff)
Added two methods for getting array elements out of TPriorityList above and below a specific priority, with inclusion. Added TPriorityMap and test cases.
-rw-r--r--.gitattributes2
-rw-r--r--framework/Collections/TPriorityList.php323
-rw-r--r--framework/Collections/TPriorityMap.php606
-rw-r--r--tests/unit/Collections/TPriorityListTest.php71
-rw-r--r--tests/unit/Collections/TPriorityMapTest.php490
5 files changed, 1307 insertions, 185 deletions
diff --git a/.gitattributes b/.gitattributes
index 37006a6b..f76c026f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2370,6 +2370,7 @@ framework/Collections/TMap.php -text
framework/Collections/TPagedDataSource.php -text
framework/Collections/TPagedList.php -text
framework/Collections/TPriorityList.php -text
+framework/Collections/TPriorityMap.php -text
framework/Collections/TQueue.php -text
framework/Collections/TStack.php -text
framework/Data/ActiveRecord/Exceptions/TActiveRecordException.php -text
@@ -3761,6 +3762,7 @@ tests/unit/Collections/TMapTest.php -text
tests/unit/Collections/TPagedDataSourceTest.php -text
tests/unit/Collections/TPagedListTest.php -text
tests/unit/Collections/TPriorityListTest.php -text
+tests/unit/Collections/TPriorityMapTest.php -text
tests/unit/Collections/TQueueTest.php -text
tests/unit/Collections/TStackTest.php -text
tests/unit/Data/DataGateway/AllTests.php -text
diff --git a/framework/Collections/TPriorityList.php b/framework/Collections/TPriorityList.php
index d6fc807c..e952099c 100644
--- a/framework/Collections/TPriorityList.php
+++ b/framework/Collections/TPriorityList.php
@@ -119,9 +119,9 @@ class TPriorityList extends TList
*/
public function getPriorityCount($priority=null)
{
- if($priority === null)
- $priority = $this->getDefaultPriority();
- $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
return false;
@@ -142,7 +142,7 @@ class TPriorityList extends TList
*/
protected function setDefaultPriority($value)
{
- $this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
+ $this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
}
/**
@@ -169,7 +169,7 @@ class TPriorityList extends TList
*/
public function getIterator()
{
- return new ArrayIterator( $this->flattenPriorities() );
+ return new ArrayIterator($this->flattenPriorities());
}
/**
@@ -188,8 +188,8 @@ class TPriorityList extends TList
*/
protected function sortPriorities() {
if(!$this->_o) {
- ksort($this->_d, SORT_NUMERIC);
- $this->_o = true;
+ ksort($this->_d,SORT_NUMERIC);
+ $this->_o=true;
}
}
@@ -202,9 +202,9 @@ class TPriorityList extends TList
return $this->_fd;
$this->sortPriorities();
- $this->_fd = array();
+ $this->_fd=array();
foreach($this->_d as $priority => $itemsatpriority)
- $this->_fd = array_merge($this->_fd, $itemsatpriority);
+ $this->_fd=array_merge($this->_fd,$itemsatpriority);
return $this->_fd;
}
@@ -218,8 +218,8 @@ class TPriorityList extends TList
*/
public function itemAt($index)
{
- if($index>=0 && $index<$this->getCount()) {
- $arr = $this->flattenPriorities();
+ if($index>=0&&$index<$this->getCount()) {
+ $arr=$this->flattenPriorities();
return $arr[$index];
} else
throw new TInvalidDataValueException('list_index_invalid',$index);
@@ -232,11 +232,11 @@ class TPriorityList extends TList
*/
public function itemsAtPriority($priority=null)
{
- if($priority === null)
- $priority = $this->getDefaultPriority();
- $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
- return isset($this->_d[$priority]) ? $this->_d[$priority] : null;
+ return isset($this->_d[$priority])?$this->_d[$priority]:null;
}
/**
@@ -247,12 +247,12 @@ class TPriorityList extends TList
*/
public function itemAtIndexInPriority($index,$priority=null)
{
- if($priority === null)
- $priority = $this->getDefaultPriority();
- $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
- return !isset($this->_d[$priority]) ? false : (
- isset($this->_d[$priority][$index]) ? $this->_d[$priority][$index] : false
+ return !isset($this->_d[$priority])?false:(
+ isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
);
}
@@ -264,7 +264,7 @@ class TPriorityList extends TList
* @return int the index within the flattened array
* @throws TInvalidOperationException if the map is read-only
*/
- public function add($item, $priority=null)
+ public function add($item,$priority=null)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
@@ -280,7 +280,7 @@ class TPriorityList extends TList
* @throws TInvalidDataValueException If the index specified exceeds the bound
* @throws TInvalidOperationException if the list is read-only
*/
- public function insertAt($index, $item)
+ public function insertAt($index,$item)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
@@ -313,18 +313,18 @@ class TPriorityList extends TList
if($preserveCache) {
$this->sortPriorities();
$cc=0;
- foreach($this->_d as $prioritykey => $items)
- if($prioritykey >= $priority)
+ foreach($this->_d as $prioritykey=>$items)
+ if($prioritykey>=$priority)
break;
else
$cc+=count($items);
- if($index === false && isset($this->_d[$priority])) {
- $c = count($this->_d[$priority]);
- $c += $cc;
+ if($index===false&&isset($this->_d[$priority])) {
+ $c=count($this->_d[$priority]);
+ $c+=$cc;
$this->_d[$priority][]=$item;
} else if(isset($this->_d[$priority])) {
- $c = $index + $cc;
+ $c=$index+$cc;
array_splice($this->_d[$priority],$index,0,array($item));
} else {
$c = $cc;
@@ -332,25 +332,25 @@ class TPriorityList extends TList
$this->_d[$priority]=array($item);
}
- if($this->_fd && is_array($this->_fd)) // if there is a flattened array cache
+ if($this->_fd&&is_array($this->_fd)) // if there is a flattened array cache
array_splice($this->_fd,$c,0,array($item));
} else {
- $c = null;
- if($index === false && isset($this->_d[$priority])) {
- $cc = count($this->_d[$priority]);
+ $c=null;
+ if($index===false&&isset($this->_d[$priority])) {
+ $cc=count($this->_d[$priority]);
$this->_d[$priority][]=$item;
} else if(isset($this->_d[$priority])) {
- $cc = $index;
+ $cc=$index;
array_splice($this->_d[$priority],$index,0,array($item));
} else {
- $cc = 0;
- $this->_o = false;
+ $cc=0;
+ $this->_o=false;
$this->_d[$priority]=array($item);
}
- if($this->_fd && is_array($this->_fd) && count($this->_d) == 1)
+ if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
array_splice($this->_fd,$cc,0,array($item));
else
- $this->_fd = null;
+ $this->_fd=null;
}
$this->_c++;
@@ -374,17 +374,17 @@ class TPriorityList extends TList
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
- if(($p=$this->priorityOf($item, true))!==false)
+ if(($p=$this->priorityOf($item,true))!==false)
{
- if($priority !== false) {
- if($priority === null)
- $priority = $this->getDefaultPriority();
- $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($priority!==false) {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
- if($p[0] != $priority)
+ if($p[0]!=$priority)
throw new TInvalidDataValueException('list_item_inexistent');
}
- $this->removeAtIndexInPriority($p[1], $p[0]);
+ $this->removeAtIndexInPriority($p[1],$p[0]);
return $p[2];
}
else
@@ -403,8 +403,8 @@ class TPriorityList extends TList
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
- if(($priority = $this->priorityAt($index, true))!==false)
- return $this->removeAtIndexInPriority($priority[1], $priority[0]);
+ if(($priority=$this->priorityAt($index, true))!==false)
+ return $this->removeAtIndexInPriority($priority[1],$priority[0]);
throw new TInvalidDataValueException('list_index_invalid',$index);
}
@@ -421,22 +421,22 @@ class TPriorityList extends TList
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
- if($priority === null)
- $priority = $this->getDefaultPriority();
- $priority = (string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
- if(!isset($this->_d[$priority]) || $index < 0 || $index >= count($this->_d[$priority]))
+ if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
throw new TInvalidDataValueException('list_item_inexistent');
// $value is an array of elements removed, only one
- $value = array_splice($this->_d[$priority],$index,1);
- $value = $value[0];
+ $value=array_splice($this->_d[$priority],$index,1);
+ $value=$value[0];
if(!count($this->_d[$priority]))
unset($this->_d[$priority]);
$this->_c--;
- $this->_fd = null;
+ $this->_fd=null;
return $value;
}
@@ -448,10 +448,10 @@ class TPriorityList extends TList
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
- $d = array_reverse($this->_d, true);
- foreach($this->_d as $priority => $items) {
- for($index = count($items) - 1; $index >= 0; $index--)
- $this->removeAtIndexInPriority($index, $priority);
+ $d=array_reverse($this->_d,true);
+ foreach($this->_d as $priority=>$items) {
+ for($index=count($items)-1;$index>=0;$index--)
+ $this->removeAtIndexInPriority($index,$priority);
unset($this->_d[$priority]);
}
}
@@ -486,20 +486,18 @@ class TPriorityList extends TList
* if withindex is true, an array is returned of [0 => $priority, 1 => $priorityIndex, 2 => flattenedIndex,
* 'priority' => $priority, 'index' => $priorityIndex, 'absindex' => flattenedIndex]
*/
- public function priorityOf($item, $withindex = false)
+ public function priorityOf($item,$withindex = false)
{
- // this is to ensure priority order
$this->sortPriorities();
$absindex = 0;
- foreach($this->_d as $priority => $items) {
+ foreach($this->_d as $priority=>$items) {
if(($index=array_search($item,$items,true))!==false) {
- $absindex += $index;
- return $withindex ?
- array($priority, $index, $absindex,
- 'priority' => $priority, 'index' => $index, 'absindex' => $absindex) : $priority;
+ $absindex+=$index;
+ return $withindex?array($priority,$index,$absindex,
+ 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
} else
- $absindex += count($items);
+ $absindex+=count($items);
}
return false;
@@ -514,21 +512,19 @@ class TPriorityList extends TList
* if withindex is true, an array is returned of [0 => $priority, 1 => $priorityIndex, 2 => flattenedIndex,
* 'priority' => $priority, 'index' => $priorityIndex, 'absindex' => flattenedIndex]
*/
- public function priorityAt($index, $withindex = false)
+ public function priorityAt($index,$withindex = false)
{
- if($index < 0 || $index >= $this->getCount())
+ if($index<0||$index>=$this->getCount())
throw new TInvalidDataValueException('list_index_invalid',$index);
- // this is to ensure priority order
- $absindex = $index;
+ $absindex=$index;
$this->sortPriorities();
- foreach($this->_d as $priority => $items) {
- if($index >= ($c = count($items)))
- $index -= $c;
+ foreach($this->_d as $priority=>$items) {
+ if($index>=($c=count($items)))
+ $index-=$c;
else
- return $withindex ?
- array($priority, $index, $absindex,
- 'priority' => $priority, 'index' => $index, 'absindex' => $absindex) : $priority;
+ return $withindex?array($priority,$index,$absindex,
+ 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
}
return false;
}
@@ -546,10 +542,10 @@ class TPriorityList extends TList
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
- if(($priority = $this->priorityOf($indexitem, true)) === false)
+ if(($priority=$this->priorityOf($indexitem,true))===false)
throw new TInvalidDataValueException('list_item_inexistent');
- $this->insertAtIndexInPriority($item, $priority[1], $priority[0]);
+ $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
return $priority[2];
}
@@ -591,6 +587,46 @@ class TPriorityList extends TList
$this->sortPriorities();
return $this->_d;
}
+
+ /**
+ * Combines the map elements which have a priority below the parameter value
+ * @param numeric the cut-off priority. All items of priority less than this are returned.
+ * @param boolean whether or not the input cut-off priority is inclusive. Default: false, not inclusive.
+ * @return array the array of priorities keys with values of arrays of items that are below a specified priority.
+ * The priorities are sorted so important priorities, lower numerics, are first.
+ */
+ public function toArrayBelowPriority($priority,$inclusive=false)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
+ break;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+
+ /**
+ * Combines the map elements which have a priority above the parameter value
+ * @param numeric the cut-off priority. All items of priority greater than this are returned.
+ * @param boolean whether or not the input cut-off priority is inclusive. Default: true, inclusive.
+ * @return array the array of priorities keys with values of arrays of items that are above a specified priority.
+ * The priorities are sorted so important priorities, lower numerics, are first.
+ */
+ public function toArrayAbovePriority($priority,$inclusive=true)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
+ continue;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
/**
@@ -601,20 +637,20 @@ class TPriorityList extends TList
*/
public function copyFrom($data)
{
- if($data instanceof TPriorityList) {
+ if($data instanceof TPriorityList)
+ {
if($this->getCount()>0)
$this->clear();
- foreach($data->getPriorities() as $priority) {
- foreach($data->itemsAtPriority($priority) as $index => $item)
- $this->insertAtIndexInPriority($item, $index, $priority);
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $index=>$item)
+ $this->insertAtIndexInPriority($item,$index,$priority);
}
-
- } else if(is_array($data) || $data instanceof Traversable) {
+ } else if(is_array($data)||$data instanceof Traversable) {
if($this->getCount()>0)
$this->clear();
foreach($data as $key=>$item)
$this->add($item);
-
} else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
@@ -629,16 +665,21 @@ class TPriorityList extends TList
*/
public function mergeWith($data)
{
- if($data instanceof TPriorityList) {
- foreach($data->getPriorities() as $priority) {
- foreach($data->itemsAtPriority($priority) as $index => $item)
- $this->insertAtIndexInPriority($item, false, $priority);
+ if($data instanceof TPriorityList)
+ {
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $index=>$item)
+ $this->insertAtIndexInPriority($item,false,$priority);
}
- } else if(is_array($data) || $data instanceof Traversable) {
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
foreach($data as $priority=>$item)
$this->add($item);
- } else if($data!==null)
+ }
+ else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
@@ -650,7 +691,7 @@ class TPriorityList extends TList
*/
public function offsetExists($offset)
{
- return ($offset>=0 && $offset<$this->getCount());
+ return ($offset>=0&&$offset<$this->getCount());
}
/**
@@ -678,16 +719,16 @@ class TPriorityList extends TList
*/
public function offsetSet($offset,$item)
{
- if($offset === null)
+ if($offset===null)
return $this->add($item);
- if($offset === $this->getCount()) {
- $priority = $this->priorityAt($offset-1, true);
+ if($offset===$this->getCount()) {
+ $priority=$this->priorityAt($offset-1,true);
$priority[1]++;
} else {
- $priority = $this->priorityAt($offset, true);
- $this->removeAtIndexInPriority($priority[1], $priority[0]);
+ $priority=$this->priorityAt($offset,true);
+ $this->removeAtIndexInPriority($priority[1],$priority[0]);
}
- $this->insertAtIndexInPriority($item, $priority[1], $priority[0]);
+ $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
}
/**
@@ -700,91 +741,3 @@ class TPriorityList extends TList
$this->removeAt($offset);
}
}
-
-/**
- * TPriorityListIterator class
- *
- * TPriorityListIterator implements Iterator interface.
- *
- * TPriorityListIterator is used by TPriorityList. It allows TPriorityList to return a new iterator
- * for traversing the items in the priority list.
- *
- * @deprecated Issue 264 : ArrayIterator should be used instead
- * @author Brad Anderson <javalizard@gmail.com>
- * @version $Id: TPriorityList.php 2541 2010-10-03 15:05:13Z javalizard $
- * @package System.Collections
- * @since 3.2a
- */
-class TPriorityListIterator implements Iterator
-{
- /**
- * @var array the data to be iterated through
- */
- private $_d;
- /**
- * @var array list of keys in the map
- */
- private $_keys;
- /**
- * @var mixed current key
- */
- private $_key;
-
- /**
- * Constructor.
- * @param array the data to be iterated through
- */
- public function __construct(&$data)
- {
- $this->_d=&$data;
- $this->_keys=array_keys($data);
- }
-
- /**
- * Rewinds internal array pointer.
- * This method is required by the interface Iterator.
- */
- public function rewind()
- {
- $this->_key=reset($this->_keys);
- }
-
- /**
- * Returns the key of the current array element.
- * This method is required by the interface Iterator.
- * @return mixed the key of the current array element
- */
- public function key()
- {
- return $this->_key;
- }
-
- /**
- * Returns the current array element.
- * This method is required by the interface Iterator.
- * @return mixed the current array element
- */
- public function current()
- {
- return $this->_d[$this->_key];
- }
-
- /**
- * Moves the internal pointer to the next array element.
- * This method is required by the interface Iterator.
- */
- public function next()
- {
- $this->_key=next($this->_keys);
- }
-
- /**
- * Returns whether there is an element at current position.
- * This method is required by the interface Iterator.
- * @return boolean
- */
- public function valid()
- {
- return $this->_key!==false;
- }
-}
diff --git a/framework/Collections/TPriorityMap.php b/framework/Collections/TPriorityMap.php
new file mode 100644
index 00000000..6f8ae8bd
--- /dev/null
+++ b/framework/Collections/TPriorityMap.php
@@ -0,0 +1,606 @@
+<?php
+/**
+ * TPriorityMap, TPriorityMapIterator classes
+ *
+ * @author Brad Anderson <javalizard@mac.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2011 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TPriorityMap.php 2817 2010-04-18 04:25:03Z javalizard $
+ * @package System.Collections
+ */
+
+/**
+ * TPriorityMap class
+ *
+ * TPriorityMap implements a collection that takes key-value pairs with
+ * a priority to allow key-value pairs to be ordered. This ordering is
+ * important when flattening the map. When flattening the map, if some
+ * key-value pairs are required to be before or after others, use this
+ * class to keep order to your map.
+ *
+ * You can access, add or remove an item with a key by using
+ * {@link itemAt}, {@link add}, and {@link remove}. These functions
+ * can optionally take a priority parameter to allow access to specific
+ * priorities. TPriorityMap is functionally backward compatible
+ * with {@link TMap}.
+ *
+ * To get the number of the items in the map, use {@link getCount}.
+ * TPriorityMap can also be used like a regular array as follows,
+ * <code>
+ * $map[$key]=$value; // add a key-value pair
+ * unset($map[$key]); // remove the value with the specified key
+ * if(isset($map[$key])) // if the map contains the key
+ * foreach($map as $key=>$value) // traverse the items in the map
+ * $n=count($map); // returns the number of items in the map
+ * </code>
+ * Using standard array access method like these will always use
+ * the default priority.
+ *
+ * An item that doesn't specify a priority will receive the default
+ * priority. The default priority is set during the instantiation
+ * of a new TPriorityMap. If no custom default priority is specified,
+ * the standard default priority of 10 is used.
+ *
+ * Priorities with significant digits below precision will be rounded.
+ *
+ * A priority may also be a numeric with decimals. This is set
+ * during the instantiation of a new TPriorityMap.
+ * The default is 8 decimal places for a priority. If a negative number
+ * is used, rounding occurs into the integer space rather than in
+ * the decimal space. See {@link round}.
+ *
+ * @author Brad Anderson <javalizard@mac.com>
+ * @version $Id: TPriorityMap.php 2817 2010-04-18 04:25:03Z javalizard $
+ * @package System.Collections
+ * @since 3.2a
+ */
+Prado::using('System.Collections.TMap');
+
+class TPriorityMap extends TMap
+{
+ /**
+ * @var array internal data storage
+ */
+ private $_d=array();
+ /**
+ * @var boolean whether this list is read-only
+ */
+ private $_r=false;
+ /**
+ * @var boolean indicates if the _d is currently ordered.
+ */
+ private $_o=false;
+ /**
+ * @var array cached flattened internal data storage
+ */
+ private $_fd=null;
+ /**
+ * @var integer number of items contain within the map
+ */
+ private $_c=0;
+ /**
+ * @var numeric the default priority of items without specified priorities
+ */
+ private $_dp=10;
+ /**
+ * @var integer the precision of the numeric priorities within this priority list.
+ */
+ private $_p=8;
+
+ /**
+ * Constructor.
+ * Initializes the array with an array or an iterable object.
+ * @param map|array|Iterator|TPriorityMap the intial data. Default is null, meaning no initialization.
+ * @param boolean whether the list is read-only
+ * @param numeric the default priority of items without specified priorities.
+ * @param integer the precision of the numeric priorities
+ * @throws TInvalidDataTypeException If data is not null and neither an array nor an iterator.
+ */
+ public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
+ {
+ if($data!==null)
+ $this->copyFrom($data);
+ $this->setReadOnly($readOnly);
+ $this->setPrecision($precision);
+ $this->setDefaultPriority($defaultPriority);
+ }
+
+ /**
+ * @return boolean whether this map is read-only or not. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->_r;
+ }
+
+ /**
+ * @param boolean whether this list is read-only or not
+ */
+ protected function setReadOnly($value)
+ {
+ $this->_r=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return numeric gets the default priority of inserted items without a specified priority
+ */
+ public function getDefaultPriority()
+ {
+ return $this->_dp;
+ }
+
+ /**
+ * This must be called internally or when instantiated.
+ * @param numeric sets the default priority of inserted items without a specified priority
+ */
+ protected function setDefaultPriority($value)
+ {
+ $this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
+ }
+
+ /**
+ * @return integer The precision of numeric priorities, defaults to 8
+ */
+ public function getPrecision()
+ {
+ return $this->_p;
+ }
+
+ /**
+ * This must be called internally or when instantiated.
+ * @param integer The precision of numeric priorities.
+ */
+ protected function setPrecision($value)
+ {
+ $this->_p=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * Returns an iterator for traversing the items in the map.
+ * This method is required by the interface IteratorAggregate.
+ * @return Iterator an iterator for traversing the items in the map.
+ */
+ public function getIterator()
+ {
+ return new ArrayIterator($this->flattenPriorities());
+ }
+
+
+ /**
+ * Orders the priority list internally.
+ */
+ protected function sortPriorities() {
+ if(!$this->_o) {
+ ksort($this->_d, SORT_NUMERIC);
+ $this->_o=true;
+ }
+ }
+
+ /**
+ * This flattens the priority map into a flat array [0,...,n-1]
+ * @return array array of items in the list in priority and index order
+ */
+ protected function flattenPriorities() {
+ if(is_array($this->_fd))
+ return $this->_fd;
+
+ $this->sortPriorities();
+ $this->_fd = array();
+ foreach($this->_d as $priority => $itemsatpriority)
+ $this->_fd = array_merge($this->_fd, $itemsatpriority);
+ return $this->_fd;
+ }
+
+ /**
+ * Returns the number of items in the map.
+ * This method is required by Countable interface.
+ * @return integer number of items in the map.
+ */
+ public function count()
+ {
+ return $this->getCount();
+ }
+
+ /**
+ * @return integer the number of items in the map
+ */
+ public function getCount()
+ {
+ return $this->_c;
+ }
+
+ /**
+ * Gets the number of items at a priority within the map.
+ * @param numeric optional priority at which to count items. if no parameter,
+ * it will be set to the default {@link getDefaultPriority}
+ * @return integer the number of items in the map at the specified priority
+ */
+ public function getPriorityCount($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+
+ if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
+ return false;
+ return count($this->_d[$priority]);
+ }
+
+ /**
+ * This returns a list of the priorities within this map, ordered lowest to highest.
+ * @return array the array of priority numerics in decreasing priority order
+ */
+ public function getPriorities()
+ {
+ $this->sortPriorities();
+ return array_keys($this->_d);
+ }
+
+ /**
+ * Returns the keys within the map ordered through the priority of each key-value pair
+ * @return array the key list
+ */
+ public function getKeys()
+ {
+ return array_keys($this->flattenPriorities());
+ }
+
+ /**
+ * Returns the item with the specified key. If a priority is specified, only items
+ * within that specific priority will be selected
+ * @param mixed the key
+ * @param mixed the priority. null is the default priority, false is any priority,
+ * and numeric is a specific priority. default: false, any priority.
+ * @return mixed the element at the offset, null if no element is found at the offset
+ */
+ public function itemAt($key,$priority=false)
+ {
+ if($priority===false){
+ $map=$this->flattenPriorities();
+ return isset($map[$key])?$map[$key]:null;
+ } else {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
+ }
+ }
+
+ /**
+ * This changes an item's priority. Specify the item and the new priority.
+ * This method is exactly the same as {@link offsetGet}.
+ * @param mixed the key
+ * @param numeric|null the priority. default: null, filled in with the default priority numeric.
+ * @return numeric old priority of the item
+ */
+ public function setPriorityAt($key,$priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+
+ $oldpriority=$this->priorityAt($key);
+ if($oldpriority!==false&&$oldpriority!=$priority) {
+ $value=$this->remove($key,$oldpriority);
+ $this->add($key,$value,$priority);
+ }
+ return $oldpriority;
+ }
+
+ /**
+ * Gets all the items at a specific priority.
+ * @param numeric priority of the items to get. Defaults to null, filled in with the default priority, if left blank.
+ * @return array all items at priority in index order, null if there are no items at that priority
+ */
+ public function itemsAtPriority($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+
+ return isset($this->_d[$priority])?$this->_d[$priority]:null;
+ }
+
+ /**
+ * Returns the priority of a particular item within the map. This searches the map for the item.
+ * @param mixed item to look for within the map
+ * @return numeric priority of the item in the map
+ */
+ public function priorityOf($item)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(($index=array_search($item,$items,true))!==false)
+ return $priority;
+ return false;
+ }
+
+ /**
+ * Retutrns the priority of an item at a particular flattened index.
+ * @param integer index of the item within the map
+ * @return numeric priority of the item in the map
+ */
+ public function priorityAt($key)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(array_key_exists($key,$items))
+ return $priority;
+ return false;
+ }
+
+ /**
+ * Adds an item into the map. A third parameter may be used to set the priority
+ * of the item within the map. Priority is primarily used during when flattening
+ * the map into an array where order may be and important factor of the key-value
+ * pairs within the array.
+ * Note, if the specified key already exists, the old value will be overwritten.
+ * No duplicate keys are allowed regardless of priority.
+ * @param mixed key
+ * @param mixed value
+ * @param numeric|null priority, default: null, filled in with default priority
+ * @return numeric priority at which the pair was added
+ * @throws TInvalidOperationException if the map is read-only
+ */
+ public function add($key,$value,$priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+
+ if(!$this->_r)
+ {
+ foreach($this->_d as $innerpriority=>$items)
+ if(array_key_exists($key,$items))
+ {
+ unset($this->_d[$innerpriority][$key]);
+ $this->_c--;
+ if(count($this->_d[$innerpriority])===0)
+ unset($this->_d[$innerpriority]);
+ }
+ if(!isset($this->_d[$priority])) {
+ $this->_d[$priority]=array($key=>$value);
+ $this->_o=false;
+ }
+ else
+ $this->_d[$priority][$key]=$value;
+ $this->_c++;
+ $this->_fd=null;
+ }
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ return $priority;
+ }
+
+ /**
+ * Removes an item from the map by its key. If no priority, or false, is specified
+ * then priority is irrelevant. If null is used as a parameter for priority, then
+ * the priority will be the default priority. If a priority is specified, or
+ * the default priority is specified, only key-value pairs in that priority
+ * will be affected.
+ * @param mixed the key of the item to be removed
+ * @param numeric|false|null priority. False is any priority, null is the
+ * default priority, and numeric is a specific priority
+ * @return mixed the removed value, null if no such key exists.
+ * @throws TInvalidOperationException if the map is read-only
+ */
+ public function remove($key,$priority=false)
+ {
+ if(!$this->_r)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+
+ if($priority===false)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(array_key_exists($key,$items))
+ {
+ $value=$this->_d[$priority][$key];
+ unset($this->_d[$priority][$key]);
+ $this->_c--;
+ if(count($this->_d[$priority])===0)
+ {
+ unset($this->_d[$priority]);
+ $this->_o=false;
+ }
+ $this->_fd=null;
+ return $value;
+ }
+ return null;
+ }
+ else
+ {
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
+ {
+ $value=$this->_d[$priority][$key];
+ unset($this->_d[$priority][$key]);
+ $this->_c--;
+ if(count($this->_d[$priority])===0) {
+ unset($this->_d[$priority]);
+ $this->_o=false;
+ }
+ $this->_fd=null;
+ return $value;
+ }
+ else
+ return null;
+ }
+ }
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ }
+
+ /**
+ * Removes all items in the map. {@link remove} is called on all items.
+ */
+ public function clear()
+ {
+ foreach($this->_d as $priority=>$items)
+ foreach(array_keys($items) as $key)
+ $this->remove($key);
+ }
+
+ /**
+ * @param mixed the key
+ * @return boolean whether the map contains an item with the specified key
+ */
+ public function contains($key)
+ {
+ $map=$this->flattenPriorities();
+ return isset($map[$key])||array_key_exists($key,$map);
+ }
+
+ /**
+ * When the map is flattened into an array, the priorities are taken into
+ * account and elements of the map are ordered in the array according to
+ * their priority.
+ * @return array the list of items in array
+ */
+ public function toArray()
+ {
+ return $this->flattenPriorities();
+ }
+
+ /**
+ * Combines the map elements which have a priority below the parameter value
+ * @param numeric the cut-off priority. All items of priority less than this are returned.
+ * @param boolean whether or not the input cut-off priority is inclusive. Default: false, not inclusive.
+ * @return array the array of priorities keys with values of arrays of items that are below a specified priority.
+ * The priorities are sorted so important priorities, lower numerics, are first.
+ */
+ public function toArrayBelowPriority($priority,$inclusive=false)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
+ break;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+
+ /**
+ * Combines the map elements which have a priority above the parameter value
+ * @param numeric the cut-off priority. All items of priority greater than this are returned.
+ * @param boolean whether or not the input cut-off priority is inclusive. Default: true, inclusive.
+ * @return array the array of priorities keys with values of arrays of items that are above a specified priority.
+ * The priorities are sorted so important priorities, lower numerics, are first.
+ */
+ public function toArrayAbovePriority($priority,$inclusive=true)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
+ continue;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+
+ /**
+ * Copies iterable data into the map.
+ * Note, existing data in the map will be cleared first.
+ * @param mixed the data to be copied from, must be an array, object implementing
+ * Traversable, or a TPriorityMap
+ * @throws TInvalidDataTypeException If data is neither an array nor an iterator.
+ */
+ public function copyFrom($data)
+ {
+ if($data instanceof TPriorityMap)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data->getPriorities() as $priority) {
+ foreach($data->itemsAtPriority($priority) as $key => $value) {
+ $this->add($key,$value,$priority);
+ }
+ }
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+
+ /**
+ * Merges iterable data into the map.
+ * Existing data in the map will be kept and overwritten if the keys are the same.
+ * @param mixed the data to be merged with, must be an array, object implementing
+ * Traversable, or a TPriorityMap
+ * @throws TInvalidDataTypeException If data is neither an array nor an iterator.
+ */
+ public function mergeWith($data)
+ {
+ if($data instanceof TPriorityMap)
+ {
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $key => $value)
+ $this->add($key,$value,$priority);
+ }
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+
+ /**
+ * Returns whether there is an element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to check on
+ * @return boolean
+ */
+ public function offsetExists($offset)
+ {
+ return $this->contains($offset);
+ }
+
+ /**
+ * Returns the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to retrieve element.
+ * @return mixed the element at the offset, null if no element is found at the offset
+ */
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+
+ /**
+ * Sets the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to set element
+ * @param mixed the element value
+ */
+ public function offsetSet($offset,$item)
+ {
+ $this->add($offset,$item);
+ }
+
+ /**
+ * Unsets the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to unset element
+ */
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+} \ No newline at end of file
diff --git a/tests/unit/Collections/TPriorityListTest.php b/tests/unit/Collections/TPriorityListTest.php
index f329538c..35c712ae 100644
--- a/tests/unit/Collections/TPriorityListTest.php
+++ b/tests/unit/Collections/TPriorityListTest.php
@@ -964,6 +964,77 @@ class TPriorityListTest extends PHPUnit_Framework_TestCase
$this->assertEquals($this->pitem3, $array[100][0]);
}
+ public function testToArrayBelowPriority() {
+ $array = $this->plist->toArrayBelowPriority(0);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->plist->toArrayBelowPriority(10);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->plist->toArrayBelowPriority(10, true);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals($this->pitem1, $array[1]);
+ $this->assertEquals($this->pitem2, $array[2]);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->plist->toArrayBelowPriority(11);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals($this->pitem1, $array[1]);
+ $this->assertEquals($this->pitem2, $array[2]);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->plist->toArrayBelowPriority(100);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals($this->pitem1, $array[1]);
+ $this->assertEquals($this->pitem2, $array[2]);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->plist->toArrayBelowPriority(100, true);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals($this->pitem1, $array[1]);
+ $this->assertEquals($this->pitem2, $array[2]);
+ $this->assertEquals($this->pitem3, $array[3]);
+ $this->assertEquals(4, count($array));
+ }
+
+ public function testToArrayAbovePriority() {
+ $array = $this->plist->toArrayAbovePriority(100, false);
+ $this->assertEquals(0, count($array));
+
+ $array = $this->plist->toArrayAbovePriority(100, true);
+ $this->assertEquals(1, count($array));
+ $this->assertEquals($this->pitem3, $array[0]);
+
+ $array = $this->plist->toArrayAbovePriority(10, false);
+ $this->assertEquals($this->pitem3, $array[0]);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->plist->toArrayAbovePriority(10);
+ $this->assertEquals($this->pitem1, $array[0]);
+ $this->assertEquals($this->pitem2, $array[1]);
+ $this->assertEquals($this->pitem3, $array[2]);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->plist->toArrayAbovePriority(11);
+ $this->assertEquals($this->pitem3, $array[0]);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->plist->toArrayAbovePriority(0);
+ $this->assertEquals($this->pitem1, $array[0]);
+ $this->assertEquals($this->pitem2, $array[1]);
+ $this->assertEquals($this->pitem3, $array[2]);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->plist->toArrayAbovePriority(-10000000, true);
+ $this->assertEquals($this->pfirst, $array[0]);
+ $this->assertEquals($this->pitem1, $array[1]);
+ $this->assertEquals($this->pitem2, $array[2]);
+ $this->assertEquals($this->pitem3, $array[3]);
+ $this->assertEquals(4, count($array));
+ }
+
public function testArrayReadTPriorityList()
{
$this->assertTrue($this->plist[0] === $this->pfirst);
diff --git a/tests/unit/Collections/TPriorityMapTest.php b/tests/unit/Collections/TPriorityMapTest.php
new file mode 100644
index 00000000..54ff68b7
--- /dev/null
+++ b/tests/unit/Collections/TPriorityMapTest.php
@@ -0,0 +1,490 @@
+<?php
+require_once dirname(__FILE__).'/../phpunit.php';
+
+class MapItem {
+ public $data='data';
+}
+
+Prado::using('System.Collections.TPriorityMap');
+/**
+ * @package System.Collections
+ */
+class TPriorityMapTest extends PHPUnit_Framework_TestCase {
+ protected $map;
+ protected $item1,$item2,$item3,$item4,$item5;
+
+ public function setUp() {
+ // test that TPriorityMap complies with TMap
+ $this->map=new TPriorityMap;
+ $this->item1=new MapItem;
+ $this->item2=new MapItem;
+ $this->item3=new MapItem;
+ $this->item4=new MapItem;
+ $this->item5=new MapItem;
+ $this->map->add('key1',$this->item1);
+ $this->map->add('key2',$this->item2);
+
+ //Test the priority capabilities
+ }
+
+ public function setUpPriorities() {
+ $this->map->add('key3', $this->item3, 0);
+ $this->map->add('key4', $this->item4, 100);
+ $this->map->add('key5', $this->item5, 1);
+ }
+
+ public function tearDown() {
+ $this->map=null;
+ $this->item1=null;
+ $this->item2=null;
+ $this->item3=null;
+ }
+
+ public function testConstruct() {
+ $a=array(1,2,'key3'=>3);
+ $map=new TPriorityMap($a);
+ $this->assertEquals(3,$map->getCount());
+ $map2=new TPriorityMap($this->map);
+ $this->assertEquals(2,$map2->getCount());
+
+ /* Test the priority functionality of TPriorityMap */
+
+ $map3=new TPriorityMap($this->map, false, 100, -1);
+ $this->assertEquals(100,$map3->getDefaultPriority());
+ $this->assertEquals(-1,$map3->getPrecision());
+ }
+
+ /* Test that TPriorityMap complies with TMap */
+
+
+ public function testGetReadOnly() {
+ $map = new TPriorityMap(null, true);
+ self::assertEquals(true, $map->getReadOnly(), 'List is not read-only');
+ $map = new TList(null, false);
+ self::assertEquals(false, $map->getReadOnly(), 'List is read-only');
+ }
+
+ public function testGetCount() {
+ $this->assertEquals(2,$this->map->getCount());
+ }
+
+ public function testGetKeys() {
+ $keys=$this->map->getKeys();
+ $this->assertTrue(count($keys)===2 && $keys[0]==='key1' && $keys[1]==='key2');
+ }
+
+ public function testAdd()
+ {
+ $this->map->add('key3',$this->item3);
+ $this->assertTrue($this->map->getCount()==3 && $this->map->contains('key3'));
+ }
+
+ public function testCanNotAddWhenReadOnly() {
+ $map = new TPriorityMap(array(), true);
+ try {
+ $map->add('key', 'value');
+ } catch(TInvalidOperationException $e) {
+ return;
+ }
+ self::fail('An expected TInvalidOperationException was not raised');
+ }
+
+ public function testRemove()
+ {
+ $this->map->remove('key1');
+ $this->assertTrue($this->map->getCount()==1 && !$this->map->contains('key1'));
+ $this->assertTrue($this->map->remove('unknown key')===null);
+ }
+
+ public function testCanNotRemoveWhenReadOnly() {
+ $map = new TPriorityMap(array('key' => 'value'), true);
+ try {
+ $map->remove('key');
+ } catch(TInvalidOperationException $e) {
+ return;
+ }
+ self::fail('An expected TInvalidOperationException was not raised');
+ }
+
+ public function testClear()
+ {
+ $this->map->clear();
+ $this->assertTrue($this->map->getCount()==0 && !$this->map->contains('key1') && !$this->map->contains('key2'));
+ }
+
+ public function testContains()
+ {
+ $this->assertTrue($this->map->contains('key1'));
+ $this->assertTrue($this->map->contains('key2'));
+ $this->assertFalse($this->map->contains('key3'));
+ }
+
+ public function testCopyFrom()
+ {
+ $array=array('key3'=>$this->item3,'key4'=>$this->item1);
+ $this->map->copyFrom($array);
+ $this->assertTrue($this->map->getCount()==2 && $this->map['key3']===$this->item3 && $this->map['key4']===$this->item1);
+ try
+ {
+ $this->map->copyFrom($this);
+ $this->fail('no exception raised when copying a non-traversable object');
+ }
+ catch(TInvalidDataTypeException $e)
+ {
+
+ }
+ }
+
+ public function testMergeWith()
+ {
+ $array=array('key2'=>$this->item1,'key3'=>$this->item3);
+ $this->map->mergeWith($array);
+ $this->assertEquals(3,$this->map->getCount());
+ $this->assertTrue($this->map['key2']===$this->item1);
+ $this->assertTrue($this->map['key3']===$this->item3);
+ try
+ {
+ $this->map->mergeWith($this);
+ $this->fail('no exception raised when copying a non-traversable object');
+ }
+ catch(TInvalidDataTypeException $e)
+ {
+
+ }
+ }
+
+ public function testArrayRead()
+ {
+ $this->assertTrue($this->map['key1']===$this->item1);
+ $this->assertTrue($this->map['key2']===$this->item2);
+ $this->assertEquals(null,$this->map['key3']);
+ }
+
+ public function testArrayWrite()
+ {
+ $this->map['key3']=$this->item3;
+ $this->assertTrue($this->map['key3']===$this->item3);
+ $this->assertEquals(3,$this->map->getCount());
+ $this->map['key1']=$this->item3;
+ $this->assertTrue($this->map['key1']===$this->item3);
+ $this->assertEquals(3,$this->map->getCount());
+ unset($this->map['key2']);
+ $this->assertEquals(2,$this->map->getCount());
+ $this->assertFalse($this->map->contains('key2'));
+ try
+ {
+ unset($this->map['unknown key']);
+
+ }
+ catch(Exception $e)
+ {
+ $this->fail('exception raised when unsetting element with unknown key');
+ }
+ }
+
+ public function testArrayForeach()
+ {
+ $n=0;
+ $found=0;
+ foreach($this->map as $index=>$item)
+ {
+ $n++;
+ if($index==='key1' && $item===$this->item1)
+ $found++;
+ if($index==='key2' && $item===$this->item2)
+ $found++;
+ }
+ $this->assertTrue($n==2 && $found==2);
+ }
+
+ public function testArrayMisc()
+ {
+ $this->assertEquals($this->map->Count,count($this->map));
+ $this->assertTrue(isset($this->map['key1']));
+ $this->assertFalse(isset($this->map['unknown key']));
+ }
+
+ public function testToArray() {
+ $map = new TPriorityMap(array('key' => 'value'));
+ self::assertEquals(array('key' => 'value'), $map->toArray());
+ }
+
+
+
+
+ /* Test the priority functionality of TPriorityMap */
+
+
+ public function testDefaultPriorityAndPrecision() {
+
+ $this->assertEquals(10, $this->map->DefaultPriority);
+
+ $this->map->DefaultPriority = 5;
+ $this->assertEquals(5, $this->map->getDefaultPriority());
+
+ $this->assertEquals(8, $this->map->Precision);
+
+ $this->map->Precision = 0;
+ $this->assertEquals(0, $this->map->getPrecision());
+
+ ;
+
+ $this->assertEquals(5, $this->map->add('key3', $this->item3));
+ $this->assertEquals(10, $this->map->add('key4', $this->item1, 10));
+ $this->assertTrue(10 == $this->map->add('key4', $this->item1, 10.01));
+ $this->assertTrue(100 == $this->map->add('key4', $this->item1, 100));
+ $this->map->Precision = 1;
+ $this->assertTrue(10.1 == $this->map->add('key5', $this->item1, 10.1));
+
+ $this->assertEquals(5, $this->map->getCount());
+ }
+
+ public function testAddWithPriorityAndPriorityOfAt() {
+
+ $this->setUpPriorities();
+
+ $this->assertEquals(5, $this->map->getCount());
+ $this->assertEquals(10, $this->map->priorityOf($this->item1));
+ $this->assertEquals(0, $this->map->priorityOf($this->item3));
+ $this->assertEquals(100, $this->map->priorityOf($this->item4));
+ $this->assertEquals(1, $this->map->priorityOf($this->item5));
+ $this->assertEquals(false, $this->map->priorityOf(null));
+ $this->assertEquals(false, $this->map->priorityOf('foo'));
+
+ $this->assertEquals(10, $this->map->priorityAt('key1'));
+ $this->assertEquals(0, $this->map->priorityAt('key3'));
+ $this->assertEquals(100, $this->map->priorityAt('key4'));
+ $this->assertEquals(1, $this->map->priorityAt('key5'));
+ $this->assertEquals(false, $this->map->priorityAt(null));
+ $this->assertEquals(false, $this->map->priorityAt('foo'));
+
+ }
+
+ public function testRemoveWithPriorityAndItemsAtWithPriority() {
+
+ $this->setUpPriorities();
+
+ $this->assertEquals(5, $this->map->getCount());
+ $this->map->remove('key6');
+ $this->assertEquals(5, $this->map->getCount());
+ $this->map->remove('key6', null);
+ $this->assertEquals(5, $this->map->getCount());
+
+
+ // key5 is at priority 1... not the default priority defined by null... nothing should happen here
+ $this->map->remove('key5', null);
+ $this->assertEquals(5, $this->map->getCount());
+
+ // key5 is at priority 1... not 50... nothing should happen here
+ $this->map->remove('key5', 50);
+ $this->assertEquals(5, $this->map->getCount());
+
+
+
+ $this->assertEquals(array('key3'=>$this->item3), $this->map->itemsAtPriority(0));
+ $this->assertEquals(array('key1'=>$this->item1, 'key2'=>$this->item2), $this->map->itemsAtPriority($this->map->DefaultPriority));
+
+ $this->assertEquals($this->item2, $this->map->itemAt('key2'));
+ $this->assertEquals($this->item2, $this->map->itemAt('key2', 10));
+ $this->assertNull($this->map->itemAt('key2', 11)); //'key2' doesn't exist and priority 11... it is only at priority 10
+ $this->assertNull($this->map->itemAt('key2', 10.1)); //'key2' doesn't exist and priority 10.1... it is only at priority 10
+
+ $this->assertEquals($this->item4, $this->map->remove('key4'));
+ $this->assertEquals(4, $this->map->getCount());
+
+ $this->assertEquals($this->item5, $this->map->remove('key5'));
+ $this->assertEquals(3, $this->map->getCount());
+ }
+ public function testIteratorAndArrayWithPriorities() {
+
+ $this->setUpPriorities();
+
+ // This is the primary reason for a TPriorityMap
+ $array = $this->map->toArray();
+
+ $ordered_keys = array_keys($array);
+ $this->assertEquals('key3', $ordered_keys[0]);
+ $this->assertEquals('key5', $ordered_keys[1]);
+ $this->assertEquals('key1', $ordered_keys[2]);
+ $this->assertEquals('key2', $ordered_keys[3]);
+ $this->assertEquals('key4', $ordered_keys[4]);
+
+ $ordered_values = array_values($array);
+ $this->assertEquals($this->item3, $ordered_values[0]);
+ $this->assertEquals($this->item5, $ordered_values[1]);
+ $this->assertEquals($this->item1, $ordered_values[2]);
+ $this->assertEquals($this->item2, $ordered_values[3]);
+ $this->assertEquals($this->item4, $ordered_values[4]);
+
+ $iter = $this->map->getIterator();
+
+ $this->assertTrue($iter->valid());
+ $this->assertEquals('key3', $iter->key());
+ $this->assertEquals($this->item1, $iter->current());
+ $iter->next();
+ $this->assertTrue($iter->valid());
+ $this->assertEquals('key5', $iter->key());
+ $this->assertEquals($this->item3, $iter->current());
+ $iter->next();
+ $this->assertTrue($iter->valid());
+ $this->assertEquals('key1', $iter->key());
+ $this->assertEquals($this->item5, $iter->current());
+ $iter->next();
+ $this->assertTrue($iter->valid());
+ $this->assertEquals('key2', $iter->key());
+ $this->assertEquals($this->item5, $iter->current());
+ $iter->next();
+ $this->assertTrue($iter->valid());
+ $this->assertEquals('key4', $iter->key());
+ $this->assertEquals($this->item5, $iter->current());
+ $iter->next();
+ $this->assertFalse($iter->valid());
+ $this->assertEquals(null, $iter->key());
+ $this->assertEquals(null, $iter->current());
+ }
+
+
+ public function testGetPriorities() {
+ $this->setUpPriorities();
+
+ $priorities = $this->map->getPriorities();
+
+ $this->assertEquals(0, $priorities[0]);
+ $this->assertEquals(1, $priorities[1]);
+ $this->assertEquals(10, $priorities[2]);
+ $this->assertEquals(100, $priorities[3]);
+ $this->assertEquals(null, $priorities[4]);
+ }
+
+
+ public function testCopyAndMergeWithPriorities() {
+ $this->setUpPriorities();
+
+ $map1 = new TPriorityMap();
+ $map1->add('key1', $this->item1);
+ $map1->add('keyc', 'valuec');
+ $map1->copyFrom($this->map);
+
+ $this->assertEquals(5, $map1->getCount());
+
+ $array = $map1->toArray();
+ $ordered_keys = array_keys($array);
+ $this->assertEquals('key3', $ordered_keys[0]);
+ $this->assertEquals('key5', $ordered_keys[1]);
+ $this->assertEquals('key1', $ordered_keys[2]);
+ $this->assertEquals('key2', $ordered_keys[3]);
+ $this->assertEquals('key4', $ordered_keys[4]);
+
+ $ordered_values = array_values($array);
+ $this->assertEquals($this->item3, $ordered_values[0]);
+ $this->assertEquals($this->item5, $ordered_values[1]);
+ $this->assertEquals($this->item1, $ordered_values[2]);
+ $this->assertEquals($this->item2, $ordered_values[3]);
+ $this->assertEquals($this->item4, $ordered_values[4]);
+
+
+
+ $map2 = new TPriorityMap();
+ $map2->add('startkey', 'startvalue', -1000);
+ $map2->add('key5', 'value5', 40);
+ $map2->add('endkey', 'endvalue', 1000);
+ $map2->mergeWith($this->map);
+
+ $this->assertEquals(7, $map2->getCount());
+
+ $array = $map2->toArray();
+ $ordered_keys = array_keys($array);
+ $this->assertEquals('startkey', $ordered_keys[0]);
+ $this->assertEquals('key3', $ordered_keys[1]);
+ $this->assertEquals('key5', $ordered_keys[2]);
+ $this->assertEquals('key1', $ordered_keys[3]);
+ $this->assertEquals('key2', $ordered_keys[4]);
+ $this->assertEquals('key4', $ordered_keys[5]);
+ $this->assertEquals('endkey', $ordered_keys[6]);
+
+ $ordered_values = array_values($array);
+ $this->assertEquals('startvalue', $ordered_values[0]);
+ $this->assertEquals($this->item3, $ordered_values[1]);
+ $this->assertEquals($this->item5, $ordered_values[2]);
+ $this->assertEquals($this->item1, $ordered_values[3]);
+ $this->assertEquals($this->item2, $ordered_values[4]);
+ $this->assertEquals($this->item4, $ordered_values[5]);
+ $this->assertEquals('endvalue', $ordered_values[6]);
+
+ $this->assertEquals(1, $map2->priorityAt('key5'));
+ $this->assertEquals(1, $map2->priorityOf($this->item5));
+ }
+
+ public function testSetPriorityAt() {
+
+ $this->assertEquals(10, $this->map->priorityAt('key2'));
+ $this->assertEquals(10, $this->map->setPriorityAt('key2', 1));
+ $this->assertEquals(1, $this->map->priorityAt('key2'));
+ $this->assertEquals(1, $this->map->setPriorityAt('key2'));
+ $this->assertEquals(10, $this->map->priorityAt('key2'));
+ }
+
+ public function testToArrayBelowPriority() {
+ $this->setUpPriorities();
+
+ $array = $this->map->toArrayBelowPriority(1);
+ $this->assertEquals(array('key3'=> $this->item3), $array);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->map->toArrayBelowPriority(1, true);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5), $array);
+ $this->assertEquals(2, count($array));
+
+ $array = $this->map->toArrayBelowPriority(2);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5), $array);
+ $this->assertEquals(2, count($array));
+
+ $array = $this->map->toArrayBelowPriority(10);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5), $array);
+ $this->assertEquals(2, count($array));
+
+ $array = $this->map->toArrayBelowPriority(10, true);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5, 'key1' => $this->item1, 'key2' => $this->item2), $array);
+ $this->assertEquals(4, count($array));
+
+ $array = $this->map->toArrayBelowPriority(100);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5, 'key1' => $this->item1, 'key2' => $this->item2), $array);
+ $this->assertEquals(4, count($array));
+
+ $array = $this->map->toArrayBelowPriority(100, true);
+ $this->assertEquals(array('key3'=> $this->item3, 'key5'=> $this->item5, 'key1' => $this->item1, 'key2' => $this->item2, 'key4' => $this->item4), $array);
+ $this->assertEquals(5, count($array));
+ }
+
+ public function testToArrayAbovePriority() {
+ $this->setUpPriorities();
+
+ $array = $this->map->toArrayAbovePriority(100, false);
+ $this->assertEquals(0, count($array));
+
+ $array = $this->map->toArrayAbovePriority(100, true);
+ $this->assertEquals(1, count($array));
+ $this->assertEquals(array('key4' => $this->item4), $array);
+
+ $array = $this->map->toArrayAbovePriority(11);
+ $this->assertEquals(array('key4' => $this->item4), $array);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->map->toArrayAbovePriority(10, false);
+ $this->assertEquals(array('key4' => $this->item4), $array);
+ $this->assertEquals(1, count($array));
+
+ $array = $this->map->toArrayAbovePriority(10);
+ $this->assertEquals(array('key1' => $this->item1, 'key2' => $this->item2, 'key4' => $this->item4), $array);
+ $this->assertEquals(3, count($array));
+
+ $array = $this->map->toArrayAbovePriority(0);
+ $this->assertEquals(array('key3' => $this->item3, 'key5' => $this->item5, 'key1' => $this->item1, 'key2' => $this->item2, 'key4' => $this->item4), $array);
+ $this->assertEquals(5, count($array));
+ }
+
+
+
+}
+
+?>