diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml new file mode 100644 index 0000000..2d73c41 --- /dev/null +++ b/.github/workflows/javadoc.yml @@ -0,0 +1,50 @@ +name: Javadoc + +on: [ release, workflow_dispatch ] + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: | + 22 + distribution: 'temurin' + - name: Grant execute permission for gradlew + if: ${{ runner.os != 'Windows' }} + run: chmod +x gradlew + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Execute Gradle build + run: ./gradlew javadoc + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: './build/docs/javadoc' + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 496ad6e..f49688b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,6 @@ Gradle: ```groovy dependencies { - implementation("io.github.over-run:memstack:0.2.0") + implementation("io.github.over-run:memstack:0.3.0") } ``` diff --git a/gradle.properties b/gradle.properties index b665cc7..e01e54b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ projGroupId=io.github.over-run projArtifactId=memstack # The project name should only contain lowercase letters, numbers and hyphen. projName=memstack -projVersion=0.2.0 +projVersion=0.3.0 projDesc=Memory stack for FFM API # Uncomment them if you want to publish to maven repository. projUrl=https://github.com/Over-Run/memstack diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b41..0aaefbc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java b/src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java index 4146ba4..af2e7ea 100644 --- a/src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java +++ b/src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java @@ -1,5 +1,6 @@ package io.github.overrun.memstack; +import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.util.Arrays; @@ -12,7 +13,9 @@ public class DefaultMemoryStack implements MemoryStack { private final MemorySegment segment; private long[] frames; + private Arena[] arenas; private long offset = 0L; + private Arena arena; private int frameIndex = 0; /** @@ -24,6 +27,7 @@ public class DefaultMemoryStack implements MemoryStack { public DefaultMemoryStack(MemorySegment segment, int frameCount) { this.segment = segment; this.frames = new long[frameCount]; + this.arenas = new Arena[frameCount]; } private MemorySegment trySlice(long byteSize, long byteAlignment) { @@ -49,8 +53,10 @@ public MemorySegment allocate(long byteSize, long byteAlignment) { public MemoryStack push() { if (frameIndex >= frames.length) { frames = Arrays.copyOf(frames, frames.length * 3 / 2); + arenas = Arrays.copyOf(arenas, arenas.length * 3 / 2); } frames[frameIndex] = offset; + arenas[frameIndex] = arena; frameIndex++; return this; } @@ -62,6 +68,10 @@ public void pop() { } frameIndex--; offset = frames[frameIndex]; + if (arena != null) { + arena.close(); + } + arena = arenas[frameIndex]; } @Override @@ -88,4 +98,29 @@ public void setPointer(long pointer) { public MemorySegment segment() { return segment; } + + @Override + public Arena asArena() { + if (arena == null) { + arena = new Arena() { + private final Arena arena = Arena.ofConfined(); + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + return DefaultMemoryStack.this.allocate(byteSize, byteAlignment); + } + + @Override + public MemorySegment.Scope scope() { + return arena.scope(); + } + + @Override + public void close() { + arena.close(); + } + }; + } + return arena; + } } diff --git a/src/main/java/io/github/overrun/memstack/MemoryStack.java b/src/main/java/io/github/overrun/memstack/MemoryStack.java index d602844..8409a5e 100644 --- a/src/main/java/io/github/overrun/memstack/MemoryStack.java +++ b/src/main/java/io/github/overrun/memstack/MemoryStack.java @@ -3,6 +3,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SegmentAllocator; +import java.util.function.Consumer; /** *

Memory stack

@@ -17,6 +18,8 @@ * The stack itself does not bind to any segment scope; * it just slices the backing segment. *

+ * To re-associate a memory segment with the memory stack, use {@link #asArena()}. + *

* Memory stack is not thread-safe; * consider using the {@linkplain #ofLocal() local stacks} to manage with threads. *

Push and pop

@@ -182,4 +185,14 @@ default void close() { * {@return the backing memory segment} */ MemorySegment segment(); + + /** + * Wraps this memory stack into an arena for re-associating a memory segment with + * {@link MemorySegment#reinterpret(Arena, Consumer) MemorySegment::reinterpret}. + *

+ * The obtained arena closes when this stack is popped. + * + * @return the arena that wraps this memory stack + */ + Arena asArena(); } diff --git a/src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java b/src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java index c03ba31..41dc0f7 100644 --- a/src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java +++ b/src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java @@ -4,10 +4,11 @@ import io.github.overrun.memstack.StackConfigurations; import org.junit.jupiter.api.Test; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.*; /** * @author squid233 @@ -108,4 +109,14 @@ void testOutOfMemory() { assertThrowsExactly(IndexOutOfBoundsException.class, () -> MemoryStack.of().allocate(StackConfigurations.STACK_SIZE.get() + 1)); } + + @Test + void testAsArena() { + MemorySegment segment; + try (MemoryStack stack = MemoryStack.pushLocal()) { + segment = stack.allocate(ValueLayout.JAVA_INT) + .reinterpret(stack.asArena(), System.out::println); + } + assertFalse(segment.scope().isAlive()); + } }