<commit_before># Strukt

C-style structs on the JVM!

**ZERO** garbage, **ZERO** reflection, **ZERO** code generation.  
**EASY** to use, and with **INCREDIBLE** [performance](#performance).

[![Build Status](https://travis-ci.com/Jire/Strukt.svg?branch=master)](https://travis-ci.com/Jire/Strukt)
[![license](https://img.shields.io/github/license/Jire/Strukt.svg)](https://github.com/Jire/Strukt/blob/master/LICENSE.txt)

### Gradle

```groovy
compile group: 'org.jire.strukt', name: 'strukt', version: '3.0.0'
```

### Maven

```xml

<dependency>
	<groupId>org.jire.strukt</groupId>
	<artifactId>strukt</artifactId>
	<version>3.0.0</version>
</dependency>
```

---

## Declaring a Strukt

First you need to use one of the extension types on your `Strukt`'s `::class` which manages (allocates, frees, etc.)
your `Strukt` to create a `Strukts`.

```kotlin
val points = Point::class.dynamic()
```

You can also create a fixed-size amount of `Strukt`s like so:

```kotlin
val points = Point::class.fixed(1_000_000)
```

A fixed `Strukts` can also be persisted to the disk as a memory mapped file!
This means you can allocate with as much space as disk space, rather than RAM!

For example, the mapped file in this example allows us to work with 256GB of points on a machine with limited RAM!

```kotlin
val points = Point::class.fixed(32_000_000_000, "points.dat")
```

Then, you need to declare your fields using your `Strukts`s invoke operator.

The value you pass in determines the field's type, and the default value for each allocation -- in this case it's `0`
for both.

```kotlin
val pointX = points(0)
val pointY = points(0)
```

Now we need to define our inline `Strukt` class.

```kotlin
inline class Point(override val address: Long = points()) : Strukt {
	var x
		get() = pointX(address)
		set(value) = pointX(address, value)
	var y
		get() = pointY(address)
		set(value) = pointY(address, value)
}
```

Because of the way inlining works, you'll notice that we need to provide virtual fields using our previously defined
fields.

You should also notice the use of `Strukts`.`invoke` as a default value for allocating our address.

## Allocating a `Strukt`

The syntax for allocation is the same as a regular object!

For the above _Point_ example, this might look like:

```kotlin
val example = Point()
```

## Accessing fields

Accessing fields is exactly like normal objects!

```kotlin
example.y = 123
println("x: ${example.x}, y: ${example.y}") // 0, 123
```

## Freeing a `Strukt`

To free any `Strukt`, you can use:

```kotlin
points.free(example.address)
```

The reason this longer syntax is necessary is because we want to avoid "generic" type use of our inline class, to
prevent creating boxed instances.

## Performance

**Benchmark sources:** https://github.com/Jire/Strukt/tree/master/src/jmh/kotlin/org/jire/strukt/benchmarks

Tested on an Intel i7 6700K @ 4.6GHz with default Oracle JDK 15 VM parameters on Windows 10:

```Benchmark                               Mode  Cnt          Score   Error  Units
StruktBenchmark.allocateAndFreeStrukt  thrpt        11644117.580          ops/s
StruktBenchmark.allocateHeap           thrpt       246406567.735          ops/s
StruktBenchmark.allocateStrukt         thrpt        17847591.022          ops/s
StruktBenchmark.readHeap               thrpt       595599999.601          ops/s
StruktBenchmark.readStrukt             thrpt       294784816.513          ops/s
StruktBenchmark.writeHeap              thrpt       466761198.451          ops/s
StruktBenchmark.writeStrukt            thrpt       285848837.752          ops/s
```

Results

* ~14x (1400%) slower allocation
* ~2x (200%) slower read
* ~1.7x (170%) slower write

So there is insignificant overhead for read/write, but significant overhead for allocation (but remember, we aren't
allocating on-heap and there are absolutely <ins>no heap allocations</ins>!)<commit_msg>updated read-me with new benchmarks<commit_after># Strukt

C-style structs on the JVM!

**ZERO** garbage, **ZERO** reflection, **ZERO** code generation.  
**EASY** to use, and with **INCREDIBLE** [performance](#performance).

[![Build Status](https://travis-ci.com/Jire/Strukt.svg?branch=master)](https://travis-ci.com/Jire/Strukt)
[![license](https://img.shields.io/github/license/Jire/Strukt.svg)](https://github.com/Jire/Strukt/blob/master/LICENSE.txt)

### Gradle

```groovy
compile group: 'org.jire.strukt', name: 'strukt', version: '3.0.0'
```

### Maven

```xml

<dependency>
	<groupId>org.jire.strukt</groupId>
	<artifactId>strukt</artifactId>
	<version>3.0.0</version>
</dependency>
```

---

## Declaring a Strukt

First you need to use one of the extension types on your `Strukt`'s `::class` which manages (allocates, frees, etc.)
your `Strukt` to create a `Strukts`.

```kotlin
val points = Point::class.dynamic()
```

You can also create a fixed-size amount of `Strukt`s like so:

```kotlin
val points = Point::class.fixed(1_000_000)
```

A fixed `Strukts` can also be persisted to the disk as a memory mapped file!
This means you can allocate with as much space as disk space, rather than RAM!

For example, the mapped file in this example allows us to work with 256GB of points on a machine with limited RAM!

```kotlin
val points = Point::class.fixed(32_000_000_000, "points.dat")
```

Then, you need to declare your fields using your `Strukts`s invoke operator.

The value you pass in determines the field's type, and the default value for each allocation -- in this case it's `0`
for both.

```kotlin
val pointX = points(0)
val pointY = points(0)
```

Now we need to define our inline `Strukt` class.

```kotlin
inline class Point(override val address: Long = points()) : Strukt {
	var x
		get() = pointX(address)
		set(value) = pointX(address, value)
	var y
		get() = pointY(address)
		set(value) = pointY(address, value)
}
```

Because of the way inlining works, you'll notice that we need to provide virtual fields using our previously defined
fields.

You should also notice the use of `Strukts`.`invoke` as a default value for allocating our address.

## Allocating a `Strukt`

The syntax for allocation is the same as a regular object!

For the above _Point_ example, this might look like:

```kotlin
val example = Point()
```

## Accessing fields

Accessing fields is exactly like normal objects!

```kotlin
example.y = 123
println("x: ${example.x}, y: ${example.y}") // 0, 123
```

## Freeing a `Strukt`

To free any `Strukt`, you can use:

```kotlin
points.free(example.address)
```

The reason this longer syntax is necessary is because we want to avoid "generic" type use of our inline class, to
prevent creating boxed instances.

## Performance

**Benchmark sources:** https://github.com/Jire/Strukt/tree/master/src/jmh/kotlin/org/jire/strukt/benchmarks

Tested on an Intel i7 6700K @ 4.6GHz with default Oracle JDK 15 VM parameters on Windows 10:

```Benchmark                   Mode  Cnt           Score   Error  Units
Read.dynamic               thrpt       2240480052.572          ops/s
Read.fixed                 thrpt       2210184723.815          ops/s
Read.heap                  thrpt       2973032782.251          ops/s
Write.dynamic              thrpt       1788241968.846          ops/s
Write.fixed                thrpt       1976772320.155          ops/s
Write.heap                 thrpt       2264473541.725          ops/s
Allocations.dynamicStrukt     ss               42.130          ms/op
Allocations.fixedStrukt       ss             2537.961          ms/op
Allocations.heap              ss              161.395          ms/op
```
{'fraction_non_alphanumeric': 0.11390063424947146, 'fraction_numerical': 0.03818710359408034, 'mean_word_length': 3.2835314091680816, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '580466', 'n_tokens_mistral': 2699, 'n_tokens_neox': 2427, 'n_words': 831}