File: //usr/share/hhvm/hack/hacklib/containers/helper_traits/hacklib_constMapLike.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_commonContainerMethods.php');
trait HACKLIB_ConstMapLike {
use HACKLIB_iteratable;
use HACKLIB_CommonContainerMethods;
//this is where we actually store elements
private $container;
private static function hacklib_makeKey($k) {
if (is_int($k)) {
return $k;
}
if (is_string($k)) {
return "_".$k;
}
else throw new \InvalidArgumentException(
'Only integer keys and string keys may be used with Maps');
}
private static function hacklib_unmakeKey($k_actual) {
if (is_string($k_actual)) {
//cast to string because substr returns false if $k_actual = "_"
return (string) substr($k_actual, 1);
} else {
return $k_actual;
}
}
protected function hacklib_init_t($it = null) {
if (is_array($it) || $it instanceof \Traversable) {
$a = array();
foreach ($it as $k => $v) {
$k_actual = self::hacklib_makeKey($k);
$a[$k_actual] = $v;
}
$this->container = $a;
} elseif (is_null($it)) {
$this->container = array();
} else {
throw new \InvalidArgumentException(
'Parameter must be an array or an instance of Traversable');
}
}
protected function hacklib_init_kv(array $keys, array $values) {
if (count($keys) !== count($values)) {
throw new \InvalidArgumentException(
get_class($this)." requires an equal number of keys and values.".
"Received ".count($keys)." keys and ".count($values)." values ");
}
$a = array();
foreach ($keys as $i => $k) {
$k_actual = self::hacklib_makeKey($k);
$a[$k_actual] = $values[$i];
}
$this->container = $a;
}
/**
* Checks if the key is present in the map.
* Returns the result AND the converted key for further
* uses.
*/
protected function hacklib_containsKey($k) {
$k_actual = self::hacklib_makeKey($k);
return array(array_key_exists($k_actual, $this->container), $k_actual);
}
/**
* Returns true if the MapLike is empty, false otherwise.
*/
public function isEmpty() {
return $this->count() == 0;
}
/**
* Returns the number of key/value pairs in the MapLike.
*/
public function count() {
return count($this->container);
}
/**
* Returns the value at the specified key. If the key is not present,
* an exception is thrown. "$v = $m->at($k)" is semantically equivalent
* to "$v = $m[$k]".
*/
public function at($k) {
return $this[$k];
}
/**
* Returns the value at the specified key. If the key is not present,
* null is returned.
*/
public function get($k) {
list($contained, $k_actual) = $this->hacklib_containsKey($k);
if ($contained) {
return $this->container[$k_actual];
}
return null;
}
/**
* Returns true if the specified key is present in the ImmMap, false
* otherwise.
*/
public function contains($k) {
return $this->hacklib_containsKey($k)[0];
}
public function containsKey($k) {
return $this->hacklib_containsKey($k)[0];
}
/**
* identical to containsKey, implemented for ArrayAccess
*/
public function offsetExists($offset) {
return $this->hacklib_containsKey($offset)[0] &&
$this->at($offset) !== null;
}
/**
* Returns an array containing the key/value pairs from this MapLike
*/
public function toArray() {
$arr = array();
foreach ($this as $k => $v) {
if (isset($arr[$k])) {
$type = join('', array_slice(explode('\\', __CLASS__), -1));
trigger_error("$type::toArray() for a ".lcfirst($type).
" containing both int($k) and string('$k')", E_USER_WARNING);
}
$arr[$k]= $v;
}
return $arr;
}
/**
* Returns a new Map with the keys in this Map not in $traversable
*/
public function differenceByKey($it) {
if ($it instanceof \Traversable) {
$a = $this->container;
foreach ($it as $k => $v) {
$k_actual = self::hacklib_makeKey($k);
unset($a[$k_actual]);
}
$newObj = static::hacklib_new_instance();
$newObj->hacklib_setContainer($a);
return $newObj;
} else {
throw new \InvalidArgumentException(
'Parameter it must be an instance of Iterable');
}
}
public function items() {
return new \LazyKVZipIterable($this);
}
public static function fromItems($it) {
if (is_array($it) || $it instanceof \Traversable) {
$a = array();
foreach ($it as $v) {
if ($v instanceof Pair) {
$k_actual = self::hacklib_makeKey($v[0]);
$a[$k_actual] = $v[1];
} else {
throw new \InvalidArgumentException(
'Parameter must be an array or an instance of Iterable<Pair>');
}
}
$m = new self();
$m->hacklib_setContainer($a);
return $m;
} elseif (is_null($it)) {
return new self();
} else {
throw new \InvalidArgumentException(
'Parameter must be an array or an instance of Traversable');
}
}
/**
* used by HACKLIB_iteratable.
* returns the key and value at given index
*/
protected function hacklib_getKeyAndValue($i) {
$keyAndValue = array_slice($this->container, $i, 1, true);
return array(
self::hacklib_unmakeKey(key($keyAndValue)),
current($keyAndValue)
);
}
/**
* used by HACKLIB_iteratable.
* returns an iterator of the appropriate type
*/
protected function hacklib_createNewIterator() {
return new \MapIterator();
}
public function __debugInfo() {
$a = array();
foreach ($this->container as $key => $value) {
$k_actual = self::hacklib_unmakeKey($key);
$a[$k_actual] = $value;
}
return $a;
}
}
}