Continued:
[core.git] / framework / main / classes / stacker / class_BaseStacker.php
index d6d627ca19131d7eedb1b565c6853770fb19e787..cdfa4bc42426a46a7e0210fba4ce4689e83db7b7 100644 (file)
@@ -1,16 +1,22 @@
 <?php
 // Own namespace
-namespace Org\Mxchange\CoreFramework\Stacker;
+namespace Org\Mxchange\CoreFramework\Stack;
 
 // Import framework stuff
+use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
+use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
 
+// Import SPL stuff
+use \BadMethodCallException;
+use \InvalidArgumentException;
+
 /**
  * A general Stacker
  *
  * @author             Roland Haeder <webmaster@shipsimu.org>
  * @version            0.0.0
- * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
+ * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
  * @license            GNU GPL 3.0 or any newer version
  * @link               http://www.shipsimu.org
  *
@@ -28,11 +34,11 @@ use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 abstract class BaseStacker extends BaseFrameworkSystem {
-       // Exception codes
-       const EXCEPTION_STACKER_ALREADY_INITIALIZED = 0x050;
-       const EXCEPTION_STACKER_IS_FULL             = 0x051;
-       const EXCEPTION_NO_STACKER_FOUND            = 0x052;
-       const EXCEPTION_STACKER_IS_EMPTY            = 0x053;
+       /**
+        * Array "caches" configuration entries for saving "expensive" method
+        * invocations
+        */
+       private $cachedMaxStackSizes = [];
 
        /**
         * Protected constructor
@@ -40,7 +46,7 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         * @param       $className      Name of the class
         * @return      void
         */
-       protected function __construct ($className) {
+       protected function __construct (string $className) {
                // Call parent constructor
                parent::__construct($className);
        }
@@ -51,30 +57,51 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         * @param       $stackerName    Name of the stack
         * @param       $forceReInit    Force re-initialization
         * @return      void
-        * @throws      AlreadyInitializedStackerException      If the stack is already initialized
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If the stack is already initialized
         */
-       public function initStack ($stackerName, $forceReInit = false) {
-               // Is the stack already initialized?
-               if (($forceReInit === false) && ($this->isStackInitialized($stackerName))) {
+       public function initStack (string $stackerName, bool $forceReInit = false) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,forceReInit=%d - CALLED!', $stackerName, intval($forceReInit)));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (($forceReInit === false) && ($this->isStackInitialized($stackerName))) {
                        // Then throw the exception
-                       throw new AlreadyInitializedStackerException(array($this, $stackerName, $forceReInit), self::EXCEPTION_STACKER_ALREADY_INITIALIZED);
-               } // END - if
+                       throw new BadMethodCallException(array($this, $stackerName, $forceReInit), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
+               }
 
-               // Initialize the given stack
+               // Initialize the given stack and "cache" configuration entry
                $this->initGenericArrayKey('stacks', $stackerName, 'entries', $forceReInit);
+               $this->cachedMaxStackSizes[$stackerName] = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry(sprintf('stacker_%s_max_size', $stackerName));
+
+               // Trace message
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
        }
 
        /**
         * Initializes all stacks
         *
         * @return      void
+        * @throws      InvalidArgumentException        If a parameter is invalid
         */
-       public function initStacks (array $stacks, $forceReInit = false) {
+       public function initStacks (array $stacks, bool $forceReInit = false) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stacks()=%d,forceReInit=%d - CALLED!', count($stacks), intval($forceReInit)));
+               if (count($stacks) == 0) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Array "stacks" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               }
+
                // "Walk" through all (more will be added as needed
                foreach ($stacks as $stackerName) {
                        // Init this stack
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: Invoking this->initStack(%s,%d) ...', $stackerName, intval($forceReInit)));
                        $this->initStack($stackerName, $forceReInit);
-               } // END - foreach
+               }
+
+               // Trace message
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
        }
 
        /**
@@ -82,12 +109,21 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $isInitialized  Whether the stack is initialized
+        * @throws      InvalidArgumentException        If a parameter is invalid
         */
-       public function isStackInitialized ($stackerName) {
+       public function isStackInitialized (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               }
+
                // Is is there?
                $isInitialized = ($this->isValidGenericArrayKey('stacks', $stackerName, 'entries'));
 
                // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isInitialized=%d - EXIT!', intval($isInitialized)));
                return $isInitialized;
        }
 
@@ -96,19 +132,25 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $isFull                 Whether the stack is full
-        * @throws      NoStackerException      If given stack is missing
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If given stack is missing
         */
-       protected function isStackFull ($stackerName) {
-               // Is the stack not yet initialized?
-               if (!$this->isStackInitialized($stackerName)) {
+       protected function isStackFull (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
-               } // END - if
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
+               }
 
                // So, is the stack full?
-               $isFull = (($this->getStackCount($stackerName)) == $this->getConfigInstance()->getConfigEntry('stacker_' . $stackerName . '_max_size'));
+               $isFull = (($this->getStackCount($stackerName)) == $this->cachedMaxStackSizes[$stackerName]);
 
                // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isFull=%d - EXIT!', intval($isFull)));
                return $isFull;
        }
 
@@ -117,19 +159,25 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName            Name of the stack
         * @return      $isEmpty                        Whether the stack is empty
-        * @throws      NoStackerException      If given stack is missing
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If given stack is missing
         */
-       public function isStackEmpty ($stackerName) {
-               // Is the stack not yet initialized?
-               if (!$this->isStackInitialized($stackerName)) {
+       public function isStackEmpty (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
-               } // END - if
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
+               }
 
                // So, is the stack empty?
                $isEmpty = (($this->getStackCount($stackerName)) == 0);
 
                // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isEmpty=%d - EXIT!', intval($isEmpty)));
                return $isEmpty;
        }
 
@@ -138,19 +186,25 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $count                  Size of stack (array count)
-        * @throws      NoStackerException      If given stack is missing
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If given stack is missing
         */
-       public function getStackCount ($stackerName) {
-               // Is the stack not yet initialized?
-               if (!$this->isStackInitialized($stackerName)) {
+       public function getStackCount (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
-               } // END - if
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
+               }
 
                // Now, count the array of entries
                $count = $this->countGenericArrayElements('stacks', $stackerName, 'entries');
 
                // Return result
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: count=%d - EXIT!', $count));
                return $count;
        }
 
@@ -160,20 +214,29 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         * @param       $stackerName    Name of the stack
         * @param       $value                  Value to add to this stacker
         * @return      void
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If given stack is missing
         * @throws      FullStackerException    Thrown if the stack is full
         */
-       protected function addValue ($stackerName, $value) {
-               // Is the stack not yet initialized or full?
-               if (!$this->isStackInitialized($stackerName)) {
-                       // Then do it here
-                       $this->initStack($stackerName);
+       protected function addValueToStack (string $stackerName, $value) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,value[]=%s - CALLED!', $stackerName, gettype($value)));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
+                       // Throw an exception
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                } elseif ($this->isStackFull($stackerName)) {
                        // Stacker is full
-                       throw new FullStackerException(array($this, $stackerName, $value), self::EXCEPTION_STACKER_IS_FULL);
+                       throw new BadMethodCallException(sprintf('stackerName=%s is full but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                }
 
                // Now add the value to the stack
                $this->pushValueToGenericArrayKey('stacks', $stackerName, 'entries', $value);
+
+               // Trace message
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
        }
 
        /**
@@ -181,23 +244,32 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $value                  Value of last added value
-        * @throws      NoStackerException      If the named stacker was not found
-        * @throws      EmptyStackerException   If the named stacker is empty
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If the named stacker was not found
+        * @throws      BadMethodCallException  If the named stacker is empty
         */
-       protected function getLastValue ($stackerName) {
-               // Is the stack not yet initialized or full?
-               if (!$this->isStackInitialized($stackerName)) {
+       protected function getLastValue (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                } elseif ($this->isStackEmpty($stackerName)) {
                        // Throw an exception
-                       throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                }
 
+               // Calculate last index
+               $lastIndex = $this->getStackCount($stackerName) - 1;
+
                // Now get the last value
-               $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', $this->getStackCount($stackerName) - 1);
+               $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', $lastIndex);
 
                // Return it
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
                return $value;
        }
 
@@ -206,23 +278,29 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $value                  Value of last added value
-        * @throws      NoStackerException      If the named stacker was not found
-        * @throws      EmptyStackerException   If the named stacker is empty
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If the named stacker was not found
+        * @throws      BadMethodCallException  If the named stacker is empty
         */
-       protected function getFirstValue ($stackerName) {
-               // Is the stack not yet initialized or full?
-               if (!$this->isStackInitialized($stackerName)) {
+       protected function getFirstValue (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                } elseif ($this->isStackEmpty($stackerName)) {
                        // Throw an exception
-                       throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                }
 
                // Now get the first value
-               $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', 0);
+               $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', '0');
 
                // Return it
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
                return $value;
        }
 
@@ -231,21 +309,30 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $value                  Value "poped" from array
-        * @throws      NoStackerException      If the named stacker was not found
-        * @throws      EmptyStackerException   If the named stacker is empty
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If the named stacker was not found
+        * @throws      BadMethodCallException  If the named stacker is empty
         */
-       protected function popLast ($stackerName) {
-               // Is the stack not yet initialized or full?
-               if (!$this->isStackInitialized($stackerName)) {
+       protected function popLast (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                } elseif ($this->isStackEmpty($stackerName)) {
                        // Throw an exception
-                       throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
+                       throw new BadMethodCallException(sprintf('stackerName=%s is empty but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                }
 
                // Now, remove the last entry, we don't care about the return value here, see elseif() block above
-               return $this->popGenericArrayElement('stacks', $stackerName, 'entries');
+               $value = $this->popGenericArrayElement('stacks', $stackerName, 'entries');
+
+               // Return it
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
+               return $value;
        }
 
        /**
@@ -253,21 +340,30 @@ abstract class BaseStacker extends BaseFrameworkSystem {
         *
         * @param       $stackerName    Name of the stack
         * @return      $value                  Value "shifted" from array
-        * @throws      NoStackerException      If the named stacker was not found
-        * @throws      EmptyStackerException   If the named stacker is empty
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      BadMethodCallException  If the named stacker was not found
+        * @throws      BadMethodCallException  If the named stacker is empty
         */
-       protected function popFirst ($stackerName) {
-               // Is the stack not yet initialized or full?
-               if (!$this->isStackInitialized($stackerName)) {
+       protected function popFirst (string $stackerName) {
+               // Validate parameter
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
+               if (empty($stackerName)) {
+                       // No empty stack name
+                       throw new InvalidArgumentException('Parameter "stackerName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif (!$this->isStackInitialized($stackerName)) {
                        // Throw an exception
-                       throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                } elseif ($this->isStackEmpty($stackerName)) {
                        // Throw an exception
-                       throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
+                       throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
                }
 
                // Now, remove the last entry, we don't care about the return value here, see elseif() block above
-               return $this->shiftGenericArrayElement('stacks', $stackerName, 'entries');
+               $value = $this->shiftGenericArrayElement('stacks', $stackerName, 'entries');
+
+               // Return it
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
+               return $value;
        }
 
 }