Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions eo-runtime/src/main/eo/io/malloc-as-output.eo
Original file line number Diff line number Diff line change
Expand Up @@ -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
18 changes: 12 additions & 6 deletions eo-runtime/src/main/eo/malloc.eo
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
29 changes: 5 additions & 24 deletions eo-runtime/src/main/java/org/eolang/Heaps.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
28 changes: 13 additions & 15 deletions eo-runtime/src/test/java/org/eolang/HeapsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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})
);
Expand Down
Loading