Skip to content

Commit

Permalink
Merge branch 'jnr:master' into doc-improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
praj-foss authored Feb 6, 2022
2 parents deefbd4 + 80145bc commit ebd461e
Show file tree
Hide file tree
Showing 41 changed files with 6,338 additions and 1,300 deletions.
33 changes: 27 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,49 @@ on:
branches: [ master ]

jobs:
jdk8:

mvn-test-ubuntu-x86:

runs-on: ubuntu-latest

strategy:
matrix:
java-version: ['8', '11']

steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/[email protected]
with:
java-version: 8
java-version: ${{ matrix.java-version }}
- name: Build with Maven
run: mvn -B package --file pom.xml

jdk11:
mvn-test-macos-aarch64:

runs-on: ubuntu-latest
runs-on: [self-hosted, macos, aarch64]

name: mvn test on Apple M1

steps:
- uses: actions/checkout@v2
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Set up JDK 11
uses: actions/setup-java@v1.4.3
uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: 11
architecture: arm
- name: Build with Maven
run: mvn -B package --file pom.xml
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ hand, or using tools such as SWIG.

## Installation

Latest version:
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jnr/jnr-ffi/badge.svg)](https://search.maven.org/artifact/com.github.jnr/jnr-ffi)

Apache Maven:
Expand All @@ -13,20 +14,20 @@ Apache Maven:
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
<version>2.2.3</version>
<version>x.y.z</version>
</dependency>
```

Gradle Kotlin:

```kotlin
implementation("com.github.jnr:jnr-ffi:2.2.3")
implementation("com.github.jnr:jnr-ffi:x.y.z")
```

Gradle Groovy:

```groovy
implementation 'com.github.jnr:jnr-ffi:2.2.3'
implementation 'com.github.jnr:jnr-ffi:x.y.z'
```

## Example
Expand Down Expand Up @@ -77,4 +78,4 @@ View more details in [our user documentation](./docs/README.md).
You should have received a copy of the GNU Lesser General Public License
version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
```
```
106 changes: 92 additions & 14 deletions docs/TypeMappings.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,104 @@
# Type Mappings

# Primitive Types
## Numeric Types

All Java primitives are mapped to their size equivalent C types:
### Signed Types

Signed numeric types map to their equivalent size Java primitive or boxed types:

| C Type | Java Type | Size |
|--------|-----------|------|
| `char` | `byte` | 8 bit integer |
| `short` | `short` | 16 bit integer |
| `int` | `int` | 32 bit integer |
| `long` | `long` | natural long, 32 bits on 32 bit systems, 64 bits on 64 bit systems |
| `float` | `float` | 32 bit floating point |
| `double` | `double` | 64 bit floating point |
| `char` | `byte` or `Byte` | 8 bit integer |
| `short` | `short` or `Short` | 16 bit integer |
| `int` | `int` or `Integer` | 32 bit integer |
| `long` | `long` or `Long` or `NativeLong` | natural long, 32 bit integer on 32 bit systems, 64 bit integer on 64 bit systems |
| `long long` | `long` or `Long` | 64 bit integer |
| `float` | `float` or `Float` | 32 bit floating point |
| `double` | `double` or `Double` | 64 bit floating point |

Java `boolean` or `Boolean` can also be used in place of a C numeric type where a boolean would be expected, check the native function's documentation
before doing this. `0` maps to `false` and any other value will be `true`. Floating point types (`float` and `double`) are not supported in this regard.

### Unsigned Types

For native unsigned types you can use the same size Java type (`unsigned char` maps to `byte` or `Byte`) but you will not be able to fit the values greater than the maximum limit for the Java type.

For example, an `unsigned char` can contain the value `220` but a Java `byte` cannot and will thus underflow to `-36`.

To remedy this you can use a larger size Java type with the corresponding annotation to let JNR-FFI to do the correct conversion. To fit the bounds of unsigned C types use the following table:

| C Type | Java Type |
|--------|-----------|
| `unsigned char` | `@u_int8_t byte` |
| `unsigned short` | `@u_int16_t int` |
| `unsigned int` | `@u_int32_t long` |

Unsigned 64 bit integers (such as `unsigned long` on 64bit systems and `unsigned long long`) are not yet supported to fit values beyond those of Java's `Long.MAX_VALUE`. [This is a documented issue.](https://github.com/jnr/jnr-ffi/issues/289)

### Enums

Native enums can be mapped using any Java integral numeric types such as `int` or `Integer`, or by using a similarly valued Java enum to the native one.

For example the C enum:

```c
enum week{Mon, Tue, Wed, Thu, Fri, Sat, Sun};
```
can be mapped in Java as:
```java
public enum Week {MON, TUE, WED, THU, FRI, SAT, SUN;}
```

This works because they have the same "value" which, if undefined, is the order in which the enum entry appears.

If the C enum contains values, the values need to match in Java by implementing a mapping function:

The signedness and width can be additionally modified using annotations for example, for C `long long` use a `long`
with the `@LongLong` annotation.
```c
enum State {On = 2, Off = 4, Broken = 8};
```
should be mapped in Java as:
```java
public static enum State implements EnumMapper.IntegerEnum {
ON(2), OFF(4), BROKEN(8);
private final int value;
public State(int value) {this.value = value;}
@Override
public int intValue() {return value;} // mapping function
}
```

C functions often use enums in "flags" and allow you to combine "flags" by logical OR-ing the values together. For example:

In addition to these types there exist numerous annotations for common C types for example `@size_t` on an `int` for C
`size_t`.
```c
void start_stream(stream_flags flags);
```
```c
// start paused and muted and allow latency adjustment
stream_flags flags = STREAM_START_PAUSED |
STREAM_START_MUTED |
STREAM_ADJUST_LATENCY;
start_stream(flags);
```

The same can be done in Java also by OR-ing the values of the enum, but more elegantly, by using an `EnumSet` where such a combined enum would be expected:

`boolean` can also be used in place of a C `int` where a boolean would be expected, check the function's documentation
before doing this.
```java
public void start_stream(EnumSet<stream_flags> flags);
```

```java
start_stream(EnumSet.of(
STREAM_START_PAUSED, STREAM_START_MUTED, STREAM_ADJUST_LATENCY
));
```

# Complex Types

Expand Down
10 changes: 2 additions & 8 deletions libtest/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export MACOSX_DEPLOYMENT_TARGET=10.5

CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null)))

TEST_SRCS = $(wildcard $(SRC_DIR)/*.c)
TEST_SRCS = $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*/*.c)
TEST_OBJS := $(patsubst $(SRC_DIR)/%.c, $(TEST_BUILD_DIR)/%.o, $(TEST_SRCS))

#
Expand Down Expand Up @@ -64,13 +64,7 @@ endif

ifeq ($(OS), darwin)
CC = gcc
ifneq ($(findstring $(CPU), x86_64),)
ARCHFLAGS = -arch x86_64
endif
ifneq ($(findstring $(CPU), ppc powerpc),)
ARCHFLAGS = -arch ppc
endif

ARCHFLAGS = -arch x86_64 -arch arm64
CFLAGS += -fno-common $(ARCHFLAGS)
LDFLAGS = $(ARCHFLAGS) -dynamiclib
LIBEXT = dylib
Expand Down
27 changes: 11 additions & 16 deletions libtest/NumberTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
*/

#include <stdio.h>
#include <stdbool.h>
#if !defined(__mips___) || defined(__PASE__)
# include <stdint.h>
#endif

// Let's define the stdint.h typedefs ourselves if they can't be found
#if !defined (_STDINT_H_) && !defined(_STDINT_H) && !defined(_SYS__STDINT_H_) && !defined(_H_STDINT)
typedef signed char int8_t;
typedef signed short int16_t;
Expand All @@ -31,23 +33,19 @@ typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
typedef char Signed8;
typedef short Signed16;
typedef int Signed32;
typedef long long Signed64;
typedef float Float32;
typedef double Float64;
typedef long SignedLong;
typedef void* pointer;

typedef unsigned long ulong;
typedef long double ldouble;
typedef void* pointer;
typedef enum Enum_t {e0, e1, e2, e3} Enum;

#define ADD(T) T add_##T(T arg1, T arg2) { return arg1 + arg2; }
#define SUB(T) T sub_##T(T arg1, T arg2) { return arg1 - arg2; }
#define MUL(T) T mul_##T(T arg1, T arg2) { return arg1 * arg2; }
#define DIV(T) T div_##T(T arg1, T arg2) { return arg1 / arg2; }
#define RET(T) T ret_##T(T arg1) { return arg1; }
typedef char* ptr;
#define TEST(T) ADD(T) SUB(T) MUL(T) DIV(T) RET(T)

TEST(int8_t);
TEST(int16_t);
TEST(int32_t);
Expand All @@ -60,11 +58,8 @@ TEST(float);
TEST(double);
TEST(long);
TEST(ulong);
TEST(Signed8);
TEST(Signed16);
TEST(Signed32);
TEST(Signed64);
TEST(SignedLong);
TEST(Float32);
TEST(Float64);
TEST(ldouble);

RET(bool);
RET(Enum);
RET(pointer);
71 changes: 71 additions & 0 deletions libtest/PointerNumericTest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <sys/types.h>
#include <sys/param.h>

#ifndef __mips__
# include <stdint.h>
#endif

#if defined(__mips64) || defined(__PASE__)
# include <stdint.h>
#endif

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

// Let's define the stdint.h typedefs ourselves if they can't be found
#if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(_SYS__STDINT_H_) && !defined(_H_STDINT)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif

typedef long double ldouble;
typedef unsigned long ulong;
typedef void* pointer;
typedef void* ptr;
typedef enum Enum_t {e0, e1, e2, e3} Enum;
typedef bool boolean;

#define RET(T) T ptr_num_ret_##T(void *p, int offset) { \
T tmp; memcpy(&tmp, (ptr) (p + offset), sizeof(tmp)); return tmp; \
}
#define SET(T) void ptr_num_set_##T(void *p, int offset, T value) { \
memcpy((ptr) (p + offset), &value, sizeof(value)); \
}

#define TEST(T) SET(T) RET(T)

TEST(int8_t);
TEST(int16_t);
TEST(int32_t);
TEST(long);
TEST(int64_t);

TEST(uint8_t);
TEST(uint16_t);
TEST(uint32_t);
TEST(ulong);
TEST(uint64_t);

TEST(float);
TEST(double);
TEST(ldouble);

TEST(boolean);
TEST(pointer);
TEST(Enum);

void *ptr_num_arr_get(void **array, int index) {
return array[index];
}

void ptr_num_arr_set(void **array, int index, void *value) {
array[index] = value;
}
Loading

0 comments on commit ebd461e

Please sign in to comment.