[FEATURE] Introduce BitSet class 50/59650/6
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Wed, 6 Feb 2019 10:35:23 +0000 (11:35 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sat, 23 Feb 2019 17:01:19 +0000 (18:01 +0100)
This patch introduces a simple BitSet class that
can be used to handle boolean flags.

Releases: master
Resolves: #87665
Change-Id: I32911ed1213421ef30596c2aceb4b8cbd27a8a45
Reviewed-on: https://review.typo3.org/c/59650
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/core/Classes/DataStructure/BitSet.php [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-87665-IntroduceBitSetClass.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/DataStructure/BitSetTest.php [new file with mode: 0644]

diff --git a/typo3/sysext/core/Classes/DataStructure/BitSet.php b/typo3/sysext/core/Classes/DataStructure/BitSet.php
new file mode 100644 (file)
index 0000000..b114000
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+declare(strict_types = 1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Core\DataStructure;
+
+/**
+ * Class TYPO3\CMS\Core\DataStructure\BitSet
+ */
+class BitSet
+{
+    /**
+     * @var int
+     */
+    private $set;
+
+    /**
+     * @param int $set
+     */
+    public function __construct(int $set = 0)
+    {
+        $this->set = $set;
+    }
+
+    /**
+     * @param int $bitIndex
+     */
+    public function set(int $bitIndex): void
+    {
+        $this->set |= $bitIndex;
+    }
+
+    /**
+     * @param int $bitIndex
+     * @param bool $value
+     */
+    public function setValue(int $bitIndex, bool $value): void
+    {
+        if ($value) {
+            $this->set($bitIndex);
+        } else {
+            $this->unset($bitIndex);
+        }
+    }
+
+    /**
+     * @param int $bitIndex
+     */
+    public function unset(int $bitIndex): void
+    {
+        $this->set &= ~$bitIndex;
+    }
+
+    /**
+     * @param int $bitIndex
+     * @return bool
+     */
+    public function get(int $bitIndex): bool
+    {
+        return ($bitIndex & $this->set) === $bitIndex;
+    }
+}
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-87665-IntroduceBitSetClass.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-87665-IntroduceBitSetClass.rst
new file mode 100644 (file)
index 0000000..51a5683
--- /dev/null
@@ -0,0 +1,87 @@
+.. include:: ../../Includes.txt
+
+========================================
+Feature: #87665 - Introduce BitSet class
+========================================
+
+See :issue:`87665`
+
+Description
+===========
+
+To efficiently handle boolean flags, bit sets can be used. Therefore a new class :php:`\TYPO3\CMS\Core\DataStructure\BitSet` has been introduced.
+The bit set can be used standalone and accessed from the outside but it can also be used to create specific BitSet classes that extend the BitSet class.
+
+The functionality is best described by an example:
+
+::
+
+   <?php
+   declare(strict_types = 1);
+
+   define('PERMISSIONS_NONE', 0b0); // 0
+   define('PERMISSIONS_PAGE_SHOW', 0b1); // 1
+   define('PERMISSIONS_PAGE_EDIT', 0b10); // 2
+   define('PERMISSIONS_PAGE_DELETE', 0b100); // 4
+   define('PERMISSIONS_PAGE_NEW', 0b1000); // 8
+   define('PERMISSIONS_CONTENT_EDIT', 0b10000); // 16
+   define('PERMISSIONS_ALL', 0b11111); // 31
+
+   $bitSet = new \TYPO3\CMS\Core\DataStructure\BitSet(PERMISSIONS_PAGE_SHOW | PERMISSIONS_PAGE_NEW);
+   $bitSet->get(PERMISSIONS_PAGE_SHOW); // true
+   $bitSet->get(PERMISSIONS_CONTENT_EDIT); // false
+
+Another example shows how to possibly extend the :php:`\TYPO3\CMS\Core\DataStructure\BitSet` class.
+
+::
+
+   <?php
+   declare(strict_types = 1);
+
+   class Permissions extends \TYPO3\CMS\Core\DataStructure\BitSet
+   {
+       public const NONE = 0b0; // 0
+       public const PAGE_SHOW = 0b1; // 1
+       public const PAGE_EDIT = 0b10; // 2
+       public const PAGE_DELETE = 0b100; // 4
+       public const PAGE_NEW = 0b1000; // 8
+       public const CONTENT_EDIT = 0b10000; // 16
+       public const ALL = 0b11111; // 31
+
+       /**
+        * @param int $permission
+        * @return bool
+        */
+       public function hasPermission(int $permission): bool
+       {
+           return $this->get($permission);
+       }
+
+       /**
+        * @return bool
+        */
+       public function hasAllPermissions(): bool
+       {
+           return $this->get(static::ALL);
+       }
+
+       /**
+        * @param int $permission
+        */
+       public function allow(int $permission): void
+       {
+           $this->set($permission);
+       }
+   }
+
+   $permissions = new Permissions(Permissions::PAGE_SHOW | Permissions::PAGE_NEW);
+   $permissions->hasPermission(Permissions::PAGE_SHOW); // true
+   $permissions->hasPermission(Permissions::CONTENT_EDIT); // false
+
+
+Impact
+======
+
+This class may come in handy in all situations where boolean flags need to be managed in an efficient way.
+
+.. index:: PHP-API, ext:core
diff --git a/typo3/sysext/core/Tests/Unit/DataStructure/BitSetTest.php b/typo3/sysext/core/Tests/Unit/DataStructure/BitSetTest.php
new file mode 100644 (file)
index 0000000..6ec3a24
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+declare(strict_types = 1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Core\Tests\Unit\DataStructure;
+
+use TYPO3\CMS\Core\DataStructure\BitSet;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+/**
+ * Class TYPO3\CMS\Core\Tests\Unit\DataStructure\BitSetTest
+ */
+class BitSetTest extends UnitTestCase
+{
+    /**
+     * @test
+     */
+    public function defaultBitSetOnlyHasZeroByteSet(): void
+    {
+        $bitSet = new BitSet();
+        static::assertTrue($bitSet->get(0b0));
+        static::assertFalse($bitSet->get(0b1));
+    }
+
+    /**
+     * @test
+     */
+    public function constructorSetsInternalSet(): void
+    {
+        $bitSet = new BitSet(0b1 | 0b100);
+        static::assertTrue($bitSet->get(0b1));
+        static::assertTrue($bitSet->get(0b100));
+        static::assertFalse($bitSet->get(0b10));
+    }
+
+    /**
+     * @test
+     */
+    public function setSetsBit(): void
+    {
+        $bitSet = new BitSet(0b101);
+        static::assertTrue($bitSet->get(0b1));
+        static::assertTrue($bitSet->get(0b100));
+        static::assertFalse($bitSet->get(0b10));
+
+        $bitSet->set(0b10);
+        static::assertTrue($bitSet->get(0b10));
+    }
+
+    /**
+     * @test
+     */
+    public function setValueSetsBit(): void
+    {
+        $bitSet = new BitSet();
+        static::assertFalse($bitSet->get(0b1));
+
+        $bitSet->setValue(0b1, true);
+        static::assertTrue($bitSet->get(0b1));
+
+        $bitSet->setValue(0b1, false);
+        static::assertFalse($bitSet->get(0b1));
+    }
+
+    /**
+     * @test
+     */
+    public function clearUnsetsBit(): void
+    {
+        $bitSet = new BitSet(0b111);
+        $bitSet->unset(0b10);
+        static::assertTrue($bitSet->get(0b1));
+        static::assertTrue($bitSet->get(0b100));
+        static::assertFalse($bitSet->get(0b10));
+    }
+}