diff --git a/eo-runtime/src/main/eo/io/malloc-as-output.eo b/eo-runtime/src/main/eo/io/malloc-as-output.eo index 49a9158e42a..95d091ab24c 100644 --- a/eo-runtime/src/main/eo/io/malloc-as-output.eo +++ b/eo-runtime/src/main/eo/io/malloc-as-output.eo @@ -60,23 +60,13 @@ mem 01-02-03-04-05-06-07-08-09-A0 - # Tests that writing more bytes than allocated memory throws an error. - [] +> throws-on-writing-more-than-allocated - malloc.of > @ - 2 - [m] - (malloc-as-output m).write 01-02-03 > @ - - # @todo #4475:35min Enable `writes-larger-data-than-provided-block` after resize will be implemented. - # If the provided memory block is not large enough for the data to write, a runtime error happens. - # However we can use `malloc.of.allocated.resized` to increase the size of the block. - [] > writes-larger-data-than-provided-block + # Tests that writing more bytes than allocated resizes the block and stores all bytes. + [] +> writes-larger-data-than-provided-block eq. > @ malloc.of 2 [mem] - seq > @ - * - (malloc-as-output mem).write 01-02-03 - mem + seq * > @ + (malloc-as-output mem).write 01-02-03 + mem 01-02-03 diff --git a/eo-runtime/src/main/eo/malloc.eo b/eo-runtime/src/main/eo/malloc.eo index e72a20e9319..b8d4682887f 100644 --- a/eo-runtime/src/main/eo/malloc.eo +++ b/eo-runtime/src/main/eo/malloc.eo @@ -290,11 +290,14 @@ b.put (m.read 0 3).eq "XYX" - # Tests that malloc throws an error when writing beyond allocated memory bounds with offset. - [] +> throws-on-writing-more-than-allocated-to-malloc-with-offset + # Tests that malloc resizes the block when writing beyond allocated memory bounds with offset. + [] +> writes-beyond-offset-and-resizes malloc.of > @ 1 - m.write 1 true > [m] + [m] + seq * > @ + m.write 1 true + m.size.eq 2 # Tests that malloc can read data from specific offset with specified length correctly. [] +> tests-malloc-reads-with-offset-and-length @@ -379,11 +382,14 @@ 0 m.copy 9 1 1 > [m] - # Tests that malloc throws an error when copying to an invalid target offset. - [] +> throws-on-copying-with-wrong-target + # Tests that malloc resizes the block when copying to a target offset beyond allocated memory. + [] +> copies-and-resizes-to-target malloc.for > @ 0 - m.copy 3 9 1 > [m] + [m] + seq * > @ + m.copy 3 9 1 + m.size.eq 10 # Tests that malloc throws an error when copying with an invalid length parameter. [] +> throws-on-copying-with-wrong-length diff --git a/eo-runtime/src/main/java/org/eolang/Heaps.java b/eo-runtime/src/main/java/org/eolang/Heaps.java index a1fa277688c..292a8af9547 100644 --- a/eo-runtime/src/main/java/org/eolang/Heaps.java +++ b/eo-runtime/src/main/java/org/eolang/Heaps.java @@ -177,33 +177,14 @@ void write(final int identifier, final int offset, final byte[] data) { ) ); } - final byte[] current = this.blocks.get(identifier); - final int length = current.length; - if (length < offset + data.length) { - throw new ExFailure( - String.format( - "Can't write '%d' bytes with offset '%d' to the block with identifier '%d', because only '%d' were allocated", - data.length, - offset, - identifier, - length - ) - ); + if (this.blocks.get(identifier).length < offset + data.length) { + this.resize(identifier, offset + data.length); } + final byte[] source = this.blocks.get(identifier); + final int length = source.length; final byte[] result = new byte[length]; - if (offset > 0) { - System.arraycopy(current, 0, result, 0, offset); - } + System.arraycopy(source, 0, result, 0, length); System.arraycopy(data, 0, result, offset, data.length); - if (length > offset + data.length) { - System.arraycopy( - current, - offset + data.length, - result, - offset + data.length, - length - offset - data.length - ); - } this.blocks.put(identifier, result); } finally { this.lock.unlock(); diff --git a/eo-runtime/src/test/java/org/eolang/HeapsTest.java b/eo-runtime/src/test/java/org/eolang/HeapsTest.java index 2f1ea8be6b7..ec46cb3d1bd 100644 --- a/eo-runtime/src/test/java/org/eolang/HeapsTest.java +++ b/eo-runtime/src/test/java/org/eolang/HeapsTest.java @@ -111,27 +111,25 @@ void readsByOffsetAndLength() { } @Test - @SuppressWarnings("PMD.UnnecessaryLocalRule") - void failsOnWriteMoreThanAllocated() { + void resizesOnWriteMoreThanAllocated() { final int idx = Heaps.INSTANCE.malloc(new HeapsTest.PhFake(), 2); - final byte[] bytes = {1, 2, 3, 4, 5}; - Assertions.assertThrows( - ExFailure.class, - () -> Heaps.INSTANCE.write(idx, 0, bytes), - "Heaps should throw an exception on writing more bytes than allocated size, but it didn't" + Heaps.INSTANCE.write(idx, 0, new byte[] {1, 2, 3, 4, 5}); + MatcherAssert.assertThat( + "Heaps should resize block when writing more bytes than allocated, but it didn't", + Heaps.INSTANCE.read(idx, 0, 5), + Matchers.equalTo(new byte[] {1, 2, 3, 4, 5}) ); Heaps.INSTANCE.free(idx); } @Test - @SuppressWarnings("PMD.UnnecessaryLocalRule") - void failsToWriteMoreThanAllocatedWithOffset() { + void resizesOnWriteMoreThanAllocatedWithOffset() { final int idx = Heaps.INSTANCE.malloc(new HeapsTest.PhFake(), 3); - final byte[] bytes = {1, 2, 3}; - Assertions.assertThrows( - ExFailure.class, - () -> Heaps.INSTANCE.write(idx, 1, bytes), - "Heaps should throw an exception on writing past allocated block using offset, but it didn't" + Heaps.INSTANCE.write(idx, 1, new byte[] {1, 2, 3}); + MatcherAssert.assertThat( + "Heaps should resize block when writing past allocated boundary using offset, but it didn't", + Heaps.INSTANCE.read(idx, 1, 3), + Matchers.equalTo(new byte[] {1, 2, 3}) ); Heaps.INSTANCE.free(idx); } @@ -142,7 +140,7 @@ void concatsOnWriteLessThanAllocated() { Heaps.INSTANCE.write(idx, 0, new byte[] {1, 1, 3, 4, 5}); Heaps.INSTANCE.write(idx, 2, new byte[] {2, 2}); MatcherAssert.assertThat( - "Heaps should return correct bytes after partial overwrite, but it didn't", + "Heaps should return correct bytes after partial overwrite preserving trailing bytes, but it didn't", Heaps.INSTANCE.read(idx, 0, 5), Matchers.equalTo(new byte[] {1, 1, 2, 2, 5}) );