File: //usr/share/hhvm/hack/hacklib/containers/helper_traits/hacklib_commonContainerMethods.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.'collections.ns.php');
/**
* Methods that cane be implemented across all containers in one place. Either
* these methods are implemented to actually locally account for differences
* in these implementations, or is entirely common.
*/
trait HACKLIB_CommonContainerMethods {
/**
* This function is intended to be private. Do not call this directly.
*/
public function __hacklib_getContainer() {
return $this->container;
}
// This is used by some of the static creation methods to bypass
// unnecessary iteration.
private function hacklib_setContainer($container) {
$this->container = $container;
}
public function __get($prop) {
throw new \InvalidOperationException(
'Cannot access a property on a collection');
}
public function __set($prop, $value) {
throw new \InvalidOperationException(
'Cannot access a property on a collection');
}
public function __isset($prop) {
return false;
}
public function __unset($prop) {
throw new \InvalidOperationException(
'Cannot access a property on a collection');
}
public function hacklib_equals($other) {
static $baseClass = array(
'HH\Pair' => 'HH\Pair',
'HH\Vector' => 'HH\Vector',
'HH\ImmVector' => 'HH\Vector',
'HH\Set' => 'HH\Set',
'HH\ImmSet' => 'HH\Set',
'HH\Map' => 'HH\Map',
'HH\ImmMap' => 'HH\Map'
);
if (is_bool($other)) {
return !($this->isEmpty()) == $other;
}
if (!is_object($other)) {
return false;
}
// We know that our class is in this list.
if ($baseClass[get_class($this)] != $baseClass[get_class($other)]) {
return false;
}
$otherContainer = $other->__hacklib_getContainer();
if (count($this->container) != count($otherContainer)) {
return false;
}
foreach ($this->container as $key => $value) {
if (
!array_key_exists($key, $otherContainer) ||
hacklib_not_equals($value, $otherContainer[$key])
) {
return false;
}
}
return true;
}
private static function hacklib_new_instance() {
return new self();
}
// creates a new object of the same type. useful to implement
// methods like map to operate in a general manner
// the second optional option returns an ImmVector from a pair when
// the method warrants it
private function hacklib_create_new($it, $replacementForPair = null) {
$obj = static::hacklib_new_instance();
$obj->hacklib_init_t($it);
return ($obj instanceof Pair && $replacementForPair) ?
new $replacementForPair($obj) : $obj;
}
private static function hacklib_fnFromCallable($callable) {
if (is_callable($callable)) {
return function ($x) use ($callable) {
return call_user_func($callable, $x);
};
} else {
throw new \InvalidArgumentException(
'Parameter must be a valid callback');
}
}
private static function hacklib_fn2FromCallable($callable) {
if (is_callable($callable)) {
return function ($x, $y) use ($callable) {
return call_user_func($callable, $x, $y);
};
} else {
throw new \InvalidArgumentException(
'Parameter must be a valid callback');
}
}
public function lazy() {
return new \LazyKeyedIterableView($this);
}
public function toVector() {
return new Vector($this);
}
public function toImmVector() {
return new ImmVector($this);
}
public function toSet() {
return new Set($this);
}
public function toImmSet() {
return new ImmSet($this);
}
public function toMap() {
return new Map($this);
}
public function toImmMap() {
return new ImmMap($this);
}
public function zip($traversable) {
if (is_array($traversable)) {
$traversable = new ImmVector($traversable);
}
if ($traversable instanceof \Traversable) {
return $this->hacklib_create_new(
new \LazyZipIterable($this, $traversable), "\\HH\\ImmVector");
} else {
throw new \InvalidArgumentException(
'Parameter must be an array or an instance of Traversable');
}
}
public function filter($fn) {
return $this->hacklib_create_new(
new \LazyFilterIterable($this, $fn), "\\HH\\ImmVector");
}
public function map($fn) {
return $this->hacklib_map($fn);
}
private function hacklib_map($callable) {
$fn = self::hacklib_fnFromCallable($callable);
return $this->hacklib_create_new(
new \LazyMapIterable($this, $fn));
}
/**
* Returns an array whose values are this containers's keys.
*/
public function toKeysArray() {
return array_map(function ($k) {
return static::hacklib_unmakeKey($k);
}, array_keys($this->container));
}
public function toValuesArray() {
return array_values($this->container);
}
public function mapWithKey($callable) {
$fn = self::hacklib_fn2FromCallable($callable);
return $this->hacklib_create_new(
new \LazyMapWithKeyIterable($this, $fn), "\\HH\\ImmVector");
}
public function filterWithKey($callable) {
$fn = self::hacklib_fn2FromCallable($callable);
return $this->hacklib_create_new(
new \LazyFilterWithKeyIterable($this, $fn), "\\HH\\ImmVector");
}
public function slice($start, $len) {
if ($start < 0) {
throw new \InvalidArgumentException(
'Parameter start must be a non-negative integer');
}
if ($len < 0) {
throw new \InvalidArgumentException(
'Parameter len must be a non-negative integer');
}
return $this->hacklib_create_new(
new \LazySliceIterable($this, $start, $len), "\\HH\\ImmVector");
}
// Note that pairs return a Vector despite the documentation saying
// that they return an immVector
public function take($n) {
if (!is_int($n)) {
throw new \InvalidArgumentException(
'Parameter n must be an integer');
}
return $this->hacklib_create_new(
new \LazyTakeIterable($this, $n), "\\HH\\Vector");
}
// Note that pairs return a Vector despite the documentation saying
// that they return an immVector
public function takeWhile($callable) {
$fn = self::hacklib_fnFromCallable($callable);
return $this->hacklib_create_new(
new \LazyTakeWhileIterable($this, $fn), "\\HH\\Vector");
}
// Note that pairs return a Vector despite the documentation saying
// that they return an immVector
public function skip($n) {
if (!is_int($n)) {
throw new \InvalidArgumentException(
'Parameter n must be an integer');
}
return $this->hacklib_create_new(
new \LazySkipIterable($this, $n), "\\HH\\Vector");
}
// Note that pairs return a Vector despite the documentation saying
// that they return an immVector
public function skipWhile($callable) {
$fn = self::hacklib_fnFromCallable($callable);
return $this->hacklib_create_new(
new \LazySkipWhileIterable($this, $fn), "\\HH\\Vector");
}
public function firstKey() {
return static::hacklib_unmakeKey(key($this->container));
}
public function lastKey() {
$last_item = array_slice($this->container, -1, 1, TRUE);
return static::hacklib_unmakeKey(key($last_item));
}
public function firstValue() {
if ($this->isEmpty()) {
return null;
}
return current($this->container);
}
public function lastValue() {
if ($this->isEmpty()) {
return null;
}
$last_item = array_slice($this->container, -1, 1);
return current($last_item);
}
protected abstract function hacklib_isImmutable();
}
}