An open API service indexing awesome lists of open source software.

https://github.com/openhft/chronicle-values


https://github.com/openhft/chronicle-values

Last synced: 9 months ago
JSON representation

Awesome Lists containing this project

README

          

= Chronicle-Values
Chronicle Software
:css-signature: demo
:toc: macro
:toclevels: 2
:icons: font

image:https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-values/badge.svg[caption="",link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-values]
image:https://javadoc.io/badge2/net.openhft/chronicle-values/javadoc.svg[link="https://www.javadoc.io/doc/net.openhft/chronicle-values/latest/index.html"]
//image:https://javadoc-badge.appspot.com/net.openhft/chronicle-values.svg?label=javadoc[JavaDoc, link=https://www.javadoc.io/doc/net.openhft/chronicle-values]
image:https://img.shields.io/github/license/OpenHFT/Chronicle-Values[GitHub]
image:https://img.shields.io/badge/release%20notes-subscribe-brightgreen[link="https://chronicle.software/release-notes/"]
image:https://sonarcloud.io/api/project_badges/measure?project=OpenHFT_Chronicle-Values&metric=alert_status[link="https://sonarcloud.io/dashboard?id=OpenHFT_Chronicle-Values"]

toc::[]

== About

Generation of constantly-sized flyweight accessors to
https://github.com/OpenHFT/Chronicle-Bytes[Chronicle Bytes] and simple bean-style on-heap implementations from
interfaces. Interfaces, that could be processed by Chronicle-Values generation, are called **value
interfaces**.

**Project status: Alpha**, the feature matrix (see below) is very vast and not fully implemented
yet, please write the value interface according to the specification below, with the **unit tests
for your interface**. If the generation from the value interface (according to spec) doesn't work,
please report the case via issues on Github.

==== Value interface specification

An important pre-requirement for value interfaces: they should belong to some package with
a non-empty name, not the default package.

Simple example:

```java
package test;

interface Balance {
long getDollars();
void setDollars(long dollars);
long addDollars(long addition);

int getCents();
void setCents(int cents);
}
```

is processed to either a flyweight of 12 bytes, or a bean class with `long dollars;` and
`int cents;` fields.

==== Supported field types

==== All Java primitives

`int`, `long`, `float`, `double`, `byte`, `boolean`, `char`, `short`

==== `String` or `CharSequence`

Must be annotated with `@MaxUtf8Length()`, like:

```java
interface Client {
CharSequence getName();
void setName(@MaxUtf8Length(20) CharSequence name);

CharSequence getStateCode();
void setStateCode(@NotNull @MaxUtf8Length(2) CharSequence stateCode);
}
```

==== Another value interface

This allows to build nested structures:

```java
interface Point {
double getX();
void setX(double x);

double getY();
void setY(double y);
}

interface Circle {
Point getCenter();
void getUsingCenter(Point using);
void setCenter(Point center);

double getRadius();
void setRadius(double radius);
}
```

Self-references are forbidden.

==== Any Java `enum` type

```java
interface Order {
enum State {NEW, CANCELLED, FILLED}

State getState();
void setState(@NotNull State state);
}
```

==== `java.util.Date`

==== Array fields

Of any of the above types, with special syntax: `-At` suffix and first parameter of all methods
should be `int index`.

```java
interface SomeStats {
@Array(length=100)
long getPercentFreqAt(int index);
void setPercentFreqAt(int index, long percentFreq);
long addPercentFreqAt(int index, long addition);
}
```

==== Supported methods

===== Simple get/set

`[get][At]`, `[set][At]`, `is[At]` - simple get/set. For `boolean`
fields, `isFoo()` Java bean syntax variation is supported. Also, `get-` and `set-` prefixes could be
omitted, e. g.
```java
interface Point {
double x();
void x(double x);

double y();
void y(double y);
}
```

===== Volatile get/set

`getVolatile[At]`, `setVolatile[At]`

===== "Ordered" set

`setOrdered[At]` - ordered write operation, the same as behind `AtomicInteger.lazySet()`

===== Simple add

`type add[At]([int index, ]type addition)` - equivalent of
```java
int foo = getFoo();
foo += addition;
setFoo(foo);
return foo;
```
works only with numeric primitive field types: `byte`, `char`, `short`, `int`, `long`, `double`,
`float`

===== Atomic add

`type addAtomic[At]([int index, ]type addition)` - same as `add`, operates via atomic
operations, works only with numeric primitive field types.

===== Compare-and-swap

`boolean compareAndSwap[At]([int index, ]type expectedValue, type newValue)` - atomic
field value exchange, returns `true` if successfully swapped the value. Works only with primitive,
`enum` and `Date` field types.

===== getUsing

`getUsing[At]([int index, ]Type using)` - for `String`, `CharSequence` or another value
interface field types. Reads the value into the given on-heap object. Primarily useful for
retrieving data from flyweight implementations without creating garbage.

If the field type is `String` or `CharSequence`, `using` parameter type must be `StringBuilder`.
Return type of the `getUsing` method in this case might be `CharSequence`, `StringBuilder`, `String`
or `void`, if this char sequence field is marked as `@NotNull`. Semantically this method is
equivalent to
```java
CharSequence getUsingName(StringBuilder using) {
using.setLength(0);
CharSequence name = getName();
if (name != null) {
using.append(name);
return using;
} else {
return null;
}
}
```

Note that the `StringBuilder` is cleared via `setLength(0)` before reusing.

If the field type is another value interface field, `using` parameter type is the value interface,
the return type of the method could be the interface or `void`. See `getUsingCenter(Point using)` in
the example above.

### Table of supported methods (type of field × type of method)
++++

Integer type: byte..long
float, double
boolean
Char sequence
Value interface
enum type
Date

get/set






Volatile get/set,
ordered set



 
 

Compare-and-swap



 
 

Simple add,
atomic add


 
 
 
 
 

getUsing
 
 
 


 
 

++++
===== Field configuration via annotations

===== Field ordering in flyweight layout

Field order is unspecified. To ensure some order, put `@Group` annotations on any of field's
methods, for example:

```java
interface Complex {
@Group(1)
double real();
void real(double real);

@Group(2)
double image();
void image(double image);
}
```

Groups are ordered in the ascending order of their argument numbers. In the above case, the
generated flyweight implementation will place `real` field at 0-7 bytes and `image` field at 8-15
bytes from it's offset.

===== Field nullability

By default, `enum` and `String`/`CharSequence` fields are nullable. Annotate them with
`@net.openhft.chronicle.values.NotNull` to forbid `null` values:

```java
interface Instrument {
CharSequence getSymbol();
void setSymbol(@NotNull @MaxUtf8Length(5) CharSequence symbol);
}
```

===== Numeric field ranges

Annotate numeric fields with `@Range(min=, max=)` to save space in flyweight implementation, e. g.

```java
interface Transaction {
int getSecondFromDayStart();
void setSecondFromDayStart(@Range(min = 0, max = 24 * 60 * 60) int secondFromDayStart);
}
```

The field `SecondFromDayStart` could take only 17 bits in bytes, instead of 32.

===== Field alignment

For flyweight implementation, you might need to align certain fields, to ensure some properties of
reads and writes. For example, you might want to ensure, that a certain field doesn't cross cache
line boundary:

```java
interface Message {
...many fields

@Align(dontCross=64)
long getImportantField();
void setImportantField(long importantValue);
}
```

See `@Align` and `@Array` annotations http://javadoc.io/doc/net.openhft/chronicle-values[Javadocs]
for more information.

== Use

```java
// flyweight
Point offHeapPoint = Values.newNativeReference(Point.class);
((Byteable) offHeapPoint).bytesStore(bytesStore, offset, 16);
offHeapPoint.setX(0);
offHeapPoint.setY(0);

// on-heap
Point onHeapPoint = Values.newHeapInstance(Point.class);
onHeapPoint.setX(1)
onHeapPoint.setY(2);
```

The generated on-heap and flyweight classes *do* implement:
- `Copyable`, to allow easy data exchange: `onHeapPoint.copyFrom(offHeapPoint)`
- `BytesMarshallable` from https://github.com/OpenHFT/Chronicle-Bytes[Chronicle Bytes]
- Proper `equals()`, `hashCode()` and `toString()`
- `Byteable`, but on-heap implementation is dummy, throws `UnsupportedOperationException`

For convenience, you could make the value interface to extend the above utility interfaces,
to avoid casting:

```java
interface Point extends Byteable, BytesMarshallable, Copyable { ... }

Point offHeapPoint = Values.newNativeReference(Point.class);
// no cast
offHeapPoint.bytesStore(bytesStore, offset, offHeapPoint.maxSize());
```

http://javadoc.io/doc/net.openhft/chronicle-values[Javadocs]