public class Struct
extends java.lang.Object
This class represents a C/C++ struct
; it confers
interoperability between Java classes and C/C++ struct.
Unlike C/C++
, the storage layout of Java objects is not
determined by the compiler. The layout of objects in memory is deferred
to run time and determined by the interpreter (or just-in-time compiler).
This approach allows for dynamic loading and binding; but also makes
interfacing with C/C++
code difficult. Hence, this class for
which the memory layout is defined by the initialization order of the
Struct
's members
and follows the same alignment
rules as C/C++ structs
.
Union
sub-class) facilitates:
Struct
/Union
using simple text macros. Here is an example of C struct:
struct Date {
unsigned short year;
unsigned byte month;
unsigned byte day;
};
struct Student {
char name[64];
struct Date birth;
float grades[10];
Student* next;
};
and here is the Java equivalent using this class:
public static class Date extends Struct {
public final Unsigned16 year = new Unsigned16();
public final Unsigned8 month = new Unsigned8();
public final Unsigned8 day = new Unsigned8();
}
public static class Student extends Struct {
public final Utf8String name = new UTF8String(64);
public final Date birth = inner(new Date());
public final Float32[] grades = array(new Float32[10]);
public final Reference32<Student> next = new Reference32<Student>();
}
Struct's members are directly accessible:
Student student = new Student();
student.name.set("John Doe"); // Null terminated (C compatible)
int age = 2003 - student.birth.year.get();
student.grades[2].set(12.5f);
student = student.next.get();
Applications may also work with the raw bytes
directly. The following illustrate how Struct
can be used to
decode/encode UDP messages directly:
class UDPMessage extends Struct {
Unsigned16 xxx = new Unsigned16();
...
}
public void run() {
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
UDPMessage message = new UDPMessage();
message.setByteBuffer(ByteBuffer.wrap(bytes), 0);
// packet and message are now two different views of the same data.
while (isListening) {
multicastSocket.receive(packet);
int xxx = message.xxx.get();
... // Process message fields directly.
}
}
It is relatively easy to map instances of this class to any physical address using JNI. Here is an example:
import java.nio.ByteBuffer;
class Clock extends Struct { // Hardware clock mapped to memory.
Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5
Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5
Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4
Clock() {
setByteBuffer(Clock.nativeBuffer(), 0);
}
private static native ByteBuffer nativeBuffer();
}
Below is the nativeBuffer()
implementation
(Clock.c
):
#include <jni.h>
#include "Clock.h" // Generated using javah
JNIEXPORT jobject JNICALL Java_Clock_nativeBuffer (JNIEnv *env, jclass) {
return (*env)->NewDirectByteBuffer(env, clock_address, buffer_size)
}
Bit-fields are supported (see Clock
example above).
Bit-fields allocation order is defined by the Struct byteOrder()
return value (leftmost bit to rightmost bit if
BIG_ENDIAN
and rightmost bit to leftmost bit if
LITTLE_ENDIAN
).
Unless the Struct packing
directive is overriden,
bit-fields cannot straddle the storage-unit boundary as defined by their
base type (padding is inserted at the end of the first bit-field
and the second bit-field is put into the next storage unit).
Finally, it is possible to change the ByteBuffer
and/or the Struct position
in its
ByteBuffer
to allow for a single Struct
object to
encode/decode multiple memory mapped instances.
Note: Because Struct/Union are basically wrappers around
java.nio.ByteBuffer
, tutorials/usages for
the Java NIO package are directly applicable to Struct.
Modifier and Type | Class and Description |
---|---|
class |
Struct.Bool
This class represents a 8 bits boolean with
true represented
by 1 and false represented by 0 . |
class |
Struct.Enum16
This class represents a 16 bits
Enum . |
class |
Struct.Enum32
This class represents a 32 bits
Enum . |
class |
Struct.Enum64
This class represents a 64 bits
Enum . |
class |
Struct.Enum8
This class represents a 8 bits
Enum . |
class |
Struct.Float32
This class represents a 32 bits float (C/C++/Java
float ). |
class |
Struct.Float64
This class represents a 64 bits float (C/C++/Java
double ). |
static interface |
Struct.InstanceFactory<S>
A factory callback that may be supplied to the
array(Struct[], com.scaleoutsoftware.soss.client.util.Struct.InstanceFactory)
method to allow callers to construct their own Struct and Struct.Member
instances as needed. |
protected class |
Struct.Member
This inner class represents the base class for all
Struct
members. |
class |
Struct.Reference32<S extends Struct>
|
class |
Struct.Reference64<S extends Struct>
|
class |
Struct.Signed16
This class represents a 16 bits signed integer.
|
class |
Struct.Signed32
This class represents a 32 bits signed integer.
|
class |
Struct.Signed64
This class represents a 64 bits signed integer.
|
class |
Struct.Signed8
This class represents a 8 bits signed integer.
|
class |
Struct.Unsigned16
This class represents a 16 bits unsigned integer.
|
class |
Struct.Unsigned32
This class represents a 32 bits unsigned integer.
|
class |
Struct.Unsigned8
This class represents a 8 bits unsigned integer.
|
class |
Struct.UTF8String
This class represents a UTF-8 character string, null terminated
(for C/C++ compatibility)
|
Constructor and Description |
---|
Struct()
Default constructor.
|
Modifier and Type | Method and Description |
---|---|
long |
address()
Returns this struct address.
|
protected <M extends Struct.Member> |
array(M[] arrayMember)
Defines the specified array member.
|
protected <M extends Struct.Member> |
array(M[][] arrayMember)
Defines the specified two-dimensional array member.
|
protected <M extends Struct.Member> |
array(M[][][] arrayMember)
Defines the specified three-dimensional array member.
|
protected <M extends Struct.Member> |
array(M[] arrayMember,
Struct.InstanceFactory<M> factory)
Defines the specified array member.
|
protected <S extends Struct> |
array(S[] structs)
Defines the specified array of structs as inner structs.
|
protected <S extends Struct> |
array(S[][] structs)
Defines the specified two-dimensional array of structs as inner
structs.
|
protected <S extends Struct> |
array(S[][][] structs)
Defines the specified three dimensional array of structs as inner
structs.
|
protected <S extends Struct> |
array(S[] structs,
Struct.InstanceFactory<S> factory) |
protected Struct.UTF8String[] |
array(Struct.UTF8String[] array,
int stringLength)
Defines the specified array of UTF-8 strings, all strings having the
specified length (convenience method).
|
java.nio.ByteOrder |
byteOrder()
Returns the byte order for this struct (configurable).
|
protected <M extends Struct.Member> |
fillArray(M[] arrayMember)
Fill the parameter arrayMember with values of type M.
|
protected <M extends Struct.Member> |
fillArray(M[] arrayMember,
Struct.InstanceFactory<M> factory)
Fill the array
arrayMember with instances of type M created by the instance
factory factory . |
protected <S extends Struct> |
fillArray(S[] structs)
Fill the array, structs, with instances so that space in the struct is appropriately
consumed.
|
protected <S extends Struct> |
fillArray(S[] structs,
Struct.InstanceFactory<S> factory)
Fill the array
factory with instances of type S created by the instance
factory factory . |
java.nio.ByteBuffer |
getByteBuffer()
Returns the byte buffer for this struct.
|
int |
getByteBufferPosition()
Returns the absolute position of this struct within its associated
byte buffer . |
protected <S extends Struct> |
inner(S struct)
Defines the specified struct as inner of this struct.
|
boolean |
isPacked()
Indicates if this struct is packed (configurable).
|
boolean |
isUnion()
Indicates if this struct's members are mapped to the same location
in memory (default
false ). |
protected java.nio.ByteBuffer |
newBuffer(int capacity) |
protected Struct |
outerStruct()
Returns the outer struct if any.
|
int |
read(java.io.InputStream in)
Reads this struct from the specified input stream
(convenience method when using Stream I/O).
|
Struct |
setByteBuffer(java.nio.ByteBuffer byteBuffer,
int position)
Sets the current byte buffer for this struct.
|
Struct |
setByteBufferPosition(int position)
Sets the position of this struct within its byte buffer.
|
int |
size()
Returns the size in bytes of this struct.
|
java.lang.String |
toString()
Returns the
String representation of this struct
in the form of its constituing bytes (hexadecimal). |
void |
write(java.io.OutputStream out)
Writes this struct to the specified output stream
(convenience method when using Stream I/O).
|
public final int size()
members
).sizeof(this)
.protected final Struct outerStruct()
public final java.nio.ByteBuffer getByteBuffer()
Returns the byte buffer for this struct. This method will allocate a new direct buffer if none has been set.
Changes to the buffer's content are visible in this struct, and vice versa.
The buffer of an inner struct is the same as its parent struct.
The position of a struct's member
within the
byte buffer is given by member.position()
setByteBuffer(java.nio.ByteBuffer, int)
protected java.nio.ByteBuffer newBuffer(int capacity)
public final Struct setByteBuffer(java.nio.ByteBuffer byteBuffer, int position)
DatagramPacket
).byteBuffer
- the new byte buffer.position
- the position of this struct in the specified byte buffer.this
java.lang.IllegalArgumentException
- if the specified byteBuffer has a
different byte order than this struct.java.lang.UnsupportedOperationException
- if this struct is an inner struct.byteOrder()
public final Struct setByteBufferPosition(int position)
position
- the position of this struct in its byte buffer.this
java.lang.UnsupportedOperationException
- if this struct is an inner struct.public final int getByteBufferPosition()
byte buffer
.public int read(java.io.InputStream in) throws java.io.IOException
java.nio.channels.*
) is recommended.in
- the input stream being read from.size
of this struct.java.io.IOException
- if an I/O error occurs.public void write(java.io.OutputStream out) throws java.io.IOException
java.nio.channels.*
) is recommended.out
- the output stream to write to.java.io.IOException
- if an I/O error occurs.public final long address()
java.lang.UnsupportedOperationException
- if the struct buffer is not
a direct buffer.Struct.Reference32
,
Struct.Reference64
public java.lang.String toString()
Returns the String
representation of this struct
in the form of its constituing bytes (hexadecimal). For example:[code]
public static class Student extends Struct {
Utf8String name = new Utf8String(16);
Unsigned16 year = new Unsigned16();
Float32 grade = new Float32();
}
Student student = new Student();
student.name.set("John Doe");
student.year.set(2003);
student.grade.set(12.5f);
System.out.println(student);
toString
in class java.lang.Object
public boolean isUnion()
false
). This method is useful for
applications extending Struct
with new member types in order to
create unions from these new structs. For example:[code]
public abstract class FortranStruct extends Struct {
public class FortranString extends Member {...}
protected FortranString[] array(FortranString[] array, int stringLength) { ... }
}
public abstract class FortranUnion extends FortranStruct {
// Inherits new members and methods.
public final isUnion() {
return true;
}
}[/code]true
if this struct's members are mapped to
to the same location in memory; false
otherwise.Union
public java.nio.ByteOrder byteOrder()
Returns the byte order for this struct (configurable). The byte order is inherited by inner structs. Sub-classes may change the byte order by overriding this method. For example: [code] public class TopStruct extends Struct { ... // Members initialization. public ByteOrder byteOrder() { // TopStruct and its inner structs use hardware byte order. return ByteOrder.nativeOrder(); } }}[/code]
BIG_ENDIAN
).public boolean isPacked()
members
of a struct are aligned on the
boundary corresponding to the member base type; padding is performed
if necessary. This directive is inherited by inner structs.
Sub-classes may change the packing directive by overriding this method.
For example:[code]
public class TopStruct extends Struct {
... // Members initialization.
public boolean isPacked() {
// TopStruct and its inner structs are packed.
return true;
}
}}[/code]true
if alignment requirements are ignored.
false
otherwise (default).protected <S extends Struct> S inner(S struct)
S
- the type of the inner struct.struct
- the inner struct.java.lang.IllegalArgumentException
- if the specified struct is already
an inner struct.protected <S extends Struct> S[] array(S[] structs)
S
- the type of the struct array.structs
- the struct array.java.lang.IllegalArgumentException
- if the specified array contains
inner structs.protected <S extends Struct> S[] array(S[] structs, Struct.InstanceFactory<S> factory)
protected <S extends Struct> S[][] array(S[][] structs)
S
- the type of the structs.structs
- the two dimensional struct array.java.lang.IllegalArgumentException
- if the specified array contains
inner structs.protected <S extends Struct> S[][][] array(S[][][] structs)
S
- the type of the structs.structs
- the three dimensional struct array.java.lang.IllegalArgumentException
- if the specified array contains
inner structs.protected <M extends Struct.Member> M[] array(M[] arrayMember)
M
- the type of the member.arrayMember
- the array member.java.lang.UnsupportedOperationException
- if the specified array
is empty and the member type is unknown.protected <M extends Struct.Member> M[] array(M[] arrayMember, Struct.InstanceFactory<M> factory)
M
- the type of the member array.arrayMember
- the array member.factory
- an InstanceFactory callback for creating instances
with which to fill the arrayjava.lang.UnsupportedOperationException
- if the specified array
is empty and the member type is unknown.protected <S extends Struct> void fillArray(S[] structs)
S
- the type of the structstructs
- the array to fillprotected <S extends Struct> void fillArray(S[] structs, Struct.InstanceFactory<S> factory)
factory
with instances of type S created by the instance
factory factory
.S
- the type of the Struct to createstructs
- an array of type S structsfactory
- a factory that can generate new instances of type S.protected <M extends Struct.Member> void fillArray(M[] arrayMember)
Fill the parameter arrayMember with values of type M.
If you add aStruct.Member
subclass that isn't covered here, you should
override this method (not
array(com.scaleoutsoftware.soss.client.util.Struct.Member[])
),
providing support for your Struct.Member
subclass and then delegating to
the super class for everything else.M
- the type of the array memberarrayMember
- the array member.protected <M extends Struct.Member> void fillArray(M[] arrayMember, Struct.InstanceFactory<M> factory)
arrayMember
with instances of type M created by the instance
factory factory
.M
- the subtype of MemberarrayMember
- the array of type Mfactory
- a factory callback that can create instances of type Mprotected <M extends Struct.Member> M[][] array(M[][] arrayMember)
M
- the type of the array member.arrayMember
- the two-dimensional array member.java.lang.UnsupportedOperationException
- if the specified array
is empty and the member type is unknown.protected <M extends Struct.Member> M[][][] array(M[][][] arrayMember)
M
- the type of the array member.arrayMember
- the three-dimensional array member.java.lang.UnsupportedOperationException
- if the specified array
is empty and the member type is unknown.protected Struct.UTF8String[] array(Struct.UTF8String[] array, int stringLength)
array
- the string array.stringLength
- the length of the string elements.