PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/core/src/main/php/util/collections/Vector.class.php

https://github.com/treuter/xp-framework
PHP | 308 lines | 133 code | 27 blank | 148 comment | 24 complexity | e599773c7508215636ee6eb011f543b3 MD5 | raw file
  1. <?php
  2. /* This class is part of the XP framework
  3. *
  4. * $Id$
  5. */
  6. uses('util.collections.IList');
  7. /**
  8. * Resizable array list
  9. *
  10. * @test xp://net.xp_framework.unittest.util.collections.VectorTest
  11. * @test xp://net.xp_framework.unittest.util.collections.GenericsTest
  12. * @test xp://net.xp_framework.unittest.util.collections.ArrayAccessTest
  13. * @see xp://lang.types.ArrayList
  14. * @purpose IList implementation
  15. */
  16. #[@generic(self= 'T', implements= array('T'))]
  17. class Vector extends Object implements IList {
  18. protected static
  19. $iterate = NULL;
  20. protected
  21. $elements = array(),
  22. $size = 0;
  23. static function __static() {
  24. self::$iterate= newinstance('Iterator', array(), '{
  25. private $i= 0, $v;
  26. public function on($v) { $self= new self(); $self->v= $v; return $self; }
  27. public function current() { return $this->v[$this->i]; }
  28. public function key() { return $this->i; }
  29. public function next() { $this->i++; }
  30. public function rewind() { $this->i= 0; }
  31. public function valid() { return $this->i < sizeof($this->v); }
  32. }');
  33. }
  34. /**
  35. * Constructor
  36. *
  37. * @param T[] elements default array()
  38. */
  39. #[@generic(params= 'T[]')]
  40. public function __construct($elements= array()) {
  41. $this->elements= $elements;
  42. $this->size= sizeof($this->elements);
  43. }
  44. /**
  45. * Returns an iterator for use in foreach()
  46. *
  47. * @see php://language.oop5.iterations
  48. * @return php.Iterator
  49. */
  50. public function getIterator() {
  51. return self::$iterate->on($this->elements);
  52. }
  53. /**
  54. * = list[] overloading
  55. *
  56. * @param int offset
  57. * @return T
  58. */
  59. #[@generic(return= 'T')]
  60. public function offsetGet($offset) {
  61. return $this->get($offset);
  62. }
  63. /**
  64. * list[]= overloading
  65. *
  66. * @param int offset
  67. * @param T value
  68. * @throws lang.IllegalArgumentException if key is neither numeric (set) nor NULL (add)
  69. */
  70. #[@generic(params= ', T')]
  71. public function offsetSet($offset, $value) {
  72. if (is_int($offset)) {
  73. $this->set($offset, $value);
  74. } else if (NULL === $offset) {
  75. $this->add($value);
  76. } else {
  77. throw new IllegalArgumentException('Incorrect type '.gettype($offset).' for index');
  78. }
  79. }
  80. /**
  81. * isset() overloading
  82. *
  83. * @param int offset
  84. * @return bool
  85. */
  86. public function offsetExists($offset) {
  87. return ($offset >= 0 && $offset < $this->size);
  88. }
  89. /**
  90. * unset() overloading
  91. *
  92. * @param int offset
  93. */
  94. public function offsetUnset($offset) {
  95. $this->remove($offset);
  96. }
  97. /**
  98. * Returns the number of elements in this list.
  99. *
  100. * @return int
  101. */
  102. public function size() {
  103. return $this->size;
  104. }
  105. /**
  106. * Tests if this list has no elements.
  107. *
  108. * @return bool
  109. */
  110. public function isEmpty() {
  111. return 0 == $this->size;
  112. }
  113. /**
  114. * Adds an element to this list
  115. *
  116. * @param T element
  117. * @return T the added element
  118. */
  119. #[@generic(params= 'T', return= 'T')]
  120. public function add($element) {
  121. $this->elements[]= $element;
  122. $this->size++;
  123. return $element;
  124. }
  125. /**
  126. * Adds an element to this list
  127. *
  128. * @param T[] elements
  129. * @return bool TRUE if the vector was changed as a result of this operation, FALSE if not
  130. * @throws lang.IllegalArgumentException
  131. */
  132. #[@generic(params= 'T[]')]
  133. public function addAll($elements) {
  134. $added= 0;
  135. foreach ($elements as $element) {
  136. $this->elements[]= $element;
  137. $added++;
  138. }
  139. $this->size+= $added;
  140. return $added > 0;
  141. }
  142. /**
  143. * Replaces the element at the specified position in this list with
  144. * the specified element.
  145. *
  146. * @param int index
  147. * @param T element
  148. * @return T the element previously at the specified position.
  149. * @throws lang.IndexOutOfBoundsException
  150. */
  151. #[@generic(params= ', T', return= 'T')]
  152. public function set($index, $element) {
  153. if ($index < 0 || $index >= $this->size) {
  154. throw new IndexOutOfBoundsException('Offset '.$index.' out of bounds');
  155. }
  156. $orig= $this->elements[$index];
  157. $this->elements[$index]= $element;
  158. return $orig;
  159. }
  160. /**
  161. * Returns the element at the specified position in this list.
  162. *
  163. * @param int index
  164. * @return T
  165. * @throws lang.IndexOutOfBoundsException if key does not exist
  166. */
  167. #[@generic(return= 'T')]
  168. public function get($index) {
  169. if ($index < 0 || $index >= $this->size) {
  170. throw new IndexOutOfBoundsException('Offset '.$index.' out of bounds');
  171. }
  172. return $this->elements[$index];
  173. }
  174. /**
  175. * Removes the element at the specified position in this list.
  176. * Shifts any subsequent elements to the left (subtracts one
  177. * from their indices).
  178. *
  179. * @param int index
  180. * @return T the element that was removed from the list
  181. */
  182. #[@generic(return= 'T')]
  183. public function remove($index) {
  184. if ($index < 0 || $index >= $this->size) {
  185. throw new IndexOutOfBoundsException('Offset '.$index.' out of bounds');
  186. }
  187. $orig= $this->elements[$index];
  188. unset($this->elements[$index]);
  189. $this->elements= array_values($this->elements);
  190. $this->size--;
  191. return $orig;
  192. }
  193. /**
  194. * Removes all of the elements from this list. The list will be empty
  195. * after this call returns.
  196. *
  197. */
  198. public function clear() {
  199. $this->elements= array();
  200. $this->size= 0;
  201. }
  202. /**
  203. * Returns an array of this list's elements
  204. *
  205. * @return T[]
  206. */
  207. #[@generic(return= 'T[]')]
  208. public function elements() {
  209. return $this->elements;
  210. }
  211. /**
  212. * Checks if a value exists in this array
  213. *
  214. * @param T element
  215. * @return bool
  216. */
  217. #[@generic(params= 'T')]
  218. public function contains($element) {
  219. for ($i= 0; $i < $this->size; $i++) {
  220. if ($this->elements[$i]->equals($element)) return TRUE;
  221. }
  222. return FALSE;
  223. }
  224. /**
  225. * Searches for the first occurence of the given argument
  226. *
  227. * @param T element
  228. * @return int offset where the element was found or FALSE
  229. */
  230. #[@generic(params= 'T')]
  231. public function indexOf($element) {
  232. for ($i= 0; $i < $this->size; $i++) {
  233. if ($this->elements[$i]->equals($element)) return $i;
  234. }
  235. return FALSE;
  236. }
  237. /**
  238. * Searches for the last occurence of the given argument
  239. *
  240. * @param T element
  241. * @return int offset where the element was found or FALSE
  242. */
  243. #[@generic(params= 'T')]
  244. public function lastIndexOf(Generic $element) {
  245. for ($i= $this->size- 1; $i > -1; $i--) {
  246. if ($this->elements[$i]->equals($element)) return $i;
  247. }
  248. return FALSE;
  249. }
  250. /**
  251. * Creates a string representation of this object
  252. *
  253. * @return string
  254. */
  255. public function toString() {
  256. $r= $this->getClassName().'['.$this->size."]@{\n";
  257. for ($i= 0; $i < $this->size; $i++) {
  258. $r.= ' '.$i.': '.xp::stringOf($this->elements[$i], ' ')."\n";
  259. }
  260. return $r.'}';
  261. }
  262. /**
  263. * Checks if a specified object is equal to this object.
  264. *
  265. * @param lang.Generic collection
  266. * @return bool
  267. */
  268. public function equals($cmp) {
  269. if (!($cmp instanceof self) || $this->size !== $cmp->size || $this->__generic !== $cmp->__generic) return FALSE;
  270. // Compare element by element
  271. for ($i= 0; $i < $this->size; $i++) {
  272. if ($this->elements[$i] instanceof Generic
  273. ? $this->elements[$i]->equals($cmp->elements[$i])
  274. : $this->elements[$i] === $cmp->elements[$i]
  275. ) continue;
  276. return FALSE;
  277. }
  278. return TRUE;
  279. }
  280. }
  281. ?>