Exercise 3: Coalesced Memory Is Genuinely Reusable, Not Just a Bookkeeping Merge — Possible Solution ==================================================================== THE TEST ------------------------------ mem = PhysicalMemory(300) a = mem.alloc_first_fit(100) # address 0 b = mem.alloc_first_fit(100) # address 100 c = mem.alloc_first_fit(100) # address 200 mem.free_coalescing(a, 100) mem.free_coalescing(b, 100) new_addr = mem.alloc_first_fit(150) # neither original block was 150 bytes mem.data[new_addr:new_addr + 150] = bytes(range(150)) read_back = bytes(mem.data[new_addr:new_addr + 150]) RESULT ------------------------------ requesting 150 bytes (neither original A nor B was that size) returns: 0 read_back == bytes(range(150)) -> True The 150-byte request succeeds at address 0, and writing 150 real bytes into that region followed by reading them back returns exactly what was written. WHY 150 BYTES COULD NEVER HAVE BEEN SATISFIED BEFORE COALESCING ------------------------------ Before either free, the memory was fully allocated (A, B, and C each 100 bytes, addresses 0-300). After naively freeing A and B without coalescing, the free list would hold two separate 100-byte entries -- neither one alone is big enough for a 150-byte request, and first-fit has no way to combine two separate list entries into one allocation. A 150-byte request against the NAIVE version of this exact scenario would fail for the same reason Finding 3's own 200-byte request did. WHY THIS PROVES THE MERGE IS REAL, NOT JUST A BOOKKEEPING CONVENIENCE ------------------------------ free_coalescing() merges (0,100) and (100,100) into a single (0,200) entry in the free list -- but a free-list entry is just a Python tuple; by itself it doesn't prove anything about the ACTUAL bytes at those addresses. This exercise closes that gap directly: requesting 150 bytes (a size that doesn't match either original block, ruling out any possibility of a coincidental match) succeeds, and then actually writing a full 150-byte sequence across what used to be the A/B boundary and reading it back intact confirms the underlying bytearray genuinely treats addresses 0 through 199 as one continuous, usable region -- not two separate 100-byte zones that merely LOOK combined in the free list's own bookkeeping. WHY THIS WORKS AS AN ANSWER ------------------------------ Deliberately choosing a request size that couldn't be satisfied by either original block alone, and then performing a real read/write that spans exactly where the old A/B boundary used to sit, verifies coalescing produces genuinely contiguous, fully usable physical memory -- not just a free-list entry that happens to report a larger number.