Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added MemoryStack::asArena #1

Merged
merged 1 commit into from
Sep 15, 2024
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
50 changes: 50 additions & 0 deletions .github/workflows/javadoc.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
```
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/io/github/overrun/memstack/DefaultMemoryStack.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.overrun.memstack;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.util.Arrays;

Expand All @@ -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;

/**
Expand All @@ -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) {
Expand All @@ -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;
}
Expand All @@ -62,6 +68,10 @@ public void pop() {
}
frameIndex--;
offset = frames[frameIndex];
if (arena != null) {
arena.close();
}
arena = arenas[frameIndex];
}

@Override
Expand All @@ -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;
}
}
13 changes: 13 additions & 0 deletions src/main/java/io/github/overrun/memstack/MemoryStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.util.function.Consumer;

/**
* <h2>Memory stack</h2>
Expand All @@ -17,6 +18,8 @@
* The stack itself does not bind to any segment scope;
* it just slices the backing segment.
* <p>
* To re-associate a memory segment with the memory stack, use {@link #asArena()}.
* <p>
* Memory stack is not thread-safe;
* consider using the {@linkplain #ofLocal() local stacks} to manage with threads.
* <h3>Push and pop</h3>
Expand Down Expand Up @@ -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}.
* <p>
* The obtained arena closes when this stack is popped.
*
* @return the arena that wraps this memory stack
*/
Arena asArena();
}
15 changes: 13 additions & 2 deletions src/test/java/io/github/overrun/memstack/test/MemoryStackTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
}
}