Last active
September 24, 2021 12:07
-
-
Save deathlyfrantic/d6cb7e95e83a83cf111bef5876d5630d to your computer and use it in GitHub Desktop.
php object implementation of a standard list (not hashtable)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function vector($arg = null): Vector { | |
return new Vector($arg); | |
} | |
function is_vector($obj): bool { | |
return $obj instanceof Vector; | |
} | |
class AttributeError extends Exception {} | |
class Vector implements Countable, ArrayAccess, Iterator { | |
protected $items = []; | |
protected $cursor = 0; | |
public function __construct(...$args) { | |
$this->items = $args; | |
} | |
public function __get($name) { | |
switch ($name) { | |
case "__items__": | |
return $this->items; | |
case "length": | |
return $this->count(); | |
default: | |
throw new AttributeError("Vector has no attribute called $name."); | |
} | |
} | |
protected function decrementCursor() { | |
if ($this->cursor > 0) { | |
$cursor--; | |
} | |
} | |
public function current() { | |
return $this->items[$this->cursor]; | |
} | |
public function key(): int { | |
return $this->cursor; | |
} | |
public function next() { | |
$this->cursor++; | |
} | |
public function rewind() { | |
$this->cursor = 0; | |
} | |
public function valid(): bool { | |
return $this->offsetExists($this->cursor); | |
} | |
public function offsetExists($idx): bool { | |
if (!is_int($idx)) { | |
throw new AttributeError("Vector keys must be integers."); | |
} | |
return $idx < ($this->count() - 1); | |
} | |
protected function ensureIndexInRange($idx) { | |
if (!$this->offsetExists($idx)) { | |
throw new AttributeError("$idx is outside the range [{$this->count()}] of this vector."); | |
} | |
} | |
public function offsetGet($idx) { | |
$this->ensureIndexInRange($idx); | |
return $this->items[$idx]; | |
} | |
public function offsetSet($idx, $val) { | |
$this->ensureIndexInRange($idx); | |
$this->items[$idx] = $val; | |
} | |
public function offsetUnset($idx) { | |
$this->ensureIndexInRange($idx); | |
$this->splice($idx, 1); | |
if ($this->cursor === $idx) { | |
$this->decrementCursor(); | |
} | |
} | |
public function count(): int { | |
return count($this->items); | |
} | |
public function push(...$args) { | |
return array_push($this->items, ...$args); | |
} | |
public function pop() { | |
if ($this->cursor === $this->count() - 1) { | |
$this->decrementCursor(); | |
} | |
return array_pop($this->items); | |
} | |
public function shift() { | |
if ($this->cursor !== 0) { | |
$this->decrementCursor(); | |
} | |
return array_shift($this->items); | |
} | |
public function unshift(...$args) { | |
return array_unshift($this->items, ...$args); | |
} | |
public function slice(int $offset, $length = null): self { | |
return new self(array_slice($this->items, $offset, $length)); | |
} | |
public function splice(int $offset, int $length = null, $replacement = []): self { | |
if (is_null($length)) { | |
$length = $this->count(); | |
} | |
return new self(array_splice($this->items, $offset, $length, $replacement)); | |
} | |
public function map(callable $cb): self { | |
return new self(array_map($cb, $this->items)); | |
} | |
public function forEach(callable $cb) { | |
array_walk($this->items, $cb); | |
} | |
public function filter(callable $cb): self { | |
return new self(array_filter($this->items, $cb)); | |
} | |
public function some(callable $cb): bool { | |
foreach ($this->items as $item) { | |
if ($cb($item)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
public function every(callable $cb): bool { | |
foreach ($this->items as $item) { | |
if (!$cb($item)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
public function includes($val): bool { | |
return in_array($val, $this->items); | |
} | |
public function join($glue = " "): string { | |
return implode($glue, $this->items); | |
} | |
public function reduce(callable $cb, $initial = null) { | |
return array_reduce($this->items, $cb, $initial); | |
} | |
public function sort(callable $cb = null): self { | |
if (is_null($cb)) { | |
sort($this->items); | |
} else { | |
usort($this->items, $cb); | |
} | |
return $this; | |
} | |
public function reverse(): self { | |
$this->items = array_reverse($this->items); | |
return $this; | |
} | |
public function indexOf($val): int { | |
$loc = array_search($val, $this->items); | |
return ($loc !== false) ? $loc : -1; | |
} | |
public function unique(): self { | |
return new self(array_unique($this->items)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment