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

1"""AI: Byte-level content rewriter that accumulates and applies pending replacements.""" 

2 

3import sys 

4 

5 

6class Rewrite: 

7 """AI: Represent one pending replacement of a byte range with new content.""" 

8 

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 

14 

15 

16class Rewriter: 

17 """A class that allows for modifications to a byte sequence.""" 

18 

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] = [] 

23 

24 def replace(self, start: int, end: int, new_content: bytes) -> None: 

25 """Replace a portion of the content with new content. 

26 

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. 

33 

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. 

38 

39 Returns: 

40 None 

41 

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)) 

53 

54 def apply(self) -> bytes: 

55 """Apply the rewrites to a copied byte sequence. 

56 

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. 

60 

61 Returns: 

62 bytes: The modified byte sequence after all rewrites have been applied. 

63 

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 

69 

70 @property 

71 def content(self) -> bytes: 

72 """AI: Return the original, unmodified content this rewriter was constructed with.""" 

73 return self.__content 

74 

75 

76if __name__ == "__main__": 

77 # create a byte array a random bytes of len 20 

78 

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)