]> git.mxchange.org Git - core.git/blob - inc/main/classes/lists/class_BaseList.php
Introduced namespaces:
[core.git] / inc / main / classes / lists / class_BaseList.php
1 <?php
2 // Own namespace
3 namespace CoreFramework\Lists;
4
5 // Load framework stuff
6 use CoreFramework\Generic\FrameworkInterface;
7
8 /**
9  * A general list class
10  *
11  * @author              Roland Haeder <webmaster@shipsimu.org>
12  * @version             0.0.0
13  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
14  * @license             GNU GPL 3.0 or any newer version
15  * @link                http://www.shipsimu.org
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  */
30 class BaseList extends BaseFrameworkSystem implements IteratorAggregate, Countable {
31         // Exception constants
32         const EXCEPTION_GROUP_ALREADY_ADDED = 0xf20;
33         const EXCEPTION_GROUP_NOT_FOUND     = 0xf21;
34         const EXCEPTION_INVALID_HASH        = 0xf22;
35
36         /**
37          * List groups array
38          */
39         private $listGroups = array();
40
41         /**
42          * List entries array
43          */
44         private $listEntries = array();
45
46         /**
47          * List index array
48          */
49         private $listIndex = array();
50
51         /**
52          * Protected constructor
53          *
54          * @param       $className      Name of the class
55          * @return      void
56          */
57         protected function __construct ($className) {
58                 // Call parent constructor
59                 parent::__construct($className);
60         }
61
62         /**
63          * Getter for iterator instance from this list
64          *
65          * @return      $iteratorInstance       An instance of a Iterator class
66          */
67         public function getIterator () {
68                 // Get iterator from here
69                 $iteratorInstance = $this->getIteratorInstance();
70
71                 // Is the instance set?
72                 if (is_null($iteratorInstance)) {
73                         // Prepare a default iterator
74                         $iteratorInstance = ObjectFactory::createObjectByConfiguredName('default_iterator_class', array($this));
75
76                         // Set it here
77                         $this->setIteratorInstance($iteratorInstance);
78                 } // END - if
79
80                 // And return it
81                 return $iteratorInstance;
82         }
83
84         /**
85          * Checks whether the given group is set
86          *
87          * @param       $groupName      Group to check if found in list
88          * @return      $isset          Whether the group is valid
89          */
90         public function isGroupSet ($groupName) {
91                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName);
92                 return isset($this->listGroups[$groupName]);
93         }
94
95         /**
96          * Adds the given group or if already added issues a ListGroupAlreadyAddedException
97          *
98          * @param       $groupName      Group to add
99          * @return      void
100          * @throws      ListGroupAlreadyAddedException  If the given group is already added
101          */
102         public function addGroup ($groupName) {
103                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ' - CALLED!');
104                 // Is the group already added?
105                 if ($this->isGroupSet($groupName)) {
106                         // Throw the exception here
107                         throw new ListGroupAlreadyAddedException(array($this, $groupName), self::EXCEPTION_GROUP_ALREADY_ADDED);
108                 } // END - if
109
110                 // Add the group which is a simple array
111                 $this->listGroups[$groupName] = ObjectFactory::createObjectByConfiguredName('list_group_class');
112                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ' - EXIT!');
113         }
114
115         /**
116          * Adds the given instance to list group and sub group
117          *
118          * @param       $groupName                      Group to add instance to
119          * @param       $subGroup                       Sub group to add instance to
120          * @param       $visitableInstance      An instance of Visitable
121          * @return      void
122          * @throws      NoListGroupException    If the given group is not found
123          */
124         public function addInstance ($groupName, $subGroup, Visitable $visitableInstance) {
125                 // Debug message
126                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName  . ',subGroup=' . $subGroup . ',visitableInstance=' . $visitableInstance->__toString() . ' - CALLED!');
127
128                 // Is the group there?
129                 if (!$this->isGroupSet($groupName)) {
130                         // Throw the exception here
131                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
132                 } // END - if
133
134                 // Is the sub group there?
135                 if (!$this->listGroups[$groupName]->isGroupSet($subGroup)) {
136                         // Automatically add it
137                         $this->listGroups[$groupName]->addGroup($subGroup);
138                 } // END - if
139
140                 // Generate the hash
141                 $hash = $this->generateHash($groupName, $subGroup, $visitableInstance);
142
143                 // Debug message
144                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName  . ',subGroup=' . $subGroup . ',hash=' . $hash . ' - Calling addEntry() ...');
145
146                 // Now add it to the group list and hash it
147                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',this->listGroups[' . $groupName . ']=' . $this->listGroups[$groupName]->__toString());
148                 //$this->listGroups[$groupName]->addEntry($subGroup, $hash);
149
150                 // Add the hash to the index
151                 array_push($this->listIndex, $hash);
152
153                 // Add the instance itself to the list
154                 $this->listEntries[$hash] = $visitableInstance;
155
156                 // Debug message
157                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName  . ',subGroup=' . $subGroup . ' - EXIT!');
158         }
159
160         /**
161          * Gets an array from given list
162          *
163          * @param       $list   The requested list
164          * @return      $array  The requested array
165          * @throws      NoListGroupException    If the given group is not found
166          */
167         public final function getArrayFromList ($list) {
168                 // Debug message
169                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',list[' . gettype($list) . ']=' . $list . ' - CALLED!');
170
171                 // Is the group there?
172                 if ((!is_null($list)) && (!$this->isGroupSet($list))) {
173                         // Throw the exception here
174                         throw new NoListGroupException(array($this, $list), self::EXCEPTION_GROUP_NOT_FOUND);
175                 } // END - if
176
177                 // Init array
178                 $array = array();
179
180                 // Is there another list?
181                 if (!is_null($list)) {
182                         // Then get it as well
183                         $array = $this->listGroups[$list]->getArrayFromList(NULL);
184                 } // END - if
185
186                 // Walk through all entries
187                 foreach ($this->listIndex as $hash) {
188                         // Debug message
189                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: hash=' . $hash);
190
191                         // Is the list entry set?
192                         if ($this->isHashValid($hash)) {
193                                 // Add it
194                                 array_push($array, $this->listEntries[$hash]);
195                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: hash=' . $hash . ',array(' . count($array) . ')=' . print_r($array, TRUE) . ' - ADDED!');
196                         } // END - if
197                 } // END - foreach
198
199                 // Debug message
200                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',list[' . gettype($list) . ']=' . $list . ',array()=' . count($array) . ' - EXIT!');
201
202                 // Return it
203                 return $array;
204         }
205
206         /**
207          * Adds the given entry to list group
208          *
209          * @param       $groupName      Group to add instance to
210          * @param       $entry          An entry of any type
211          * @return      void
212          * @throws      NoListGroupException    If the given group is not found
213          */
214         public function addEntry ($groupName, $entry) {
215                 // Debug message
216                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ' - CALLED!');
217
218                 // Is the group already added?
219                 if (!$this->isGroupSet($groupName)) {
220                         // Throw the exception here
221                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
222                 } // END - if
223
224                 // Generate hash
225                 $hash = $this->generateHash($groupName, $groupName, $entry);
226
227                 // Debug message
228                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ',entry=' . print_r($entry, TRUE) . ', hash=' . $hash);
229
230                 // Add the hash to the index
231                 array_push($this->listIndex, $hash);
232
233                 // Debug message
234                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ',listEntries()=' . count($this->listEntries));
235
236                 // Now add the entry to the list
237                 $this->listEntries[$hash] = $entry;
238
239                 // Debug message
240                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ',listEntries()=' . count($this->listEntries) . ' - EXIT!');
241         }
242
243         /**
244          * Removes given entry from the list group
245          *
246          * @param       $groupName      Group where we should remove the entry from
247          * @param       $entry          The entry we should remove
248          * @return      void
249          * @throws      NoListGroupException    If the given group is not found
250          */
251         public function removeEntry ($groupName, $entry) {
252                 // Debug message
253                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ' - CALLED!');
254
255                 // Is the group already added?
256                 if (!$this->isGroupSet($groupName)) {
257                         // Throw the exception here
258                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
259                 } // END - if
260
261                 // Generate hash
262                 $hash = $this->generateHash($groupName, $groupName, $entry);
263
264                 // Debug message
265                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ',entry=' . $entry . ', hash=' . $hash);
266
267                 // Remove it from the list ...
268                 unset($this->listEntries[$hash]);
269
270                 // ... and hash list as well
271                 unset($this->listIndex[array_search($hash, $this->listIndex)]);
272
273                 // Debug message
274                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: this=' . $this->__toString() . ',groupName=' . $groupName . ' - EXIT!');
275         }
276
277         /**
278          * Generates a hash from given group, sub group and entry
279          *
280          * @param       $groupName      Group to add instance to
281          * @param       $subGroup       Sub group to add instance to
282          * @param       $entry          An entry of any type
283          * @return      $hash           The generated
284          */
285         private function generateHash ($groupName, $subGroup, $entry) {
286                 // Created entry, 'null' is default
287                 $entry2 = 'null';
288
289                 // Determine type of entry
290                 if (is_null($entry)) {
291                         // Ignore this
292                 } elseif ($entry instanceof FrameworkInterface) {
293                         // Own instance detected
294                         $entry2 = $entry->hashCode();
295                 } elseif ((is_int($entry)) || (is_float($entry)) || (is_resource($entry))) {
296                         // Integer/float/resource detected
297                         $entry2 = gettype($entry) . ':' . $entry;
298                 } elseif (is_string($entry)) {
299                         // String found
300                         $entry2 = crc32($entry) . ':' . strlen($entry);
301                 } elseif ((is_array($entry)) && (isset($entry['id']))) {
302                         // Supported array found
303                         $entry2 = crc32($entry['id']) . ':' . count($entry);
304                 } elseif ((is_array($entry)) && (isset($entry[BasePool::SOCKET_ARRAY_RESOURCE])) && (isset($entry[BasePool::SOCKET_ARRAY_CONN_TYPE]))) {
305                         // Is a socket resource array
306                         $entry2 = crc32($entry[BasePool::SOCKET_ARRAY_RESOURCE] . ':' . $entry[BasePool::SOCKET_ARRAY_CONN_TYPE]);
307                 } else {
308                         // Unsupported type detected
309                         self::createDebugInstance(__CLASS__)->debugOutput('BASE-LIST[' . __METHOD__ . ':' . __LINE__ . ']: Entry type ' . gettype($entry) . ' is unsupported.');
310
311                         // @TODO Extend this somehow?
312                         $entry2 = gettype($entry);
313                 }
314
315                 // Construct string which we shall hash
316                 $hashString = $groupName . ':' . $subGroup . ':' . $entry2;
317
318                 // Hash it with fastest hasher
319                 $hash = crc32($hashString);
320
321                 // And return it
322                 return $hash;
323         }
324
325         /**
326          * Clears an array of groups, all are being checked for existence
327          *
328          * @param       $groupNames             An array with existing list groups
329          * @return      void
330          */
331         protected function clearGroups (array $groupNames) {
332                 // Walk through all groups
333                 foreach ($groupNames as $groupName) {
334                         // Clear this group
335                         $this->clearGroup($groupName);
336                 } // END - foreach
337         }
338
339         /**
340          * Clears a single group by resetting it to its initial state (empty array)
341          *
342          * @param       $groupName      Name of an existing group to clear
343          * @return      void
344          */
345         protected function clearGroup ($groupName) {
346                 // Does this group exist?
347                 if (!$this->isGroupSet($groupName)) {
348                         // Throw the exception here
349                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
350                 } // END - if
351
352                 // Then clear this group list
353                 $this->listGroups[$groupName]->clearList();
354
355                 // Clear this list
356                 $this->listIndex = array();
357                 $this->listEntries = array();
358         }
359         
360         /**
361          * Counts all entries in this list
362          *
363          * @return      $count  All entries in this list
364          */
365         public final function count () {
366                 return count($this->listIndex);
367         }
368
369         /**
370          * Checks whether the given hash is valid
371          *
372          * @param       $hash           The hash we should validate
373          * @return      $isValid        Whether the given hash is valid
374          */
375         public final function isHashValid ($hash) {
376                 // Check it
377                 $isValid = ((in_array($hash, $this->listIndex)) && (isset($this->listEntries[$hash])));
378
379                 // Return the result
380                 return $isValid;
381         }
382
383         /**
384          * Getter for hash from given hash index
385          *
386          * @param       $hashIndex      Index holding the hash
387          * @return      $hash           The hash
388          */
389         public final function getHash ($hashIndex) {
390                 // Get it ...
391                 $hash = $this->listIndex[$hashIndex];
392
393                 // ... and return it
394                 return $hash;
395         }
396
397         /**
398          * Gets an entry from given hash index
399          *
400          * @param       $hashIndex      The hash index to resolve the mapped entry
401          * @return      $entry          Solved entry from list
402          * @throws      InvalidListHashException        If the solved hash index is invalid
403          */
404         public function getEntry ($hashIndex) {
405                 // Get the hash value
406                 $hash = $this->getHash($hashIndex);
407
408                 // Is the hash valid?
409                 if (!$this->isHashValid($hash)) {
410                         // Throw an exception here
411                         throw new InvalidListHashException(array($this, $hash, $hashIndex), self::EXCEPTION_INVALID_HASH);
412                 } // END - if
413
414                 // Now copy the entry
415                 $entry = $this->listEntries[$hash];
416
417                 // Return it
418                 return $entry;
419         }
420
421         /**
422          * Gets a full array from given group name
423          *
424          * @param       $groupName      The group name to get a list for
425          * @return      $entries        The array with all entries
426          * @throws      NoListGroupException    If the specified group is invalid
427          */
428         public function getArrayFromProtocolInstance ($groupName) {
429                 // Is the group valid?
430                 if (!$this->isGroupSet($groupName)) {
431                         // Throw the exception here
432                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
433                 } // END - if
434
435                 // Init the entries' array
436                 $entries = array();
437
438                 // Get an iterator
439                 $iteratorInstance = $this->listGroups[$groupName]->getIterator();
440
441                 // Rewind the iterator for this round
442                 $iteratorInstance->rewind();
443
444                 // Go through all entries
445                 while ($iteratorInstance->valid()) {
446                         // Get key
447                         $entryIndex = $iteratorInstance->key();
448
449                         // ... and the final entry which is the stored instance
450                         $entry = $this->getEntry($entryIndex);
451
452                         // Debug message
453                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('LIST: Adding entry ' . $entry . ' ...');
454
455                         // Add it to the list
456                         $entries[$iteratorInstance->current()] = $entry;
457
458                         // Skip to next one
459                         $iteratorInstance->next();
460                 } // END - while
461
462                 // Return the list
463                 return $entries;
464         }
465
466         /**
467          * Updates the given entry by hash with given array
468          *
469          * @param       $hash           Hash for this entry
470          * @param       $entryArray     Array with entry we should update
471          * @return      void
472          * @throws      InvalidListHashException        If the solved hash index is invalid
473          */
474         public function updateCurrentEntryByHash ($hash, array $entryArray) {
475                 // Is the hash valid?
476                 if (!$this->isHashValid($hash)) {
477                         // Throw an exception here, hashIndex is unknown at this point
478                         throw new InvalidListHashException(array($this, $hash, -999), self::EXCEPTION_INVALID_HASH);
479                 } // END - if
480
481                 // Set the entry
482                 $this->listEntries[$hash] = $entryArray;
483         }
484
485 }