https://github.com/openhft/chronicle-values
https://github.com/openhft/chronicle-values
Last synced: 9 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/openhft/chronicle-values
- Owner: OpenHFT
- License: other
- Created: 2015-02-24T13:44:32.000Z (almost 11 years ago)
- Default Branch: ea
- Last Pushed: 2024-05-29T07:45:52.000Z (over 1 year ago)
- Last Synced: 2024-05-29T07:50:54.292Z (over 1 year ago)
- Language: Java
- Homepage: http://chronicle.software
- Size: 668 KB
- Stars: 103
- Watchers: 32
- Forks: 38
- Open Issues: 4
-
Metadata Files:
- Readme: README.adoc
- License: LICENSE.adoc
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]