chdemko/php-sorted-collections

View on GitHub
src/SortedCollection/SubSet.php

Summary

Maintainability
B
5 hrs
Test Coverage
<?php

/**
 * chdemko\SortedCollection\SubSet class
 *
 * @author    Christophe Demko <chdemko@gmail.com>
 * @copyright Copyright (C) 2012-2023 Christophe Demko. All rights reserved.
 *
 * @license BSD 3-Clause License
 *
 * This file is part of the php-sorted-collections package https://github.com/chdemko/php-sorted-collections
 */

// Declare chdemko\SortedCollection namespace
namespace chdemko\SortedCollection;

/**
 * Sub set
 *
 * @package    SortedCollection
 * @subpackage Set
 *
 * @since 1.0.0
 *
 * @property      mixed      $from           The from element
 * @property      boolean    $fromInclusive  The from inclusive flag
 * @property      mixed      $to             The to element
 * @property      boolean    $toInclusive    The to inclusive flag
 * @property-read callable   $comparator     The element comparison function
 * @property-read mixed      $first          The first element of the set
 * @property-read mixed      $last           The last element of the set
 * @property-read integer    $count          The number of elements in the set
 * @property-read SortedSet  $set            The underlying set
 */
class SubSet extends AbstractSet
{
    /**
     * When the from or to value is unused
     *
     * @since 1.0.0
     */
    private const UNUSED = 0;

    /**
     * When the from or to value is inclusive
     *
     * @since 1.0.0
     */
    private const INCLUSIVE = 1;

    /**
     * When the from or to value is exclusive
     *
     * @since 1.0.0
     */
    private const EXCLUSIVE = 2;

    /**
     * @var SortedSet  Internal set
     *
     * @since 1.0.0
     */
    private $set;

    /**
     * Magic get method
     *
     * @param string $property The property
     *
     * @return mixed The value associated to the property
     *
     * @since 1.0.0
     */
    public function __get($property)
    {
        switch ($property) {
            case 'from':
                return $this->getMap()->fromKey;
            case 'to':
                return $this->getMap()->toKey;
            case 'fromInclusive':
                return $this->getMap()->fromInclusive;
            case 'toInclusive':
                return $this->getMap()->toInclusive;
            case 'set':
                return $this->set;
            default:
                return parent::__get($property);
        }
    }

    /**
     * Magic set method
     *
     * @param string $property The property
     * @param mixed  $value    The new value
     *
     * @throws RuntimeException If the property does not exist
     *
     * @return void
     *
     * @since 1.0.0
     */
    public function __set($property, $value)
    {
        switch ($property) {
            case 'from':
                $this->getMap()->fromKey = $value;
                break;
            case 'to':
                $this->getMap()->toKey = $value;
                break;
            case 'fromInclusive':
                $this->getMap()->fromInclusive = $value;
                break;
            case 'toInclusive':
                $this->getMap()->toInclusive = $value;
                break;
            default:
                throw new \RuntimeException('Undefined property');
        }
    }

    /**
     * Magic unset method
     *
     * @param string $property The property
     *
     * @throws RuntimeException If the property does not exist
     *
     * @return void
     *
     * @since 1.0.0
     */
    public function __unset($property)
    {
        switch ($property) {
            case 'from':
                unset($this->getMap()->fromKey);
                break;
            case 'to':
                unset($this->getMap()->toKey);
                break;
            case 'fromInclusive':
                unset($this->getMap()->fromInclusive);
                break;
            case 'toInclusive':
                unset($this->getMap()->toInclusive);
                break;
            default:
                throw new \RuntimeException('Undefined property');
        }
    }

    /**
     * Magic isset method
     *
     * @param string $property The property
     *
     * @return boolean
     *
     * @since 1.0.0
     */
    public function __isset($property)
    {
        switch ($property) {
            case 'from':
                return isset($this->getMap()->fromKey);
            case 'to':
                return isset($this->getMap()->toKey);
            case 'fromInclusive':
                return isset($this->getMap()->fromInclusive);
            case 'toInclusive':
                return isset($this->getMap()->toInclusive);
            default:
                return false;
        }
    }

    /**
     * Constructor
     *
     * @param SortedSet $set        Internal set
     * @param mixed     $from       The from element
     * @param integer   $fromOption The option for from (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
     * @param mixed     $to         The to element
     * @param integer   $toOption   The option for to (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
     *
     * @since 1.0.0
     */
    protected function __construct(SortedSet $set, $from, $fromOption, $to, $toOption)
    {
        if ($fromOption == self::UNUSED) {
            if ($toOption == self::UNUSED) {
                $this->setMap(SubMap::view($set->getMap()));
            } else {
                $this->setMap(SubMap::head($set->getMap(), $to, $toOption == self::INCLUSIVE));
            }
        } elseif ($toOption == self::UNUSED) {
            $this->setMap(SubMap::tail($set->getMap(), $from, $fromOption == self::INCLUSIVE));
        } else {
            $this->setMap(
                SubMap::create($set->getMap(), $from, $to, $fromOption == self::INCLUSIVE, $toOption == self::INCLUSIVE)
            );
        }

        $this->set = $set;
    }

    /**
     * Create
     *
     * @param SortedSet $set           Internal set
     * @param mixed     $from          The from element
     * @param mixed     $to            The to element
     * @param boolean   $fromInclusive The inclusive flag for from
     * @param boolean   $toInclusive   The inclusive flag for to
     *
     * @return SubSet A new sub set
     *
     * @since 1.0.0
     */
    public static function create(SortedSet $set, $from, $to, $fromInclusive = true, $toInclusive = false)
    {
        return new static(
            $set,
            $from,
            $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
            $to,
            $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
        );
    }

    /**
     * Head
     *
     * @param SortedSet $set         Internal set
     * @param mixed     $to          The to element
     * @param boolean   $toInclusive The inclusive flag for to
     *
     * @return SubSet A new head set
     *
     * @since 1.0.0
     */
    public static function head(SortedSet $set, $to, $toInclusive = false)
    {
        return new static($set, null, self::UNUSED, $to, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
    }

    /**
     * Tail
     *
     * @param SortedSet $set           Internal set
     * @param mixed     $from          The from element
     * @param boolean   $fromInclusive The inclusive flag for from
     *
     * @return SubSet A new tail set
     *
     * @since 1.0.0
     */
    public static function tail(SortedSet $set, $from, $fromInclusive = true)
    {
        return new static($set, $from, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
    }

    /**
     * View
     *
     * @param SortedSet $set Internal set
     *
     * @return SubSet A new sub set
     *
     * @since 1.0.0
     */
    public static function view(SortedSet $set)
    {
        return new static($set, null, self::UNUSED, null, self::UNUSED);
    }

    /**
     * Serialize the object
     *
     * @return array Array of values
     *
     * @since 1.0.0
     */
    public function jsonSerialize(): array
    {
        if (isset($this->from)) {
            if (isset($this->to)) {
                return array(
                    'SubSet' => array(
                        'set' => $this->set->jsonSerialize(),
                        'from' => $this->from,
                        'fromInclusive' => $this->fromInclusive,
                        'to' => $this->to,
                        'toInclusive' => $this->toInclusive,
                    )
                );
            } else {
                return array(
                    'TailSet' => array(
                        'set' => $this->set->jsonSerialize(),
                        'from' => $this->from,
                        'fromInclusive' => $this->fromInclusive,
                    )
                );
            }
        } else {
            if (isset($this->to)) {
                return array(
                    'HeadSet' => array(
                        'set' => $this->set->jsonSerialize(),
                        'to' => $this->to,
                        'toInclusive' => $this->toInclusive,
                    )
                );
            } else {
                return array(
                    'ViewSet' => array(
                        'set' => $this->set->jsonSerialize(),
                    )
                );
            }
        }
    }
}