From fbdee1fb5042d4211db447d0c4597d67dac801a5 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Sat, 12 Mar 2016 18:57:04 +0100 Subject: [PATCH 01/19] add tests for Bitmap class --- test/unit/BitmapTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/unit/BitmapTest.php diff --git a/test/unit/BitmapTest.php b/test/unit/BitmapTest.php new file mode 100644 index 0000000..357ca58 --- /dev/null +++ b/test/unit/BitmapTest.php @@ -0,0 +1,21 @@ +assertEquals(true, $b[0]); + $this->assertEquals(true, $b[9]); + + $b[9] = false; + $this->assertEquals(false, $b[9]); + + $this->setExpectedException('RuntimeException'); + unset($b[0]); + } + + +} From b5445c37a935593db7eb8d8929cea753bae9306f Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Sat, 12 Mar 2016 18:57:22 +0100 Subject: [PATCH 02/19] begin implementing Bitmap class --- src/Bitmap.php | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/Bitmap.php diff --git a/src/Bitmap.php b/src/Bitmap.php new file mode 100644 index 0000000..783fbf3 --- /dev/null +++ b/src/Bitmap.php @@ -0,0 +1,61 @@ +length = $length; + $this->bitmap = str_repeat("\0", ceil($this->length / 8)); + } + + public function __toString() { + return $this->toString(); + } + + public function toString($true = "1", $false = "0") { + $string = str_repeat($false, $this->length); + for ($offset = 0; $offset < $this->length; $offset++) { + if (ord($this->bitmap[(int) ($offset / 8)]) & (1 << $offset % 8)) { + $string[$offset] = $true; + } + } + + return $string; + } + + // ArrayAccess interface + + public function offsetExists($offset) { + return is_int($offset) && $offset >= 0 && $offset < $this->length; + } + + public function offsetGet($offset) + { + if ($this->offsetExists($offset)) { + return (bool) (ord($this->bitmap[(int) ($offset / 8)]) & (1 << $offset % 8)); + } else { + throw new \OutOfRangeException(); + } + } + + public function offsetSet($offset, $value) + { + if ($this->offsetExists($offset)) { + $index = (int) ($offset / 8); + if ($value) { + $this->bitmap[$index] = chr(ord($this->bitmap[$index]) | (1 << $offset % 8)); + } else { + $this->bitmap[$index] = chr(ord($this->bitmap[$index]) & ~(1 << $offset % 8)); + } + } else { + throw new \OutOfRangeException(); + } + } + + public function offsetUnset($offset) { + throw new \RuntimeException("Bitmap does not support offsetUnset"); + } +} From 8cd49f0f68b43f4176171975d43a202f47c96aa5 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Sat, 12 Mar 2016 18:57:49 +0100 Subject: [PATCH 03/19] Replace standard php boolean array with custom Bitmap class --- src/AttributedString.php | 42 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/AttributedString.php b/src/AttributedString.php index 7f0e2a8..6b9ec32 100644 --- a/src/AttributedString.php +++ b/src/AttributedString.php @@ -54,7 +54,7 @@ public function createAttribute($attribute) { throw new \InvalidArgumentException(); } - $this->attributes[$attribute] = array_fill(0, $this->length, false); + $this->attributes[$attribute] = new Bitmap($this->length); } /** @@ -99,7 +99,9 @@ public function setRange($from, $to, $attribute, $state = true) { } // Set attribute state for given range - $this->attributes[$attribute] = array_replace($this->attributes[$attribute], array_fill($from, $to-$from+1, $state)); + for($i = $from; $i <= $to; $i++) { + $this->attributes[$attribute][$i] = $state; + } } /** @@ -173,26 +175,20 @@ public function searchAttribute($attribute, $offset = 0, $returnLength = false, } $a = $this->attributes[$attribute]; - - if ($offset) { - $a = array_slice($a, $offset, NULL, true); - } - - $pos = array_search($state, $a, $strict); - - if ($returnLength) { - if (false === $pos) { - return false; + for ($i = $offset; $i < $this->length; $i++) { + if (($strict and $a[$i] === $state) or (!$strict and $a[$i] == $state)) { + if ($returnLength) { + $length = $this->searchAttribute($attribute, $i, false, !$state, $strict); + $length = $length ? $length - $i : $this->length - $i; + + return [$i, $length]; + } else { + return $i; + } } - - $a = array_slice($a, $pos - $offset); - $length = array_search(!$state, $a, $strict); - $length = $length ? $length : $this->length - $pos; - - return [$pos, $length]; - } else { - return $pos; } + + return false; } /** @@ -389,11 +385,7 @@ public function combineAttributes($op, $attribute1, $attribute2 = false, $to = f * @param string $false char to use for false state of attribute */ public function attributeToString($attribute, $true = "-", $false = " ") { - $map = $this->attributes[$attribute]; - - return implode("", array_map(function($v) use ($true, $false) { - return $v ? $true : $false; - }, $map)); + return $this->attributes[$attribute]->toString($true, $false); } /** From 9a8dc6f54ccef1093eca94b2e17624f862b90a20 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Mon, 14 Mar 2016 09:31:32 +0100 Subject: [PATCH 04/19] implement/test Bitmap countable --- src/Bitmap.php | 15 +++++++++++++-- test/unit/BitmapTest.php | 5 ++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Bitmap.php b/src/Bitmap.php index 783fbf3..ee231f1 100644 --- a/src/Bitmap.php +++ b/src/Bitmap.php @@ -1,14 +1,14 @@ length = $length; - $this->bitmap = str_repeat("\0", ceil($this->length / 8)); + $this->bitmap = str_repeat(chr(0), ceil($this->length / 8)); } public function __toString() { @@ -58,4 +58,15 @@ public function offsetSet($offset, $value) public function offsetUnset($offset) { throw new \RuntimeException("Bitmap does not support offsetUnset"); } + + // Countable interface + + /** + * Return bitmap length + * + * @return int bitmap length + */ + public function count() { + return $this->length; + } } diff --git a/test/unit/BitmapTest.php b/test/unit/BitmapTest.php index 357ca58..71deae4 100644 --- a/test/unit/BitmapTest.php +++ b/test/unit/BitmapTest.php @@ -17,5 +17,8 @@ public function testArrayAccess() { unset($b[0]); } - + public function testCountable() { + $b = new Bitmap(10); + $this->assertEquals(10, count($b)); + } } From 4235cdb9599434c22fe7983f64a8fc763a68c410 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Mon, 14 Mar 2016 21:25:33 +0100 Subject: [PATCH 05/19] add interface for Attribute implementations --- src/Attribute.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Attribute.php diff --git a/src/Attribute.php b/src/Attribute.php new file mode 100644 index 0000000..c92eea0 --- /dev/null +++ b/src/Attribute.php @@ -0,0 +1,9 @@ + Date: Mon, 14 Mar 2016 21:26:05 +0100 Subject: [PATCH 06/19] Bitmap implements Attribute interface --- src/Bitmap.php | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Bitmap.php b/src/Bitmap.php index ee231f1..81f268a 100644 --- a/src/Bitmap.php +++ b/src/Bitmap.php @@ -1,7 +1,7 @@ offsetSet($i, $state); + } + } + + /** + * Search inside bitmap for ranges with the given state + * + * @param int $offset start offset + * @param bool $returnLength if true (default is false), return an array with position and length of the found range + * @param bool $state the state to look for (default is true) + * @param bool $strict perform strict comparison during search + * @return int|int[] either position or position and lenght in an array + */ + public function search($offset = 0, $returnLength = false, $state = true, $strict = true) { + for ($i = $offset; $i < $this->length; $i++) { + if (($strict and $this->offsetGet($i) === $state) or (!$strict and $this->offsetGet($i) == $state)) { + if ($returnLength) { + $length = $this->search($i, false, !$state, $strict); + $length = $length ? $length - $i : $this->length - $i; + + return [$i, $length]; + } else { + return $i; + } + } + } + + return false; + } + // ArrayAccess interface public function offsetExists($offset) { From 28fe992f20c91dc18ae0d10360393c6377e18467 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Mon, 14 Mar 2016 21:26:41 +0100 Subject: [PATCH 07/19] rewrite AttributedString to use generic Attribute storage --- src/AttributedString.php | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/AttributedString.php b/src/AttributedString.php index 6b9ec32..6870eaa 100644 --- a/src/AttributedString.php +++ b/src/AttributedString.php @@ -99,9 +99,7 @@ public function setRange($from, $to, $attribute, $state = true) { } // Set attribute state for given range - for($i = $from; $i <= $to; $i++) { - $this->attributes[$attribute][$i] = $state; - } + $this->attributes[$attribute]->setRange($from, $to, $state); } /** @@ -174,21 +172,7 @@ public function searchAttribute($attribute, $offset = 0, $returnLength = false, return false; } - $a = $this->attributes[$attribute]; - for ($i = $offset; $i < $this->length; $i++) { - if (($strict and $a[$i] === $state) or (!$strict and $a[$i] == $state)) { - if ($returnLength) { - $length = $this->searchAttribute($attribute, $i, false, !$state, $strict); - $length = $length ? $length - $i : $this->length - $i; - - return [$i, $length]; - } else { - return $i; - } - } - } - - return false; + return $this->attributes[$attribute]->search($offset, $returnLength, $state, $strict); } /** @@ -342,8 +326,8 @@ public function combineAttributes($op, $attribute1, $attribute2 = false, $to = f throw new \InvalidArgumentException("Attribute does not exist"); } - if (!isset($this->attributes[$to])) { - $this->attributes[$to] = []; // No need to init because array is created below + if (!$this->hasAttribute($to)) { + $this->createAttribute($to); } // Switch outside the loops for speed From f163377a7f4dbc7b2483745e68c106e5e87dabd0 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Mon, 14 Mar 2016 21:46:34 +0100 Subject: [PATCH 08/19] Add BooleanArray class implementing Attribute interface --- src/BooleanArray.php | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/BooleanArray.php diff --git a/src/BooleanArray.php b/src/BooleanArray.php new file mode 100644 index 0000000..660aee8 --- /dev/null +++ b/src/BooleanArray.php @@ -0,0 +1,97 @@ +length = $length; + $this->attribute = []; + } + + public function __toString() { + return $this->toString(); + } + + public function toString($true = "1", $false = "0") { + return implode("", array_map(function($v) use ($true, $false) { + return $v ? $true : $false; + }, $this->attribute)); + } + + /** + * Set given range to a state + * + * @param int $from start offset + * @param int $to end offset + * @param bool $state set state to true (default) or false + */ + public function setRange($from, $to, $state = true) { + // Set attribute state for given range + $this->attribute = array_replace($this->attribute, array_fill($from, $to-$from+1, $state)); + } + + /** + * Search inside bitmap for ranges with the given state + * + * @param int $offset start offset + * @param bool $returnLength if true (default is false), return an array with position and length of the found range + * @param bool $state the state to look for (default is true) + * @param bool $strict perform strict comparison during search + * @return int|int[] either position or position and lenght in an array + */ + public function search($offset = 0, $returnLength = false, $state = true, $strict = true) { + $a = $this->attribute; + if ($offset) { + $a = array_slice($a, $offset, NULL, true); + } + + $pos = array_search($state, $a, $strict); + + if ($returnLength) { + if (false === $pos) { + return false; + } + + $a = array_slice($a, $pos - $offset); + $length = array_search(!$state, $a, $strict); + $length = $length ? $length : $this->length - $pos; + return [$pos, $length]; + } else { + return $pos; + } + } + + // ArrayAccess interface + + public function offsetExists($offset) { + return $offest < $this->length; + } + + public function offsetGet($offset) + { + return $this->attribute[$offset]; + } + + public function offsetSet($offset, $value) + { + $this->attribute[$offset] = $value; + } + + public function offsetUnset($offset) { + unset($this->attribute[$offset]); + } + + // Countable interface + + /** + * Return array length + * + * @return int array length + */ + public function count() { + return $this->length; + } +} From 80d52eabe0f45171858d2417836f36d4ed86632b Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Mon, 14 Mar 2016 21:47:04 +0100 Subject: [PATCH 09/19] AttributedString: Allow injecting a custom Attribute class --- src/AttributedString.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AttributedString.php b/src/AttributedString.php index 6870eaa..7618698 100644 --- a/src/AttributedString.php +++ b/src/AttributedString.php @@ -14,11 +14,12 @@ class AttributedString implements \Countable, \ArrayAccess protected $attributes = []; protected $length; protected $byteToChar; + protected $attributeClass; /** * @param string|AttributedString $string Either a simple string or another AttributedString to init the AttributedString */ - public function __construct($string) { + public function __construct($string, $attributeClass = "apemsel\AttributedString\Bitmap") { if (is_string($string)) { $this->string = $string; $this->length = mb_strlen($string, "utf-8"); @@ -32,6 +33,8 @@ public function __construct($string) { else { throw new \InvalidArgumentException(); } + + $this->attributeClass = $attributeClass; } /** @@ -54,7 +57,7 @@ public function createAttribute($attribute) { throw new \InvalidArgumentException(); } - $this->attributes[$attribute] = new Bitmap($this->length); + $this->attributes[$attribute] = new $this->attributeClass($this->length); } /** From 1d9169672e03706f4e231fbd7492ce827c20a08d Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Tue, 15 Mar 2016 22:10:00 +0100 Subject: [PATCH 10/19] fixes for BooleanArray, implement insert() and delete() --- src/BooleanArray.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/BooleanArray.php b/src/BooleanArray.php index 660aee8..5e19257 100644 --- a/src/BooleanArray.php +++ b/src/BooleanArray.php @@ -8,7 +8,7 @@ class BooleanArray implements Attribute public function __construct($length) { $this->length = $length; - $this->attribute = []; + $this->attribute = array_fill(0, $length, false); } public function __toString() { @@ -64,10 +64,18 @@ public function search($offset = 0, $returnLength = false, $state = true, $stric } } + public function insert($pos, $length, $state) { + array_splice($this->attribute, $pos, 0, array_fill(0, $length, $state)); + } + + public function delete($pos, $length) { + array_splice($this->attribute, $pos, $length); + } + // ArrayAccess interface public function offsetExists($offset) { - return $offest < $this->length; + return $offset < $this->length; } public function offsetGet($offset) From 8b2b0fad78dc2f66970f27f928faba70e944c669 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Tue, 15 Mar 2016 22:10:36 +0100 Subject: [PATCH 11/19] MutableAttributedString: use attributes insert() and delete() instead of manipulating it directly --- src/MutableAttributedString.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/MutableAttributedString.php b/src/MutableAttributedString.php index 6f144c0..9bb9276 100644 --- a/src/MutableAttributedString.php +++ b/src/MutableAttributedString.php @@ -28,18 +28,18 @@ public function insert($pos, $string) { $this->length += $length; $this->byte2Char = []; // invalidate cache - foreach ($this->attributes as $attribute => &$map) { + foreach ($this->attributes as $name => $attribute) { // Check state of surrounding map to determine state of inserted part $state = false; - $maxPos = count($map) - 1; - $leftState = $map[min($maxPos, $pos)]; - $rightState = $map[min($maxPos, $pos + 1)]; + $maxPos = count($attribute) - 1; + $leftState = $attribute[min($maxPos, $pos)]; + $rightState = $attribute[min($maxPos, $pos + 1)]; if ($leftState == $rightState) { $state = $leftState; } - array_splice($map, $pos, 0, array_fill(0, $length, $state)); + $attribute->insert($pos, $length, $state); } } @@ -63,8 +63,8 @@ public function delete($pos, $length) { $this->string = $leftPart.$rightPart; $this->length -= $length; - foreach ($this->attributes as $attribute => &$map) { - array_splice($map, $pos, $length); + foreach ($this->attributes as $name => $attribute) { + $attribute->delete($pos, $length); } } From 9b40e6a5aff0eefe68e65f2f391e0f874719d61e Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Tue, 15 Mar 2016 22:11:23 +0100 Subject: [PATCH 12/19] AttributedString: add getAttribute(), change default attribute class to BooleanArray --- src/AttributedString.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/AttributedString.php b/src/AttributedString.php index 7618698..90c1d0d 100644 --- a/src/AttributedString.php +++ b/src/AttributedString.php @@ -19,7 +19,7 @@ class AttributedString implements \Countable, \ArrayAccess /** * @param string|AttributedString $string Either a simple string or another AttributedString to init the AttributedString */ - public function __construct($string, $attributeClass = "apemsel\AttributedString\Bitmap") { + public function __construct($string, $attributeClass = "apemsel\AttributedString\BooleanArray") { if (is_string($string)) { $this->string = $string; $this->length = mb_strlen($string, "utf-8"); @@ -375,6 +375,16 @@ public function attributeToString($attribute, $true = "-", $false = " ") { return $this->attributes[$attribute]->toString($true, $false); } + /** + * Return attribute object + * + * @param string $attribute name of the attribute + * @return object an object implementing the attribute interface + */ + public function getAttribute($attribute) { + return $this->attributes[$attribute]; + } + /** * Enable and fill cache for byte to char offset conversion * From e430f2eb26e75489d2ecbbe256a1da772113fa96 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Tue, 15 Mar 2016 22:23:55 +0100 Subject: [PATCH 13/19] fix last bug in BooleanArray, all tests pass --- src/BooleanArray.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BooleanArray.php b/src/BooleanArray.php index 5e19257..9b90291 100644 --- a/src/BooleanArray.php +++ b/src/BooleanArray.php @@ -65,10 +65,12 @@ public function search($offset = 0, $returnLength = false, $state = true, $stric } public function insert($pos, $length, $state) { + $this->length += $length; array_splice($this->attribute, $pos, 0, array_fill(0, $length, $state)); } public function delete($pos, $length) { + $this->length -= $length; array_splice($this->attribute, $pos, $length); } From 2b095ae9750e3c51cf10571a9913f792b246d775 Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Wed, 16 Mar 2016 09:53:00 +0100 Subject: [PATCH 14/19] documentation for Bitmap class --- src/Bitmap.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/Bitmap.php b/src/Bitmap.php index 81f268a..a963c0d 100644 --- a/src/Bitmap.php +++ b/src/Bitmap.php @@ -1,20 +1,42 @@ + */ class Bitmap implements Attribute { protected $bitmap; protected $length; + /** + * @param int length of bitmask + */ public function __construct($length) { $this->length = $length; $this->bitmap = str_repeat(chr(0), ceil($this->length / 8)); } + /** + * Returns the bitmask as a visual string + * + * @return string bitmask as visual string of 0s and 1s + */ public function __toString() { return $this->toString(); } + /** + * Returns the bitmask as a visual string with custom chars for 0s and 1s + * + * @param string $true representation of 1s + * @param string $true representation of 0s + * @return string bitmask as visual string of 0s and 1s + */ public function toString($true = "1", $false = "0") { $string = str_repeat($false, $this->length); for ($offset = 0; $offset < $this->length; $offset++) { @@ -68,10 +90,22 @@ public function search($offset = 0, $returnLength = false, $state = true, $stric // ArrayAccess interface + /** + * Check if the given offset exists in the bitmap + * + * @param int $offset offset + * @return bool does the offset exist + */ public function offsetExists($offset) { return is_int($offset) && $offset >= 0 && $offset < $this->length; } + /** + * Get bit at given offset + * + * @param int $offset offset + * @return bool bit at given offset + */ public function offsetGet($offset) { if ($this->offsetExists($offset)) { @@ -81,6 +115,12 @@ public function offsetGet($offset) } } + /** + * Set bit at given offset + * + * @param int $offset offset + * @param bool $value bit at given offset + */ public function offsetSet($offset, $value) { if ($this->offsetExists($offset)) { @@ -95,6 +135,11 @@ public function offsetSet($offset, $value) } } + /** + * Unset bit at given offset - not implemented + * + * @throws RuntimeException always + */ public function offsetUnset($offset) { throw new \RuntimeException("Bitmap does not support offsetUnset"); } From fcee8d4821ff7eb3f59f263e416e23d83a1c636e Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Wed, 16 Mar 2016 09:55:32 +0100 Subject: [PATCH 15/19] AttributedString: Add missing docblock, throw runtime exception instead of InvalidArgumentException for unimplemented methods --- src/AttributedString.php | 16 +++++++++++----- test/unit/AttributedStringTest.php | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/AttributedString.php b/src/AttributedString.php index 90c1d0d..2857da0 100644 --- a/src/AttributedString.php +++ b/src/AttributedString.php @@ -18,6 +18,7 @@ class AttributedString implements \Countable, \ArrayAccess /** * @param string|AttributedString $string Either a simple string or another AttributedString to init the AttributedString + * @param string $attributeClass Class to use for attributes */ public function __construct($string, $attributeClass = "apemsel\AttributedString\BooleanArray") { if (is_string($string)) { @@ -70,6 +71,11 @@ public function hasAttribute($attribute) { return isset($this->attributes[$attribute]); } + /** + * Delete an attribute + * + * @param string $attribute The name of the attribute to delete + */ public function deleteAttribute($attribute) { if (isset($this->attributes[$attribute])) { unset($this->attributes[$attribute]); @@ -376,7 +382,7 @@ public function attributeToString($attribute, $true = "-", $false = " ") { } /** - * Return attribute object + * Return attribute instance * * @param string $attribute name of the attribute * @return object an object implementing the attribute interface @@ -480,18 +486,18 @@ public function offsetGet($offset) { /** * Not implemented since AttributedString is immutable * - * @throws InvalidArgumentException always + * @throws RuntimeException always */ public function offsetSet($offset, $value) { - throw new \InvalidArgumentException("AttributedString is immutable"); + throw new \RuntimeException("AttributedString is immutable"); } /** * Not implemented since AttributedString is immutable * - * @throws InvalidArgumentException always + * @throws RuntimeException always */ public function offsetUnset($offset) { - throw new \InvalidArgumentException("AttributedString is immutable"); + throw new \RuntimeException("AttributedString is immutable"); } } diff --git a/test/unit/AttributedStringTest.php b/test/unit/AttributedStringTest.php index a4a6b11..f09d9ea 100644 --- a/test/unit/AttributedStringTest.php +++ b/test/unit/AttributedStringTest.php @@ -177,7 +177,7 @@ public function testArrayAccess() { $this->assertEquals("f", $as[0]); $this->assertEquals("ò", $as[2]); - $this->setExpectedException('InvalidArgumentException'); + $this->setExpectedException('RuntimeException'); $as[0] = "z"; } } From a17108252bdc66c3fc480db48854c24d7044419a Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Wed, 16 Mar 2016 10:16:22 +0100 Subject: [PATCH 16/19] Add MutableAttribute interface --- src/MutableAttribute.php | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/MutableAttribute.php diff --git a/src/MutableAttribute.php b/src/MutableAttribute.php new file mode 100644 index 0000000..d313304 --- /dev/null +++ b/src/MutableAttribute.php @@ -0,0 +1,8 @@ + Date: Wed, 16 Mar 2016 10:16:39 +0100 Subject: [PATCH 17/19] Make TokenizedAttributedString pass throught attribute class --- src/Bitmap.php | 4 +- src/BooleanArray.php | 70 ++++++++++++++++++++++++++++--- src/TokenizedAttributedString.php | 4 +- 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/Bitmap.php b/src/Bitmap.php index a963c0d..fd1cd98 100644 --- a/src/Bitmap.php +++ b/src/Bitmap.php @@ -4,7 +4,7 @@ /** * Bitmap * - * A memory-efficient Attribute implementation using a bitmask stored in a string. + * A memory efficient Attribute implementation using a bitmask stored in a string. * * @author Adrian Pemsel */ @@ -35,7 +35,7 @@ public function __toString() { * * @param string $true representation of 1s * @param string $true representation of 0s - * @return string bitmask as visual string of 0s and 1s + * @return string bitmask as visual string of the given representations */ public function toString($true = "1", $false = "0") { $string = str_repeat($false, $this->length); diff --git a/src/BooleanArray.php b/src/BooleanArray.php index 9b90291..0aa66be 100644 --- a/src/BooleanArray.php +++ b/src/BooleanArray.php @@ -1,20 +1,42 @@ + */ +class BooleanArray implements MutableAttribute { protected $attribute; protected $length; + /** + * @param int length of array + */ public function __construct($length) { $this->length = $length; $this->attribute = array_fill(0, $length, false); } + /** + * Returns the array as a visual string + * + * @return string array as visual string of 0s and 1s + */ public function __toString() { return $this->toString(); } + /** + * Returns the array as a visual string with custom chars for 0s and 1s + * + * @param string $true representation of 1s + * @param string $true representation of 0s + * @return string array as visual string of the given representations + */ public function toString($true = "1", $false = "0") { return implode("", array_map(function($v) use ($true, $false) { return $v ? $true : $false; @@ -64,32 +86,70 @@ public function search($offset = 0, $returnLength = false, $state = true, $stric } } - public function insert($pos, $length, $state) { + // MutableAttribute interface + + /** + * Insert a piece into the array at given offset with a given state and length + * + * @param int $offset offset + * @param int $length length of inserted piece + * @param bool $state state of inserted piece + */ + public function insert($offset, $length, $state) { $this->length += $length; - array_splice($this->attribute, $pos, 0, array_fill(0, $length, $state)); + array_splice($this->attribute, $offset, 0, array_fill(0, $length, $state)); } - public function delete($pos, $length) { + /** + * Delete a piece of the array at given offset with a given length + * + * @param int $offset offset + * @param int $length length of inserted piece + */ + public function delete($offset, $length) { $this->length -= $length; - array_splice($this->attribute, $pos, $length); + array_splice($this->attribute, $offset, $length); } // ArrayAccess interface + /** + * Check if the given offset exists in the array + * + * @param int $offset offset + * @return bool does the offset exist + */ public function offsetExists($offset) { return $offset < $this->length; } + /** + * Get bool at given offset + * + * @param int $offset offset + * @return bool bit at given offset + */ public function offsetGet($offset) { return $this->attribute[$offset]; } + /** + * Set bool at given offset + * + * @param int $offset offset + * @param bool $value bit at given offset + */ public function offsetSet($offset, $value) { $this->attribute[$offset] = $value; } + /** + * Unset bit at given offset + * + * @param int $offset offset + */ public function offsetUnset($offset) { unset($this->attribute[$offset]); } diff --git a/src/TokenizedAttributedString.php b/src/TokenizedAttributedString.php index 773d5df..78507de 100644 --- a/src/TokenizedAttributedString.php +++ b/src/TokenizedAttributedString.php @@ -18,8 +18,8 @@ class TokenizedAttributedString extends AttributedString * @param string|AttributedString $string String to work on * @param string $tokenizer Tokenizer to use, either "whitespace", "word" or a custom regex */ - public function __construct($string, $tokenizer = "whitespace") { - parent::__construct($string); + public function __construct($string, $tokenizer = "whitespace", $attributeClass = "apemsel\AttributedString\BooleanArray") { + parent::__construct($string, $attributeClass); $tokenizerFunction = "tokenizeOn".ucfirst($tokenizer); From b89985ac1202a4f23ec084cb1a24a1867a56596f Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Wed, 16 Mar 2016 10:31:19 +0100 Subject: [PATCH 18/19] MutableAttributedString constructor checks if attribute class is mutable --- src/MutableAttributedString.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/MutableAttributedString.php b/src/MutableAttributedString.php index 9bb9276..09e00a0 100644 --- a/src/MutableAttributedString.php +++ b/src/MutableAttributedString.php @@ -10,6 +10,18 @@ */ class MutableAttributedString extends AttributedString { + /** + * @param string|AttributedString $string Either a simple string or another AttributedString to init the AttributedString + * @param string $attributeClass Class to use for attributes + */ + public function __construct($string, $attributeClass = "apemsel\AttributedString\BooleanArray") { + if (!in_array("apemsel\AttributedString\MutableAttribute", class_implements($attributeClass))) { + throw new \InvalidArgumentException("MutableAttributedString can only be used with attributes implementing MutableAttribute"); + } + + parent::__construct($string, $attributeClass); + } + /** * Insert string at given offset * From 012fb75b2f3fd35e04e683c4e89b48320ed8810d Mon Sep 17 00:00:00 2001 From: Adrian Pemsel Date: Wed, 16 Mar 2016 10:34:54 +0100 Subject: [PATCH 19/19] update documentation --- doc/404.html | 7 + ...ss-apemsel.AttributedString.Attribute.html | 269 +++++ ...sel.AttributedString.AttributedString.html | 141 ++- ...class-apemsel.AttributedString.Bitmap.html | 593 +++++++++++ ...apemsel.AttributedString.BooleanArray.html | 672 ++++++++++++ ...sel.AttributedString.MutableAttribute.html | 239 +++++ ...ributedString.MutableAttributedString.html | 64 +- ...butedString.TokenizedAttributedString.html | 13 +- doc/elementlist.js | 2 +- doc/index.html | 9 +- doc/namespace-apemsel.AttributedString.html | 30 +- doc/namespace-apemsel.html | 2 +- ...ss-apemsel.AttributedString.Attribute.html | 111 ++ ...sel.AttributedString.AttributedString.html | 968 +++++++++--------- ...class-apemsel.AttributedString.Bitmap.html | 259 +++++ ...apemsel.AttributedString.BooleanArray.html | 269 +++++ ...sel.AttributedString.MutableAttribute.html | 110 ++ ...ributedString.MutableAttributedString.html | 265 ++--- ...butedString.TokenizedAttributedString.html | 13 +- 19 files changed, 3381 insertions(+), 655 deletions(-) create mode 100644 doc/class-apemsel.AttributedString.Attribute.html create mode 100644 doc/class-apemsel.AttributedString.Bitmap.html create mode 100644 doc/class-apemsel.AttributedString.BooleanArray.html create mode 100644 doc/class-apemsel.AttributedString.MutableAttribute.html create mode 100644 doc/source-class-apemsel.AttributedString.Attribute.html create mode 100644 doc/source-class-apemsel.AttributedString.Bitmap.html create mode 100644 doc/source-class-apemsel.AttributedString.BooleanArray.html create mode 100644 doc/source-class-apemsel.AttributedString.MutableAttribute.html diff --git a/doc/404.html b/doc/404.html index 6ebe688..20a7515 100644 --- a/doc/404.html +++ b/doc/404.html @@ -66,10 +66,17 @@

Namespaces

Classes

+

Interfaces

+ diff --git a/doc/class-apemsel.AttributedString.Attribute.html b/doc/class-apemsel.AttributedString.Attribute.html new file mode 100644 index 0000000..93d3711 --- /dev/null +++ b/doc/class-apemsel.AttributedString.Attribute.html @@ -0,0 +1,269 @@ + + + + + + Interface apemsel\AttributedString\Attribute + + + + + + + + + +
+ +
+ +
+ + + + + + diff --git a/doc/class-apemsel.AttributedString.AttributedString.html b/doc/class-apemsel.AttributedString.AttributedString.html index f7c9716..bafb431 100644 --- a/doc/class-apemsel.AttributedString.AttributedString.html +++ b/doc/class-apemsel.AttributedString.AttributedString.html @@ -66,10 +66,17 @@

Namespaces

Classes

+

Interfaces

+ @@ -126,7 +133,7 @@

Direct known subclasses

Author: Adrian Pemsel apemsel@gmail.com
- Located at AttributedString.php + Located at AttributedString.php
@@ -146,7 +153,7 @@

Direct known subclasses

# - __construct( string|apemsel\AttributedString\AttributedString $string ) + __construct( string|apemsel\AttributedString\AttributedString $string, string $attributeClass = "apemsel\AttributedString\BooleanArray" )
@@ -160,6 +167,8 @@

Parameters

$string
Either a simple string or another AttributedString to init the AttributedString
+
$attributeClass
+
Class to use for attributes
@@ -180,7 +189,7 @@

Parameters

# - __toString( ) + __toString( )

Returns the native string

@@ -213,7 +222,7 @@

Returns

# - createAttribute( string $attribute ) + createAttribute( string $attribute )

Creates a new attribute layer

@@ -251,7 +260,7 @@

Throws

# - hasAttribute( string $attribute ) + hasAttribute( string $attribute )

Check if the given attribute exists

@@ -289,16 +298,21 @@

Returns

# - deleteAttribute( $attribute ) + deleteAttribute( string $attribute )
- +

Delete an attribute