Skip to content

Commit

Permalink
Added align methods
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Zoppi <[email protected]>
  • Loading branch information
TexZK committed Mar 7, 2024
1 parent 07a8fa9 commit 1a78f87
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

0.1.1 (2024-03-07)
------------------

* Added ``align`` methods.


0.1.0 (2024-02-22)
------------------

Expand Down
3 changes: 3 additions & 0 deletions docs/_autosummary/bytesparse.base.MutableBytesparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ MutableBytesparse
:nosignatures:

~MutableBytesparse.__init__
~MutableBytesparse.align
~MutableBytesparse.align_backup
~MutableBytesparse.align_restore
~MutableBytesparse.append
~MutableBytesparse.append_backup
~MutableBytesparse.append_restore
Expand Down
3 changes: 3 additions & 0 deletions docs/_autosummary/bytesparse.base.MutableMemory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ MutableMemory
:nosignatures:

~MutableMemory.__init__
~MutableMemory.align
~MutableMemory.align_backup
~MutableMemory.align_restore
~MutableMemory.append
~MutableMemory.append_backup
~MutableMemory.append_restore
Expand Down
3 changes: 3 additions & 0 deletions docs/_autosummary/bytesparse.inplace.Memory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Memory
:nosignatures:

~Memory.__init__
~Memory.align
~Memory.align_backup
~Memory.align_restore
~Memory.append
~Memory.append_backup
~Memory.append_restore
Expand Down
3 changes: 3 additions & 0 deletions docs/_autosummary/bytesparse.inplace.bytesparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ bytesparse
:nosignatures:

~bytesparse.__init__
~bytesparse.align
~bytesparse.align_backup
~bytesparse.align_restore
~bytesparse.append
~bytesparse.append_backup
~bytesparse.append_restore
Expand Down
2 changes: 1 addition & 1 deletion src/bytesparse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"""

__version__ = '0.1.0'
__version__ = '0.1.1'

from .inplace import Memory
from .inplace import bytesparse
Expand Down
125 changes: 124 additions & 1 deletion src/bytesparse/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3777,6 +3777,129 @@ def _prebound_start_backup(
"""
...

@abc.abstractmethod
def align(
self,
modulo: int,
start: Optional[Address] = None,
endex: Optional[Address] = None,
pattern: Union[AnyBytes, Value] = 0,
) -> None:
r"""Floods blocks to align their boundaries.
Arguments:
modulo (int):
Alignment modulo.
start (int):
Inclusive start address for flooding.
If ``None``, :attr:`start` is considered.
endex (int):
Exclusive end address for flooding.
If ``None``, :attr:`endex` is considered.
pattern (items):
Pattern of items to fill the range.
See Also:
:meth:`align_backup`
:meth:`align_restore`
:meth:`flood`
Examples:
>>> from bytesparse import Memory
+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
+===+===+===+===+===+===+===+===+===+===+===+===+===+
| |[A | B | C]| | |[x | y | z]| | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|[0 | A | B | C | 0 | 1 | x | y | z | 1 | 2 | 3]| |
+---+---+---+---+---+---+---+---+---+---+---+---+---+
>>> memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
>>> memory.align(4, pattern=b'0123')
>>> memory.to_blocks()
[[0, b'0ABC01xyz123']]
~~~
+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
+===+===+===+===+===+===+===+===+===+===+===+===+===+
| |[A | B | C]| | | |[0 | 1 | 2 | 3]| | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|[x | A | B | C]| | |[x | 0 | 1 | 2 | 3 | z]| |
+---+---+---+---+---+---+---+---+---+---+---+---+---+
>>> memory = Memory.from_blocks([[1, b'ABC'], [7, b'0123']])
>>> memory.align(2, pattern=b'xyz')
>>> memory.to_blocks()
[[0, b'xABC'], [6, b'x0123z']]
~~~
+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+===+===+===+===+===+===+===+===+===+===+
| |[A | B | C]| | |[x | y | z]| |
+---+---+---+---+---+---+---+---+---+---+
>>> memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
>>> memory.align(2, start=3, endex=7, pattern=b'.@')
>>> memory.to_blocks()
[[1, b'ABC'], [6, b'xyz']]
"""
...

@abc.abstractmethod
def align_backup(
self,
modulo: int,
start: Optional[Address] = None,
endex: Optional[Address] = None,
) -> List[OpenInterval]:
r"""Backups an `align()` operation.
Arguments:
modulo (int):
Alignment modulo.
start (int):
Inclusive start address for filling.
If ``None``, :attr:`start` is considered.
endex (int):
Exclusive end address for filling.
If ``None``, :attr:`endex` is considered.
Returns:
list of open intervals: Backup memory gaps.
See Also:
:meth:`align`
:meth:`align_restore`
"""
...

@abc.abstractmethod
def align_restore(
self,
gaps: List[OpenInterval],
) -> None:
r"""Restores an `align()` operation.
Arguments:
gaps (list of open intervals):
Backup memory gaps to restore.
See Also:
:meth:`align`
:meth:`align_backup`
"""
...

@abc.abstractmethod
def append(
self,
Expand Down Expand Up @@ -4397,7 +4520,7 @@ def flood(
+---+---+---+---+---+---+---+---+---+---+
>>> memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
>>> memory.flood(3, 7, b'123')
>>> memory.flood(start=3, endex=7, pattern=b'123')
>>> memory.to_blocks()
[[1, b'ABC23xyz']]
"""
Expand Down
57 changes: 57 additions & 0 deletions src/bytesparse/inplace.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,63 @@ def _prebound_start_backup(
else:
return self.__class__()

def align(
self,
modulo: int,
start: Optional[Address] = None,
endex: Optional[Address] = None,
pattern: Union[AnyBytes, Value] = 0,
) -> None:

modulo = modulo.__index__()
if modulo < 1:
raise ValueError('invalid modulo')
if modulo == 1:
return

for start, endex in self.intervals(start=start, endex=endex):
start_offset = start % modulo
if start_offset:
start -= start_offset

endex_offset = endex % modulo
if endex_offset:
endex += modulo - endex_offset

if start_offset or endex_offset:
self.flood(start=start, endex=endex, pattern=pattern)

def align_backup(
self,
modulo: int,
start: Optional[Address] = None,
endex: Optional[Address] = None,
) -> List[OpenInterval]:

modulo = modulo.__index__()
if modulo < 1:
raise ValueError('invalid modulo')

start, endex = self.bound(start, endex)

if modulo != 1:
start_offset = start % modulo
if start_offset:
start -= start_offset

endex_offset = endex % modulo
if endex_offset:
endex += modulo - endex_offset

return self.flood_backup(start=start, endex=endex)

def align_restore(
self,
gaps: List[OpenInterval],
) -> None:

self.flood_restore(gaps)

def append(
self,
item: Union[AnyBytes, Value],
Expand Down
121 changes: 120 additions & 1 deletion tests/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4551,7 +4551,7 @@ def test_flood_doctest(self):
assert memory.to_blocks() == [[1, b'ABC12xyz']]

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
memory.flood(3, 7, b'123')
memory.flood(start=3, endex=7, pattern=b'123')
assert memory.to_blocks() == [[1, b'ABC23xyz']]

def test_flood_template(self):
Expand Down Expand Up @@ -4603,6 +4603,125 @@ def test_flood_backup_doctest(self):
def test_flood_restore_doctest(self):
pass # no doctest

def test_align_doctest(self):
Memory = self.Memory

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
memory.align(4, pattern=b'0123')
assert memory.to_blocks() == [[0, b'0ABC01xyz123']]

memory = Memory.from_blocks([[1, b'ABC'], [7, b'0123']])
memory.align(2, pattern=b'xyz')
assert memory.to_blocks() == [[0, b'xABC'], [6, b'x0123z']]

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
memory.align(2, start=3, endex=7, pattern=b'.@')
assert memory.to_blocks() == [[1, b'ABC'], [6, b'xyz']]

def test_align(self):
Memory = self.Memory

memory = Memory()
memory.align(4)
assert memory.to_blocks() == []

blocks = [[0, b'ABCD'], [8, b'xyz!']]
memory = Memory.from_blocks(blocks)
memory.align(4)
assert memory.to_blocks() == blocks

blocks = [[1, b'ABC'], [6, b'xyz']]
memory = Memory.from_blocks(blocks)
memory.align(1)
assert memory.to_blocks() == blocks

def test_align_invalid_modulo(self):
Memory = self.Memory
memory = Memory()

with pytest.raises(ValueError, match='invalid modulo'):
memory.align(0)

with pytest.raises(ValueError, match='invalid modulo'):
memory.align(-1)

def test_align_backup_doctest(self):
pass # no doctest

def test_align_backup(self):
Memory = self.Memory

memory = Memory()
backup = memory.align_backup(4)
assert backup == [(None, None)]

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
backup = memory.align_backup(4)
assert backup == [(0, 1), (4, 6), (9, 12)]

memory = Memory.from_blocks([[1, b'ABC'], [7, b'0123']])
backup = memory.align_backup(2)
assert backup == [(0, 1), (4, 7), (11, 12)]

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
backup = memory.align_backup(2, start=3, endex=7)
assert backup == [(4, 6)]

blocks = [[0, b'ABCD'], [8, b'xyz!']]
memory = Memory.from_blocks(blocks)
backup = memory.align_backup(4)
assert backup == [(4, 8)]

blocks = [[1, b'ABC'], [6, b'xyz']]
memory = Memory.from_blocks(blocks)
backup = memory.align_backup(1)
assert backup == [(4, 6)]

def test_align_backup_invalid_modulo(self):
Memory = self.Memory
memory = Memory()

with pytest.raises(ValueError, match='invalid modulo'):
memory.align_backup(0)

with pytest.raises(ValueError, match='invalid modulo'):
memory.align_backup(-1)

def test_align_restore_doctest(self):
pass # no doctest

def test_align_restore(self):
Memory = self.Memory

memory = Memory()
memory.align_restore([])
assert memory.to_blocks() == []

memory = Memory.from_blocks([[0, b'0ABC01xyz123']])
backup = [(0, 1), (4, 6), (9, 12)]
memory.align_restore(backup)
assert memory.to_blocks() == [[1, b'ABC'], [6, b'xyz']]

memory = Memory.from_blocks([[0, b'xABC'], [6, b'x0123z']])
backup = [(0, 1), (4, 7), (11, 12)]
memory.align_restore(backup)
assert memory.to_blocks() == [[1, b'ABC'], [7, b'0123']]

memory = Memory.from_blocks([[1, b'ABC.@xyz']])
backup = [(4, 6)]
memory.align_restore(backup)
assert memory.to_blocks() == [[1, b'ABC'], [6, b'xyz']]

memory = Memory.from_blocks([[0, b'ABCD'], [8, b'xyz!']])
backup = [(4, 8)]
memory.align_restore(backup)
assert memory.to_blocks() == [[0, b'ABCD'], [8, b'xyz!']]

memory = Memory.from_blocks([[1, b'ABC'], [6, b'xyz']])
backup = [(4, 6)]
memory.align_restore(backup)
assert memory.to_blocks() == [[1, b'ABC'], [6, b'xyz']]

def test_keys_doctest(self):
Memory = self.Memory

Expand Down

0 comments on commit 1a78f87

Please sign in to comment.