Slice a MemorySegment using SequenceLayout's element boundaries

Sebastian Stenzel sebastian.stenzel at gmail.com
Wed Jan 12 12:22:22 UTC 2022


Thank you, this is in fact an elegant solution. Yes, for two elements it is debatable, but it solves the general problem.

However, I don't understand the maths documented in the JavaDoc: The used Spliterator supplies S/N/2 elements. Now if my segment is 100 bytes in size, and my layout is 25 bytes, I'd expect it to split into four elements. If the layout is 30 bytes, I'd expect three elements (and a remainder of 10 unused bytes). So where does this /2 come from?

---

To add a little background to my original question:

I can imagine that dealing with MemoryAddresses that marks the begin of an array is not that uncommon. In this particular case, one can be sure to deal with a sequence of identical MemoryLayouts. Which suggests using a SequenceLayout. Therefore I assumed there should be some method that involves a SequenceLayout and a MemorySegment to obtain slices for individual elements.
 

> On 12. Jan 2022, at 12:20, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
> 
> On 12/01/2022 09:08, Sebastian Stenzel wrote:
>> Hi Maurizio,
>> 
>> thanks for the fast reply. While your suggested method may achieve the same, it doesn't really appeal to me. Creating a method handle and invoking it (i.e. without any type safety) isn't any less complicated than my original code. Or maybe I didn't understand it correct yet?
> 
> Well, you can create the method handle, store it in a static final constant - then wrap it with a static method if you want (static) type safety. The problem here is that when accessing a layout path there are an unknown number of coordinates involved (the API I pointed out is general, and allows you also to access structs nested into structs nested into arrays, etc.).
> 
> In your case, it seems like you have a memory segment which contains a bunch of structs with given layouts. If you don't want the slicing method handle, and you don't want to do manual offset computation, perhaps you could try with MemorySegment::element(MemoryLayout). This gives you a Stream of slices, with given layout. But not 100% is simpler that your original approach - especially if you only ever need two slices.
> 
> But you can do:
> 
> var slices = segment.elements(structLayout).toList();
> var elem0 = slices.get(0);
> var elem1 = slices.get(1);
> 
> Maurizio
> 
>> 
>> 
>>> On 11. Jan 2022, at 22:08, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
>>> 
>>> Hi Sebastian,
>>> look at the MemoryLayouy::sliceHandle - I believe it should do what you want? It takes a sequence of PathElements and returns a MethodHandle which takes a MemorySegment and some long coordinates and return the segment slice at that coordinates, which seems to be what you are trying to do.
>>> 
>>> Cheers
>>> Maurizio
>>> 
>>> On 11/01/2022 20:48, Sebastian Stenzel wrote:
>>>> Hi,
>>>> 
>>>> I've just updated some of my experiments [1] using the latest API in the upcoming JDK 18. Which lead to a question:
>>>> 
>>>> Given:
>>>> 
>>>> 1. a MemoryAddress (parameter in an upcall stub) representing a pointer to an array of structs
>>>> 2. a matching SequenceLayout of GroupLayouts for this array of structs
>>>> 
>>>> Is there any convenient API to obtain a MemorySegment of the nth array element? Currently I'm calculating memory boundaries manually and slice my segment accordingly:
>>>> 
>>>> ```
>>>> private void upcall(MemoryAddress pointer) {
>>>>    try (var scope = ResourceScope.newConfinedScope()) {
>>>>       var structLayout = ...;
>>>>       var sequenceLayout = MemoryLayout.sequenceLayout(42, structLayout);
>>>>       var segment = MemorySegment.ofAddress(pointer, sequenceLayout.byteSize(), scope);
>>>> 
>>>>       // either:
>>>>       var offset0 = sequenceLayout.byteOffset(MemoryLayout.PathElement.sequenceElement(0));
>>>>       var offset1 = sequenceLayout.byteOffset(MemoryLayout.PathElement.sequenceElement(1));
>>>>       var elem0 = segment.asSlice(offset0, structLayout.byteSize());
>>>>       var elem1 = segment.asSlice(offset1, structLayout.byteSize());
>>>> 
>>>>       // or alternatively:
>>>>       var elem0 = segment.asSlice(0, structLayout.byteSize());
>>>>       var elem1 = segment.asSlice(structLayout.byteSize(), structLayout.byteSize());
>>>>    }
>>>> }
>>>> ```
>>>> 
>>>> But since a SequenceLayout knows how to calculate the offset and knows the size of each of its elements, I guess there is a more convenient way to slice a segment.
>>>> 
>>>> Or if there isn't: Consider this a feature request ��
>>>> 
>>>> Cheers!
>>>> Sebastian
>>>> 
>>>> [1]: https://urldefense.com/v3/__https://github.com/skymatic/fuse-panama/blob/develop/mac/src/main/java/de/skymatic/fusepanama/mac/MacFuseOperationsMapper.java*L178-L187__;Iw!!ACWV5N9M2RV99hQ!Zkw2UevH7tHtVRCVOw26fKKMnrSXW14_OkGwUxlfVh6CLFkmHDIojtxtBeCOUKEzyHR6cfU$ <https://urldefense.com/v3/__https://github.com/skymatic/fuse-panama/blob/develop/mac/src/main/java/de/skymatic/fusepanama/mac/MacFuseOperationsMapper.java*L178-L187__;Iw!!ACWV5N9M2RV99hQ!Zkw2UevH7tHtVRCVOw26fKKMnrSXW14_OkGwUxlfVh6CLFkmHDIojtxtBeCOUKEzyHR6cfU$>


More information about the panama-dev mailing list