Advertisement
fruffl

LIFO/LILO/FIFO/FILO

Mar 8th, 2012
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 15.97 KB | None | 0 0
  1. <?PHP
  2.     /**
  3.      * ILLI
  4.      *
  5.      * @category   ILLI_System
  6.      * @package    ILLI
  7.      * @subpackage System
  8.      * @link       http://illi.be
  9.      * @license    http://l.illi.be
  10.      * @copyright  ILLI Conference
  11.      */
  12.     NAMESPACE ILLI\System;
  13.  
  14.     /**
  15.      * ILLI System Abstract Prototype Array
  16.      *
  17.      * Basic Array: index : offset : value
  18.      * support for LIFO, LILO, FIFO, FILO
  19.      *
  20.      * @category    ILLI_System
  21.      * @package ILLI
  22.      * @subpackage  System
  23.      * @namespace   ILLI\System
  24.      * @link    http://illi.be
  25.      * @license http://l.illi.be
  26.      * @copyright   ILLI Conference
  27.      * @since   2.0.0-1
  28.      * @version 2.0.0-1
  29.      * @abstract
  30.      * @todo    flags/it-modes
  31.      */
  32.     ABSTRACT CLASS ProtoArray EXTENDS Proto IMPLEMENTS iCountable, iArrayAccess, iSerializable, iIterator
  33.     {
  34.         /**
  35.          * iterator modes
  36.          * [LIFO 0] [LILO 4] [FIFO 2] [FILO 6] [default: LIFO]
  37.          * @var int
  38.          */
  39.         const IT_MODE_FI        = 0x00000002;
  40.        
  41.         /**
  42.          * @see IT_MODE_FI
  43.          * @var int
  44.          */
  45.         const IT_MODE_LO        = 0x00000004;
  46.        
  47.         /**
  48.          * typedef values: if set, strict type for values
  49.          * [mixed: 0] [safe: 32] [default: 0]
  50.          * @var int
  51.          */
  52.         const VALUE_TYPE_SAFE       = 0x00000020;
  53.        
  54.         /**
  55.          * typedef: zerobased or assoc array
  56.          * [array: 0] [assoc: 256] [default: 0]
  57.          * @var int
  58.          */
  59.         const ARRAY_MODE_ASSOC      = 0x00000100;
  60.        
  61.         /**
  62.          * array_merge: order of priority
  63.          * [new before existing: 0] [existing before new: 1024] [default: 0]
  64.          * @var int
  65.          */
  66.         const PERM_ARRAY_AS_SUPER   = 0x00000400;
  67.        
  68.         /**
  69.          * serializable private properties
  70.          * @var array
  71.          * @static
  72.          */
  73.         private static $__serializable  =
  74.                         [
  75.                             '__array',
  76.                             '__offsets',
  77.                             '__indexes',
  78.                             '__bitFlag'
  79.                         ];
  80.        
  81.         /**
  82.          * bitflag
  83.          * @var ProtoFlag
  84.          * @see IT_MODE_FI
  85.          * @see IT_MODE_LO
  86.          * @see VALUE_TYPE_SAFE
  87.          * @see ARRAY_MODE_ASSOC
  88.          * @see PERM_ARRAY_AS_SUPER
  89.          */
  90.         private $__FLAG         = NULL;
  91.        
  92.         /**
  93.          * data array
  94.          * @var array
  95.          */
  96.         private $__array        = [];
  97.        
  98.         /**
  99.          * offset cache: array keys from $__array
  100.          * @var array
  101.          */
  102.         private $__offsets      = [];
  103.        
  104.         /**
  105.          * index cache: flipped $__offsets
  106.          * @var array
  107.          */
  108.         private $__indexes      = [];
  109.        
  110.         /**
  111.          * iterator index
  112.          * @var int32
  113.          */
  114.         private $__itIndex      = 0;
  115.        
  116.         /**
  117.          * last insert offset
  118.          */
  119.         private $__lastInsertOffset = NULL;
  120.        
  121.         /**
  122.          * last changed offset
  123.          */
  124.         private $__lastChangedOffset    = NULL;
  125.        
  126.         /**
  127.          * @param array|ProtoArray $array initial value
  128.          */
  129.         public function __construct($array = [], ProtoFlag $flag = NULL)
  130.         {
  131.             if(NULL === $array)
  132.                 $array = [];
  133.                
  134.             if($array instanceOf ProtoArray
  135.             || $array instanceOf ProtoArraySegment)
  136.                 $array = $array->toArray();
  137.            
  138.             if(FALSE === is_array($array))
  139.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_ARRAY);
  140.                
  141.             $this->__FLAG = (NULL !== $flag)
  142.                 ? $flag
  143.                 : new ProtoFlag;
  144.            
  145.             self::$__tSerializableProperties    = self::$__serializable;
  146.             $this->__array              = $array;
  147.            
  148.             $this->updateEvent();
  149.         }
  150.        
  151.         // iSerializable
  152.        
  153.         /**
  154.          * @see tSerializable
  155.          */
  156.         USE tSerializable;
  157.        
  158.         // Countable
  159.        
  160.         public function count()
  161.         {
  162.             return sizeOf($this->__array);
  163.         }
  164.        
  165.         // Iterator
  166.        
  167.         public function rewind()
  168.         {
  169.             $this->__itIndex = (TRUE === $this->__FLAG->valueGet(self::IT_MODE_LO))
  170.                 ? $this->lastIndex()
  171.                 : $this->firstIndex();
  172.                
  173.             return $this;
  174.         }
  175.        
  176.         public function current()
  177.         {
  178.             return $this->indexGet($this->__itIndex);
  179.         }
  180.        
  181.         public function key()
  182.         {
  183.             return $this->indexToOffset($this->__itIndex);
  184.         }
  185.        
  186.         public function next()
  187.         {
  188.             if(TRUE === $this->__FLAG->valueGet(self::IT_MODE_LO))
  189.                 return $this->prev();
  190.                
  191.             return ++$this->__itIndex;
  192.         }
  193.        
  194.         public function prev()
  195.         {
  196.             return --$this->__itIndex;
  197.         }
  198.        
  199.         public function valid()
  200.         {
  201.             return $this->indexExists($this->__itIndex);
  202.         }
  203.        
  204.         public function currentIeratorIndex()
  205.         {
  206.             return $this->__itIndex;
  207.         }
  208.        
  209.         public function setIteratorIndex($itIndex)
  210.         {
  211.             if(NULL === $itIndex)
  212.                 throw new ArgumentNullException;
  213.                
  214.             if(FALSE === is_integer($itIndex))
  215.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  216.            
  217.             if(FALSE === $this->indexExists($itIndex))
  218.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  219.                     ['key' => $itIndex]);
  220.            
  221.             $this->__itIndex = $itIndex;
  222.             return $this;
  223.         }
  224.        
  225.         // ArrayAccess
  226.        
  227.         public function offsetSet($offset, $value)
  228.         {
  229.             if(NULL === $offset)
  230.                 $offset = $this->nextAvailOffset();
  231.                
  232.             if(FALSE === is_scalar($offset))
  233.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  234.                
  235.             if($offset === "")
  236.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  237.            
  238.             if(FALSE === $this->offsetExists($offset))
  239.             {
  240.                 $this->__array          = $this->insert($offset, $value);
  241.                 $this->__lastInsertOffset   = $offset;
  242.                
  243.                 return $this->updateEvent();
  244.             }
  245.            
  246.             $this->__array[$offset]     = $value;
  247.             $this->__lastChangedOffset  = $offset;
  248.            
  249.             return $this->updateEvent();
  250.         }
  251.        
  252.         /**
  253.          * array merge
  254.          *
  255.          * merge by priority
  256.          * PERM_ARRAY_AS_SUPER: existing offsets will be ignored
  257.          *
  258.          * merge will not cleanup existing offsets!
  259.          *
  260.          * merge appends/prepends by IT_MODE_FI of $this->__array and IT_MODE_LO of $array
  261.          *
  262.          * no modifiers set: LIFO
  263.          *
  264.          * <code>
  265.          * <?PHP
  266.          *  $mArray = ["m.foo",            "m.bar",      "m.fox"];
  267.          *  $aArray = ["a.foo", "a.bar" => "a.bar", 7 => "a.fox"];
  268.          *  
  269.          *  var_dump($mArray);
  270.          *  var_dump($aArray);
  271.          *  
  272.          *  
  273.          *  $m = new tArray($mArray);
  274.          *  $a = new tArray($aArray);
  275.          *  
  276.          *  // default replace like array_merge
  277.          *  $m->merge($a);
  278.          *  // => a.foo m.bar m.fox a.bar a.fox
  279.          *  var_dump($m->toArray());
  280.          *  
  281.          *  // it-mode FI in $m: values of $a at first; note the order of $a!
  282.          *  // => a.fox a.bar a.foo m.bar m.fox
  283.          *  var_dump((new tArray($mArray, new System\ProtoFlag(tArray::IT_MODE_FI)))->merge($a)->toArray());
  284.          *  
  285.          *  // $m with it-mode FI: to hold the positions of $a set it-mode to LO
  286.          *  $aLO = new tArray($aArray, new System\ProtoFlag(tArray::IT_MODE_LO));
  287.          *  // => a.bar a.fox a.foo m.bar m.fox
  288.          *  var_dump((new tArray($mArray, new System\ProtoFlag(tArray::IT_MODE_FI)))->merge($aLO)->toArray());
  289.          * ?>
  290.          * </code>
  291.          */
  292.         public function merge($array)
  293.         {
  294.             if(FALSE === ($array instanceOf ProtoArray)
  295.             && FALSE === ($array instanceOf ProtoArraySegment)
  296.             && FALSE === is_array($array))
  297.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_ARRAY);
  298.            
  299.             if(FALSE === (bool) $array)
  300.                 return $this;
  301.                
  302.             foreach($array as $k => $v)
  303.             {
  304.                 if(TRUE === $this->__FLAG->valueGet(self::PERM_ARRAY_AS_SUPER)
  305.                 && $this->offsetExists($k))
  306.                     continue;
  307.                
  308.                 $this[$k] = $v;
  309.             }
  310.            
  311.             return $this;
  312.         }
  313.        
  314.         /**
  315.          * cleanup numeric offsets
  316.          */
  317.         public function cleanup()
  318.         {
  319.             $this->__array = array_merge($this->__array, []);
  320.             $this->updateEvent();
  321.             return $this;
  322.         }
  323.        
  324.         public function offsetExists($offset)
  325.         {
  326.             if(NULL === $offset)
  327.                 throw new ArgumentNullException;
  328.                
  329.             if(FALSE === is_scalar($offset))
  330.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  331.                
  332.             if($offset === "")
  333.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  334.                
  335.             return array_key_exists($offset, $this->__array);
  336.         }
  337.        
  338.         public function offsetUnset($offset)
  339.         {
  340.             if(NULL === $offset)
  341.                 throw new ArgumentNullException;
  342.                
  343.             if(FALSE === is_scalar($offset))
  344.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  345.                
  346.             if($offset === "")
  347.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  348.                
  349.             if(FALSE === $this->offsetExists($offset))
  350.                 return $this;
  351.            
  352.             unset($this->__array[$offset]);
  353.             return $this->updateEvent();
  354.         }
  355.        
  356.         public function offsetGet($offset)
  357.         {
  358.             if(NULL === $offset)
  359.                 throw new ArgumentNullException;
  360.                
  361.             if(FALSE === is_scalar($offset))
  362.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  363.                
  364.             if($offset === "")
  365.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  366.                
  367.             return (TRUE === $this->offsetExists($offset))
  368.                 ? $this->__array[$offset]
  369.                 : null;
  370.         }
  371.        
  372.         // IndexAccess
  373.            
  374.         /**
  375.          * index-based alias for offsetExists
  376.          */
  377.         public function indexExists($index)
  378.         {
  379.             if(NULL === $index)
  380.                 throw new ArgumentNullException;
  381.                
  382.             if(FALSE === is_integer($index))
  383.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  384.                
  385.             return array_key_exists($index, $this->__offsets);
  386.         }
  387.            
  388.         /**
  389.          * index-based alias for offsetSet
  390.          */
  391.         public function indexSet($index, $value)
  392.         {
  393.             if(NULL === $index)
  394.                 throw new ArgumentNullException;
  395.                
  396.             if(FALSE === is_integer($index))
  397.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  398.            
  399.             if(FALSE === $this->indexExists($index))
  400.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  401.                     ['key' => $index]);
  402.            
  403.             return $this->offsetSet($this->indexToOffset($index), $value);
  404.         }
  405.            
  406.         /**
  407.          * index-based alias for offsetUnset
  408.          */
  409.         public function indexUnset($index)
  410.         {
  411.             if(NULL === $index)
  412.                 throw new ArgumentNullException;
  413.                
  414.             if(FALSE === is_integer($index))
  415.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  416.            
  417.             if(FALSE === $this->indexExists($index))
  418.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  419.                     ['key' => $index]);
  420.            
  421.             return $this->offsetUnset($this->indexToOffset($index));
  422.         }
  423.            
  424.         /**
  425.          * index-based alias for offsetGet
  426.          */
  427.         public function indexGet($index)
  428.         {
  429.             if(NULL === $index)
  430.                 throw new ArgumentNullException;
  431.                
  432.             if(FALSE === is_integer($index))
  433.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  434.            
  435.             if(FALSE === $this->indexExists($index))
  436.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  437.                     ['key' => $index]);
  438.            
  439.             return $this->offsetGet($this->indexToOffset($index));
  440.         }
  441.        
  442.         // Conversation
  443.        
  444.         /**
  445.          * get the next avail numeric offset
  446.          */
  447.         public function nextAvailOffset()
  448.         {
  449.             return max($this->__offsets) + 1;
  450.         }
  451.            
  452.         /**
  453.          * get the index by offset
  454.          */
  455.         public function offsetToIndex($offset)
  456.         {
  457.             if(NULL === $offset)
  458.                 throw new ArgumentNullException;
  459.                
  460.             if(FALSE === is_scalar($offset))
  461.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  462.                
  463.             if($offset === "")
  464.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  465.            
  466.             if(FALSE === $this->offsetExists($offset))
  467.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  468.                     ['key' => $offset]);
  469.                
  470.             return $this->__indexes[$offset];
  471.         }
  472.        
  473.         /**
  474.          * get the offset by index
  475.          */
  476.         public function indexToOffset($index)
  477.         {
  478.             if(NULL === $index)
  479.                 throw new ArgumentNullException;
  480.                
  481.             if(FALSE === is_integer($index))
  482.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  483.            
  484.             if(FALSE === $this->indexExists($index))
  485.                 throw new ArgumentOutOfRangeException(E::ARGUMENT_OUT_OF_ARRAY_INDEX,
  486.                     ['key' => $index]);
  487.            
  488.             return $this->__offsets[$index];
  489.         }
  490.        
  491.         /**
  492.          * bottom value
  493.          */
  494.         public function firstValue()
  495.         {
  496.             return $this->__array[$this->firstOffset()];
  497.         }
  498.        
  499.         /**
  500.          * top value
  501.          */
  502.         public function lastValue()
  503.         {
  504.             return $this->__array[$this->lastOffset()];
  505.         }
  506.        
  507.         /**
  508.          * last insert value
  509.          */
  510.         public function lastInsertValue()
  511.         {
  512.             return $this->__array[$this->lastInsertOffset()];
  513.         }
  514.        
  515.         /**
  516.          * last changed value
  517.          */
  518.         public function lastChangedValue()
  519.         {
  520.             return $this->__array[$this->lastChangedOffset()];
  521.         }
  522.        
  523.         /**
  524.          * bottom offset
  525.          */
  526.         public function firstOffset()
  527.         {
  528.             return $this->__offsets[$this->firstIndex()];
  529.         }
  530.        
  531.         /**
  532.          * top offset
  533.          */
  534.         public function lastOffset()
  535.         {
  536.             return $this->__offsets[$this->lastIndex()];
  537.         }
  538.        
  539.         /**
  540.          * last insert offset
  541.          */
  542.         public function lastInsertOffset()
  543.         {
  544.             return $this->__lastInsertOffset;
  545.         }
  546.        
  547.         /**
  548.          * last changed offset
  549.          */
  550.         public function lastChangedOffset()
  551.         {
  552.             return $this->__lastChangedOffset;
  553.         }
  554.        
  555.         /**
  556.          * bottom index
  557.          */
  558.         public function firstIndex()
  559.         {
  560.             return 0;
  561.         }
  562.        
  563.         /**
  564.          * top index
  565.          */
  566.         public function lastIndex()
  567.         {
  568.             return $this->count() - 1;
  569.         }
  570.        
  571.         /**
  572.          * last insert index
  573.          */
  574.         public function lastInsertIndex()
  575.         {
  576.             return $this->offsetToIndex($this->lastInsertOffset());
  577.         }
  578.        
  579.         /**
  580.          * last changed index
  581.          */
  582.         public function lastChangedIndex()
  583.         {
  584.             return $this->offsetToIndex($this->lastChangedOffset());
  585.         }
  586.        
  587.         /**
  588.          * returns the value by offset or by top-offset
  589.          */
  590.         public function peekValueByOffset($offset)
  591.         {
  592.             if(NULL === $offset)
  593.                 throw new ArgumentNullException;
  594.                
  595.             if(FALSE === is_scalar($offset))
  596.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  597.                
  598.             if($offset === "")
  599.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  600.            
  601.             return (FALSE === $this->offsetExists($offset))
  602.                 ? $this->lastValue()
  603.                 : $this->offsetGet($offset);
  604.         }
  605.        
  606.         /**
  607.          * returns the value by index or by top-index
  608.          */
  609.         public function peekValueByIndex($index)
  610.         {
  611.             if(NULL === $index)
  612.                 throw new ArgumentNullException;
  613.                
  614.             if(FALSE === is_integer($index))
  615.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  616.            
  617.             return (FALSE === $this->indexExists($index))
  618.                 ? $this->lastValue()
  619.                 : $this->indexGet($index);
  620.         }
  621.        
  622.         /**
  623.          * returns the index by offset or by top-offset
  624.          */
  625.         public function peekIndexByOffset($offset)
  626.         {
  627.             if(NULL === $offset)
  628.                 throw new ArgumentNullException;
  629.                
  630.             if(FALSE === is_scalar($offset))
  631.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_SCALAR);
  632.                
  633.             if($offset === "")
  634.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_STRING_EMPTY);
  635.            
  636.             return (FALSE === $this->offsetExists($offset))
  637.                 ? $this->lastIndex()
  638.                 : $this->offsetToIndex($offset);
  639.         }
  640.        
  641.         /**
  642.          * returns the offset by index or by top-index
  643.          */
  644.         public function peekOffsetByIndex($index)
  645.         {
  646.             if(NULL === $index)
  647.                 throw new ArgumentNullException;
  648.                
  649.             if(FALSE === is_integer($index))
  650.                 throw new ArgumentException(E::ARGUMENT_EXPECTED_INTEGER);
  651.            
  652.             return (FALSE === $this->indexExists($index))
  653.                 ? $this->lastOffset()
  654.                 : $this->indexToOffset($index);
  655.         }
  656.        
  657.         // generic array functions
  658.        
  659.         public function push($value)
  660.         {
  661.         }
  662.        
  663.         public function toArray()
  664.         {
  665.             return $this->__array;
  666.         }
  667.        
  668.         /**
  669.          * synchronize $__array with $__indexes and $__offsets
  670.          *
  671.          * its essential to update the both arrays whenever you edit $__array
  672.          *
  673.          * @see $__array
  674.          * @see $__indexes
  675.          * @see $__offsets
  676.          */
  677.         protected function updateEvent()
  678.         {
  679.             $this->__offsets = array_keys($this->__array);
  680.             $this->__indexes = array_flip($this->__offsets);
  681.            
  682.             if(NULL !== $this->__lastInsertOffset
  683.             && FALSE === $this->offsetExists($this->__lastInsertOffset))
  684.                 $this->__lastInsertOffset = NULL;
  685.                
  686.             if(NULL !== $this->__lastChangedOffset
  687.             && FALSE === $this->offsetExists($this->__lastChangedOffset))
  688.                 $this->__lastChangedOffset = NULL;
  689.            
  690.             return $this;
  691.         }
  692.        
  693.         /**
  694.          * append or prepend offset by IT_MODE_FI
  695.          */
  696.         private function insert($offset, $value)
  697.         {
  698.             if(TRUE === $this->__FLAG->valueGet(self::IT_MODE_FI))
  699.             {
  700.                 $array1 = [$offset => $value];
  701.                 $array2 = $this->__array;
  702.             }
  703.             else
  704.             {
  705.                 $array1 = $this->__array;
  706.                 $array2 = [$offset => $value];
  707.             }
  708.            
  709.             $result = [];
  710.            
  711.             if(TRUE === (bool) $array1)
  712.                 foreach($array1 as $k => $v)
  713.                     $result[$k] = $v;
  714.                
  715.             if(TRUE === (bool) $array2)
  716.                 foreach($array2 as $k => $v)
  717.                     $result[$k] = $v;
  718.            
  719.             return $result;
  720.         }
  721.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement