Coverage for src/renaissance/common/rewriter.py: 72%
39 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
1"""AI: Byte-level content rewriter that accumulates and applies pending replacements."""
3import sys
6class Rewrite:
7 """AI: Represent one pending replacement of a byte range with new content."""
9 def __init__(self, start: int, end: int, replacement: bytes) -> None:
10 """AI: Record a pending replacement of a byte range with new content."""
11 self.start = start
12 self.end = end
13 self.replacement = replacement
16class Rewriter:
17 """A class that allows for modifications to a byte sequence."""
19 def __init__(self, content: bytes) -> None:
20 """AI: Prepare a rewriter that accumulates edits to apply to the given content."""
21 self.__content = content
22 self.__rewrites: list[Rewrite] = []
24 def replace(self, start: int, end: int, new_content: bytes) -> None:
25 """Replace a portion of the content with new content.
27 This method will replace the content between the specified start and end
28 indices with the provided new_content. If there is an existing rewrite
29 that partially overlaps with the specified range, the new content will be
30 appended to the existing replacement, and the range will be adjusted to
31 encompass both the old and new content. If the start or end indices are out
32 of bounds, then new content will be inserted at the end of the byte sequence.
34 Args:
35 start (int): The starting index of the content to be replaced.
36 end (int): The ending index of the content to be replaced.
37 new_content (bytes): The new content to insert in place of the old content.
39 Returns:
40 None
42 """
43 for r in self.__rewrites:
44 # if r partially overlaps with start and end then append the new content to the existing replacement
45 if r.start <= start <= r.end:
46 r.replacement += new_content
47 r.start = min(r.start, start)
48 r.end = max(r.end, end)
49 return
50 real_start = len(self.__content) if start > len(self.__content) or start < 0 else start
51 real_end = len(self.__content) if end > len(self.__content) or end < 0 else end
52 self.__rewrites.append(Rewrite(real_start, real_end, new_content))
54 def apply(self) -> bytes:
55 """Apply the rewrites to a copied byte sequence.
57 This method reverses the order of the rewrites to ensure that insertions
58 are performed correctly. It then sorts the rewrites by their start position
59 in descending order and applies each rewrite to the byte sequence.
61 Returns:
62 bytes: The modified byte sequence after all rewrites have been applied.
64 """
65 result = bytearray(self.__content[:])
66 for rewrite in sorted(self.__rewrites, key=lambda x: x.start, reverse=True):
67 result[rewrite.start : rewrite.end] = rewrite.replacement
68 return result
70 @property
71 def content(self) -> bytes:
72 """AI: Return the original, unmodified content this rewriter was constructed with."""
73 return self.__content
76if __name__ == "__main__":
77 # create a byte array a random bytes of len 20
79 my_bytes = bytearray(20)
80 for i in range(20):
81 my_bytes[i] = ord("a") + i
82 rewriter = Rewriter(my_bytes)
83 rewriter.replace(5, 10, b"hellooo")
84 rewriter.replace(5, 10, b" world")
85 rewriter.replace(0, 0, b"BEGIN")
86 s = rewriter.apply().decode(sys.getfilesystemencoding())
87 print(len(s))
88 print(s)