Skip to content

Commit 6d59bc3

Browse files
committed
Added MemoryStack::asArena
1 parent 5776783 commit 6d59bc3

File tree

7 files changed

+114
-5
lines changed

7 files changed

+114
-5
lines changed

.github/workflows/javadoc.yml

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Javadoc
2+
3+
on: [ release, workflow_dispatch ]
4+
5+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
6+
permissions:
7+
contents: read
8+
pages: write
9+
id-token: write
10+
11+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
12+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
- name: Setup Pages
23+
uses: actions/configure-pages@v5
24+
- name: Set up JDK
25+
uses: actions/setup-java@v4
26+
with:
27+
java-version: |
28+
22
29+
distribution: 'temurin'
30+
- name: Grant execute permission for gradlew
31+
if: ${{ runner.os != 'Windows' }}
32+
run: chmod +x gradlew
33+
- name: Setup Gradle
34+
uses: gradle/actions/setup-gradle@v3
35+
- name: Execute Gradle build
36+
run: ./gradlew javadoc
37+
- name: Upload artifact
38+
uses: actions/upload-pages-artifact@v3
39+
with:
40+
path: './build/docs/javadoc'
41+
deploy:
42+
environment:
43+
name: github-pages
44+
url: ${{ steps.deployment.outputs.page_url }}
45+
runs-on: ubuntu-latest
46+
needs: build
47+
steps:
48+
- name: Deploy to GitHub Pages
49+
id: deployment
50+
uses: actions/deploy-pages@v4

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ Gradle:
4141
4242
```groovy
4343
dependencies {
44-
implementation("io.github.over-run:memstack:0.2.0")
44+
implementation("io.github.over-run:memstack:0.3.0")
4545
}
4646
```

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ projGroupId=io.github.over-run
1212
projArtifactId=memstack
1313
# The project name should only contain lowercase letters, numbers and hyphen.
1414
projName=memstack
15-
projVersion=0.2.0
15+
projVersion=0.3.0
1616
projDesc=Memory stack for FFM API
1717
# Uncomment them if you want to publish to maven repository.
1818
projUrl=https://github.com/Over-Run/memstack

gradle/wrapper/gradle-wrapper.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java

+35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.overrun.memstack;
22

3+
import java.lang.foreign.Arena;
34
import java.lang.foreign.MemorySegment;
45
import java.util.Arrays;
56

@@ -12,7 +13,9 @@
1213
public class DefaultMemoryStack implements MemoryStack {
1314
private final MemorySegment segment;
1415
private long[] frames;
16+
private Arena[] arenas;
1517
private long offset = 0L;
18+
private Arena arena;
1619
private int frameIndex = 0;
1720

1821
/**
@@ -24,6 +27,7 @@ public class DefaultMemoryStack implements MemoryStack {
2427
public DefaultMemoryStack(MemorySegment segment, int frameCount) {
2528
this.segment = segment;
2629
this.frames = new long[frameCount];
30+
this.arenas = new Arena[frameCount];
2731
}
2832

2933
private MemorySegment trySlice(long byteSize, long byteAlignment) {
@@ -49,8 +53,10 @@ public MemorySegment allocate(long byteSize, long byteAlignment) {
4953
public MemoryStack push() {
5054
if (frameIndex >= frames.length) {
5155
frames = Arrays.copyOf(frames, frames.length * 3 / 2);
56+
arenas = Arrays.copyOf(arenas, arenas.length * 3 / 2);
5257
}
5358
frames[frameIndex] = offset;
59+
arenas[frameIndex] = arena;
5460
frameIndex++;
5561
return this;
5662
}
@@ -62,6 +68,10 @@ public void pop() {
6268
}
6369
frameIndex--;
6470
offset = frames[frameIndex];
71+
if (arena != null) {
72+
arena.close();
73+
}
74+
arena = arenas[frameIndex];
6575
}
6676

6777
@Override
@@ -88,4 +98,29 @@ public void setPointer(long pointer) {
8898
public MemorySegment segment() {
8999
return segment;
90100
}
101+
102+
@Override
103+
public Arena asArena() {
104+
if (arena == null) {
105+
arena = new Arena() {
106+
private final Arena arena = Arena.ofConfined();
107+
108+
@Override
109+
public MemorySegment allocate(long byteSize, long byteAlignment) {
110+
return DefaultMemoryStack.this.allocate(byteSize, byteAlignment);
111+
}
112+
113+
@Override
114+
public MemorySegment.Scope scope() {
115+
return arena.scope();
116+
}
117+
118+
@Override
119+
public void close() {
120+
arena.close();
121+
}
122+
};
123+
}
124+
return arena;
125+
}
91126
}

src/main/java/io/github/overrun/memstack/MemoryStack.java

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.lang.foreign.Arena;
44
import java.lang.foreign.MemorySegment;
55
import java.lang.foreign.SegmentAllocator;
6+
import java.util.function.Consumer;
67

78
/**
89
* <h2>Memory stack</h2>
@@ -17,6 +18,8 @@
1718
* The stack itself does not bind to any segment scope;
1819
* it just slices the backing segment.
1920
* <p>
21+
* To re-associate a memory segment with the memory stack, use {@link #asArena()}.
22+
* <p>
2023
* Memory stack is not thread-safe;
2124
* consider using the {@linkplain #ofLocal() local stacks} to manage with threads.
2225
* <h3>Push and pop</h3>
@@ -182,4 +185,14 @@ default void close() {
182185
* {@return the backing memory segment}
183186
*/
184187
MemorySegment segment();
188+
189+
/**
190+
* Wraps this memory stack into an arena for re-associating a memory segment with
191+
* {@link MemorySegment#reinterpret(Arena, Consumer) MemorySegment::reinterpret}.
192+
* <p>
193+
* The obtained arena closes when this stack is popped.
194+
*
195+
* @return the arena that wraps this memory stack
196+
*/
197+
Arena asArena();
185198
}

src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import io.github.overrun.memstack.StackConfigurations;
55
import org.junit.jupiter.api.Test;
66

7+
import java.lang.foreign.Arena;
8+
import java.lang.foreign.MemorySegment;
79
import java.lang.foreign.ValueLayout;
810

9-
import static org.junit.jupiter.api.Assertions.assertEquals;
10-
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
11+
import static org.junit.jupiter.api.Assertions.*;
1112

1213
/**
1314
* @author squid233
@@ -108,4 +109,14 @@ void testOutOfMemory() {
108109
assertThrowsExactly(IndexOutOfBoundsException.class, () ->
109110
MemoryStack.of().allocate(StackConfigurations.STACK_SIZE.get() + 1));
110111
}
112+
113+
@Test
114+
void testAsArena() {
115+
MemorySegment segment;
116+
try (MemoryStack stack = MemoryStack.pushLocal()) {
117+
segment = stack.allocate(ValueLayout.JAVA_INT)
118+
.reinterpret(stack.asArena(), System.out::println);
119+
}
120+
assertFalse(segment.scope().isAlive());
121+
}
111122
}

0 commit comments

Comments
 (0)