File: //usr/share/hhvm/hack/hacklib/containers/helper_traits/hacklib_vectorLike.php
<?php
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace HH {
require_once(__DIR__.SEP.'..'.SEP.'hacklib_iterator.php');
require_once(__DIR__.SEP.'hacklib_constVectorLike.php');
require_once(__DIR__.SEP.'hacklib_commonMutableContainerMethods.php');
/**
* Trait that implements all mutating methods of Vectors.
*/
trait HACKLIB_VectorLike {
use HACKLIB_ConstVectorLike;
use HACKLIB_CommonMutableContainerMethods;
/**
* identical to at, implemented for ArrayAccess
*/
public function &offsetGet($offset) {
$this->hacklib_validateKeyType($offset);
$this->hacklib_validateKeyBounds($offset);
return $this->container[$offset];
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->add($value);
} else {
$this->set($offset, $value);
}
}
public function offsetUnset($offset) {
throw new \RuntimeException(
'Cannot unset an element of a '.get_class($this));
}
/**
* Stores a value into the Vector with the specified key, overwriting the
* previous value associated with the key. If the key is not present,
* an exception is thrown. "$vec->set($k,$v)" is semantically equivalent
* to "$vec[$k] = $v" (except that set() returns the Vector).
*/
public function set($k, $v) {
$this->hacklib_validateKeyType($k);
$this->hacklib_validateKeyBounds($k);
$this->container[$k] = $v;
return $this;
}
public function setAll($it) {
if (is_array($it) || $it instanceof \Traversable) {
foreach ($it as $k => $v) {
$this->set($k, $v);
}
return $this;
} elseif (is_null($it)) {
return $this;
}
throw new \InvalidArgumentException(\sprintf(
'Parameter must be an array or an instance of Traversable, got %s',
is_object($it) ? get_class($it) : gettype($it)
));
}
/**
* Append a copy of a value to the end of the Vector, assigning the next
* available integer key. "$vec->add($v)" is semantically equivalent to
* "$vec[] = $v" (except that add() returns the Vector).
*/
public function add($value) {
$this->hacklib_expireAllIterators();
$this->container[]= $value;
return $this;
}
/**
* Adds the keys of the specified container to this Vector and returns
* the Vector.
*/
public function addAllKeysOf($it) {
if (is_array($it) || $it instanceof \Traversable) {
foreach ($it as $k => $v) {
$this->add($k);
}
return $this;
} elseif (is_null($it)) {
return $this;
}
throw new \InvalidArgumentException(\sprintf(
'Parameter must be a container (array or collection), got %s',
is_object($it) ? get_class($it) : gettype($it)
));
}
/**
* Removes the specified key from this Vector. This will cause elements
* with higher keys to be renumbered.
*/
public function removeKey($k) {
if ($k >= 0 && $k < count($this->container)) {
array_splice($this->container, $k, 1);
$this->hacklib_expireAllIterators();
}
return $this;
}
/**
* Remove the last element of this Vector and return it. This function
* throws an exception if this Vector is empty.
*/
public function pop() {
if (!$this->container) {
throw new \InvalidOperationException('Cannot pop empty '.get_class($this));
}
$this->hacklib_expireAllIterators();
return array_pop($this->container);
}
/**
* Resize this Vector to contain 'sz' elements. If 'sz' is smaller than
* the current size of this Vector, elements are removed from the end of
* this Vector. If 'sz' is greater than the current size of this Vector,
* this Vector is extended by appending as many copies of 'value' as
* needed to reach a size of 'sz' elements.
*/
public function resize($sz, $value) {
if ($sz > self::MAX_SIZE) {
throw new \InvalidArgumentException(
"Parameter sz must be at most ".self::MAX_SIZE."; $sz passed");
}
if ($this->count() === $sz) {
return;
}
$this->hacklib_expireAllIterators();
if ($this->count() > $sz) {
array_splice($this->container, $sz);
} else {
$this->container = array_pad($this->container, $sz, $value);
}
}
/**
* Reserves enough memory to accommodate 'sz' elements. If 'sz' is less
* than or equal to the current capacity of this VectorLike, does nothing.
*/
public function reserve($sz) {
if ($sz < 0) {
throw new \InvalidArgumentException(
'Parameter sz must be a non-negative integer, got '. $sz
);
}
if ($sz > self::MAX_SIZE) {
throw new \InvalidArgumentException(
"Parameter sz must be at most ".self::MAX_SIZE."; $sz passed");
}
if ($sz > $this->count()) {
$this->hacklib_expireAllIterators();
}
// do nothing for now. in the future we can store size separately and
// pad the array
}
/**
* Reverse the elements of this Vector in place.
*/
public function reverse() {
$this->container = array_reverse($this->container);
if ($this->count() > 1) {
$this->hacklib_expireAllIterators();
}
}
/**
* Splice this Vector in place. This function provides the functionality
* of array_splice() for Vectors. Note that this function modifies this
* Vector in place.
*/
public function splice($offset, $len = null) {
if (!is_int($offset)) {
throw new \InvalidArgumentException(\sprintf(
'Parameter offset must be an integer, got %s',
is_object($object) ? get_class($object) : gettype($object)
));
}
if (!is_null($len) && !is_int($len)) {
throw new \InvalidArgumentException(\sprintf(
'Parameter len must be null or an integer, got %s',
is_object($len) ? get_class($len) : gettype($len)
));
}
$removed = is_null($len) ? array_splice($this->container, $offset) :
array_splice($this->container, $offset, $len);
if (count($removed) > 0) {
$this->hacklib_expireAllIterators();
}
}
/**
* Shuffles the values of the Vector randomly in place.
*/
public function shuffle() {
shuffle($this->container);
if ($this->count() > 1) {
$this->hacklib_expireAllIterators();
}
}
protected function hacklib_isImmutable() {
return false;
}
}
}