Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AccessTrait added and used in ArrayView. #10

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Interfaces/ArrayViewInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ public function count(): int;

/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return bool
*/
public function offsetExists($offset): bool;

/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return T|array<T>
*/
#[\ReturnTypeWillChange]
Expand All @@ -99,12 +101,14 @@ public function offsetGet($offset);
/**
* @param numeric|string|ArraySelectorInterface $offset
* @param T|array<T>|ArrayViewInterface<T> $value
*
* @return void
*/
public function offsetSet($offset, $value): void;

/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return void
*/
public function offsetUnset($offset): void;
Expand Down
126 changes: 126 additions & 0 deletions src/Traits/ArrayViewAccessTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

namespace Smoren\ArrayView\Traits;

use Smoren\ArrayView\Exceptions\IndexError;
use Smoren\ArrayView\Exceptions\KeyError;
use Smoren\ArrayView\Exceptions\NotSupportedError;
use Smoren\ArrayView\Exceptions\ReadonlyError;
use Smoren\ArrayView\Interfaces\ArraySelectorInterface;
use Smoren\ArrayView\Interfaces\ArrayViewInterface;
use Smoren\ArrayView\Selectors\SliceSelector;
use Smoren\ArrayView\Structs\Slice;

/**
* @template T
*/
trait ArrayViewAccessTrait
{
/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return bool
*
* {@inheritDoc}
*/
public function offsetExists($offset): bool
{
if (\is_numeric($offset)) {
return $this->numericOffsetExists($offset);
}

if (\is_string($offset) && Slice::isSlice($offset)) {
return true;
}

if ($offset instanceof ArraySelectorInterface) {
return true;
}

return false;
}

/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return T|array<T>
*
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
/** @var mixed $offset */
if (\is_numeric($offset)) {
if (!$this->numericOffsetExists($offset)) {
throw new IndexError("Index {$offset} is out of range.");
}
return $this->source[$this->convertIndex(\intval($offset))];
}

if (\is_string($offset) && Slice::isSlice($offset)) {
return $this->subview(new SliceSelector($offset))->toArray();
}

if ($offset instanceof ArraySelectorInterface) {
return $this->subview($offset)->toArray();
}

$strOffset = \is_scalar($offset) ? \strval($offset) : \gettype($offset);
throw new KeyError("Invalid key: \"{$strOffset}\".");
}

/**
* @param numeric|string|ArraySelectorInterface $offset
* @param T|array<T>|ArrayViewInterface<T> $value
*
* @return void
*
* {@inheritDoc}
*/
public function offsetSet($offset, $value): void
{
/** @var mixed $offset */
if ($this->isReadonly()) {
throw new ReadonlyError("Cannot modify a readonly view.");
}

if (\is_numeric($offset)) {
if (!$this->numericOffsetExists($offset)) {
throw new IndexError("Index {$offset} is out of range.");
}

// @phpstan-ignore-next-line
$this->source[$this->convertIndex(\intval($offset))] = $value;
return;
}

if (\is_string($offset) && Slice::isSlice($offset)) {
/** @var array<T>|ArrayViewInterface<T> $value */
$this->subview(new SliceSelector($offset))->set($value);
return;
}

if ($offset instanceof ArraySelectorInterface) {
$this->subview($offset)->set($value);
return;
}

$strOffset = \is_scalar($offset) ? \strval($offset) : \gettype($offset);
throw new KeyError("Invalid key: \"{$strOffset}\".");
}

/**
* @param numeric|string|ArraySelectorInterface $offset
*
* @return void
*
* @throws NotSupportedError
*
* {@inheritDoc}
*/
public function offsetUnset($offset): void
{
throw new NotSupportedError();
}
}
116 changes: 16 additions & 100 deletions src/Views/ArrayView.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@
namespace Smoren\ArrayView\Views;

use Smoren\ArrayView\Exceptions\IndexError;
use Smoren\ArrayView\Exceptions\KeyError;
use Smoren\ArrayView\Exceptions\SizeError;
use Smoren\ArrayView\Exceptions\NotSupportedError;
use Smoren\ArrayView\Exceptions\ReadonlyError;
use Smoren\ArrayView\Exceptions\ValueError;
use Smoren\ArrayView\Interfaces\ArraySelectorInterface;
use Smoren\ArrayView\Interfaces\ArrayViewInterface;
use Smoren\ArrayView\Interfaces\MaskSelectorInterface;
use Smoren\ArrayView\Selectors\MaskSelector;
use Smoren\ArrayView\Selectors\SliceSelector;
use Smoren\ArrayView\Structs\Slice;
use Smoren\ArrayView\Traits\ArrayViewAccessTrait;
use Smoren\ArrayView\Util;

/**
Expand All @@ -25,6 +22,11 @@
*/
class ArrayView implements ArrayViewInterface
{
/**
* @use ArrayViewAccessTrait<T>
*/
use ArrayViewAccessTrait;

/**
* @var array<T>|ArrayViewInterface<T>
*/
Expand Down Expand Up @@ -124,7 +126,8 @@ public function subview($selector, bool $readonly = null): ArrayViewInterface
*/
public function apply(callable $mapper): self
{
for ($i = 0; $i < \count($this); $i++) {
$size = \count($this);
for ($i = 0; $i < $size; $i++) {
/** @var T $item */
$item = $this[$i];
$this[$i] = $mapper($item, $i);
Expand All @@ -151,7 +154,8 @@ public function applyWith($data, callable $mapper): self

$dataView = ArrayView::toView($data);

for ($i = 0; $i < \count($this); $i++) {
$size = \count($this);
for ($i = 0; $i < $size; $i++) {
/** @var T $lhs */
$lhs = $this[$i];
/** @var U $rhs */
Expand All @@ -170,7 +174,8 @@ public function applyWith($data, callable $mapper): self
public function set($newValues): self
{
if (!\is_array($newValues) && !($newValues instanceof ArrayViewInterface)) {
for ($i = 0; $i < \count($this); $i++) {
$size = \count($this);
for ($i = 0; $i < $size; $i++) {
$this[$i] = $newValues;
}
return $this;
Expand All @@ -183,7 +188,8 @@ public function set($newValues): self

$newValuesView = ArrayView::toView($newValues);

for ($i = 0; $i < \count($this); $i++) {
$size = \count($this);
for ($i = 0; $i < $size; $i++) {
$this[$i] = $newValuesView[$i];
}

Expand All @@ -195,7 +201,8 @@ public function set($newValues): self
*/
public function getIterator(): \Generator
{
for ($i = 0; $i < \count($this); $i++) {
$size = \count($this);
for ($i = 0; $i < $size; $i++) {
/** @var T $item */
$item = $this[$i];
yield $item;
Expand All @@ -210,97 +217,6 @@ public function isReadonly(): bool
return $this->readonly;
}

/**
* {@inheritDoc}
*/
public function offsetExists($offset): bool
{
if (\is_numeric($offset)) {
return $this->numericOffsetExists($offset);
}

if (\is_string($offset) && Slice::isSlice($offset)) {
return true;
}

if ($offset instanceof ArraySelectorInterface) {
return true;
}

return false;
}

/**
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
/** @var mixed $offset */
if (\is_numeric($offset)) {
if (!$this->numericOffsetExists($offset)) {
throw new IndexError("Index {$offset} is out of range.");
}
return $this->source[$this->convertIndex(\intval($offset))];
}

if (\is_string($offset) && Slice::isSlice($offset)) {
return $this->subview(new SliceSelector($offset))->toArray();
}

if ($offset instanceof ArraySelectorInterface) {
return $this->subview($offset)->toArray();
}

$strOffset = \is_scalar($offset) ? \strval($offset) : \gettype($offset);
throw new KeyError("Invalid key: \"{$strOffset}\".");
}

/**
* {@inheritDoc}
*/
public function offsetSet($offset, $value): void
{
/** @var mixed $offset */
if ($this->isReadonly()) {
throw new ReadonlyError("Cannot modify a readonly view.");
}

if (\is_numeric($offset)) {
if (!$this->numericOffsetExists($offset)) {
throw new IndexError("Index {$offset} is out of range.");
}

// @phpstan-ignore-next-line
$this->source[$this->convertIndex(\intval($offset))] = $value;
return;
}

if (\is_string($offset) && Slice::isSlice($offset)) {
/** @var array<T>|ArrayViewInterface<T> $value */
$this->subview(new SliceSelector($offset))->set($value);
return;
}

if ($offset instanceof ArraySelectorInterface) {
$this->subview($offset)->set($value);
return;
}

$strOffset = \is_scalar($offset) ? \strval($offset) : \gettype($offset);
throw new KeyError("Invalid key: \"{$strOffset}\".");
}

/**
* @throws NotSupportedError
*
* {@inheritDoc}
*/
public function offsetUnset($offset): void
{
throw new NotSupportedError();
}

/**
* {@inheritDoc}
*/
Expand Down
Loading