Skip to content

Commit 81e877f

Browse files
committed
manual use 4 spaces for indentation
why? Because IntelliJ is not supporting it well in every case (e.g. long parameters lists etc) and I don't want to fight this. Most of other java devs prefer spaces... so let it be :)
1 parent 478655c commit 81e877f

222 files changed

Lines changed: 56358 additions & 51612 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
77
Java 25 native implementation of the [Vortex](https://github.com/spiraldb/vortex) columnar file format. Uses FFM (
88
`MemorySegment`/`Arena`) instead of JNI or `sun.misc.Unsafe`.
99

10-
1110
## Branching strategy
1211

1312
Trunk-based development. PRs are fine but always squash or rebase — no merge commits.
@@ -20,11 +19,13 @@ Never use `mvn install` or `./mvwn install`.
2019
Generated sources (`fbs`/`proto` → Java) are committed under `core/src/main/java`.
2120
Normal builds need no external tools.
2221
To regenerate after editing `.fbs` or `.proto` schemas:
22+
2323
```bash
2424
brew install flatbuffers protobuf
2525
./mvnw generate-sources -pl core -P regenerate-sources
2626
# then commit the updated files
2727
```
28+
2829
Any `flatc` version works — the profile strips the version guard automatically.
2930

3031
```bash
@@ -69,9 +70,11 @@ Every public method must have complete Javadoc. The build enforces this via
6970
`failOnError=true` + `failOnWarnings=true` in the `maven-javadoc-plugin`.
7071

7172
Rules:
73+
7274
- Every public method needs a main description, `@param` for each parameter, and `@return` (unless `void`).
7375
- Every public record needs `@param` entries on the class-level doc (one per component).
74-
- Cross-references use `[ClassName#method(ParamType)]` — verify the target exists before writing it. Wrong references are **errors**, not warnings.
76+
- Cross-references use `[ClassName#method(ParamType)]` — verify the target exists before writing it. Wrong references
77+
are **errors**, not warnings.
7578
- `@see`-only Javadoc counts as "no main description" — always add a prose sentence.
7679

7780
**Check:** `./mvnw javadoc:javadoc -pl core` — must produce zero output.
@@ -108,9 +111,11 @@ Encoding IDs are strings (e.g. `"vortex.flat"`, `"fastlanes.bitpacked"`). `Decod
108111
via `ServiceLoader`; register custom decoders with `registry.register(decoder)`.
109112

110113
**Adding a new encoding:** three touch-points, always all three:
114+
111115
1. `EncodingId.java` — add enum constant `VORTEX_FOO("vortex.foo")`
112116
2. `AlpRdEncoding.java` (or `FooEncoding.java`) — implement `Encoding`
113-
3. `core/src/main/resources/META-INF/services/io.github.dfa1.vortex.encoding.Encoding` — add the fully-qualified class name
117+
3. `core/src/main/resources/META-INF/services/io.github.dfa1.vortex.encoding.Encoding` — add the fully-qualified class
118+
name
114119

115120
### Memory model
116121

@@ -120,6 +125,7 @@ the mapped region.
120125

121126
**Encoding output allocation rule:** never allocate `byte[]` + wrap with `MemorySegment.ofArray()` for decode output.
122127
Always allocate from `ctx.arena()`:
128+
123129
```java
124130
// WRONG — heap allocation, GC pressure, extra copy
125131
byte[] outBytes = new byte[(int) (n * elemBytes)];
@@ -128,6 +134,7 @@ MemorySegment out = MemorySegment.ofArray(outBytes);
128134
// CORRECT — off-heap, zero GC, same lifetime as the scan chunk
129135
MemorySegment out = ctx.arena().allocate(n * elemBytes);
130136
```
137+
131138
If the allocation is in a private static helper that doesn't receive `DecodeContext`, add an `Arena arena` parameter
132139
and pass `ctx.arena()` from the `decode()` call site.
133140

@@ -149,6 +156,7 @@ methods in the Rust source to get the exact protobuf schema, then implement from
149156

150157
## Code style
151158

159+
- indents are 4 spaces, enforced by checkstyle
152160
- Zero SonarQube bugs/smells policy.
153161
- No `sun.misc.Unsafe` or internal JDK APIs.
154162
- Prefer explicit over clever. Fail fast on unhandled cases.
@@ -173,11 +181,23 @@ class if genuinely shared by both.
173181
```java
174182
public final class FooEncoding implements Encoding {
175183

176-
@Override public EncodeResult encode(DType dtype, Object data) { return Encoder.encode(dtype, data); }
177-
@Override public Array decode(DecodeContext ctx) { return Decoder.decode(ctx); }
184+
@Override
185+
public EncodeResult encode(DType dtype, Object data) {
186+
return Encoder.encode(dtype, data);
187+
}
188+
189+
@Override
190+
public Array decode(DecodeContext ctx) {
191+
return Decoder.decode(ctx);
192+
}
193+
194+
private static final class Encoder {
195+
static EncodeResult encode(DType dtype, Object data) { ...}
196+
}
178197

179-
private static final class Encoder { static EncodeResult encode(DType dtype, Object data) { ... } }
180-
private static final class Decoder { static Array decode(DecodeContext ctx) { ... } }
198+
private static final class Decoder {
199+
static Array decode(DecodeContext ctx) { ...}
200+
}
181201
}
182202
```
183203

@@ -191,24 +211,29 @@ Their `EncodeResult` uses an `EncodeNode` with `metadata` set and an empty `buff
191211
```java
192212
ByteBuffer metaBuf = ByteBuffer.wrap(meta.toByteArray());
193213
EncodeNode node = new EncodeNode(encodingId, metaBuf, new EncodeNode[0], new int[]{});
194-
return new EncodeResult(node, List.of(), null, null);
214+
return new
215+
216+
EncodeResult(node, List.of(), null,null);
195217
```
196218

197219
The decoder reads back via `ctx.metadata()`, not `ctx.buffer(n)`.
198220

199221
## Testing
200222

201-
- Every feature needs unit tests covering: happy path, negative cases (invalid input, error conditions), and corner cases (empty, zero, max values, boundary conditions).
223+
- Every feature needs unit tests covering: happy path, negative cases (invalid input, error conditions), and corner
224+
cases (empty, zero, max values, boundary conditions).
202225
- Unit tests must be fast — no file I/O, no network, no sleep. Mock or use in-memory data.
203-
- Integration tests are critical: there is no formal spec, so interoperability with the Rust reference implementation is the ground truth. Write integration tests for every encoding round-trip and file format boundary.
226+
- Integration tests are critical: there is no formal spec, so interoperability with the Rust reference implementation is
227+
the ground truth. Write integration tests for every encoding round-trip and file format boundary.
204228
- JUnit 5 + Mockito (BDDMockito) + AssertJ.
205229
- Every test has `// Given` / `// When` / `// Then` sections.
206230
- Class under test is always named `sut`.
207231
- Use `BDDMockito` exclusively: `given(mock.method()).willReturn(value)`. Never the reverse form. Only static-import
208232
`given` and `then` — not `willReturn`/`willThrow`.
209233
- Prefer `@ParameterizedTest` over copy-pasting tests. Use `@ValueSource` when possible; `@ArgumentsSource` when more
210234
structure needed (test case must have a name).
211-
- Use `@ParameterizedTest` with seeded random generators for encoding/decoding logic where input space is large — they find corner cases that example tests miss.
235+
- Use `@ParameterizedTest` with seeded random generators for encoding/decoding logic where input space is large — they
236+
find corner cases that example tests miss.
212237
- Acceptance tests run the built jar end-to-end with hosh scripts.
213238
- Use `@Nested` to group related tests by scenario or feature within a test class:
214239
```java
@@ -222,15 +247,18 @@ The decoder reads back via `ctx.metadata()`, not `ctx.buffer(n)`.
222247

223248
## Random-data parameterized tests
224249

225-
Use `@ParameterizedTest` + `@MethodSource` for random-input coverage. Put generators in `RandomArrays` (integration module)
250+
Use `@ParameterizedTest` + `@MethodSource` for random-input coverage. Put generators in `RandomArrays` (integration
251+
module)
226252
or a similar utility class. Static provider methods in the test class delegate to the generator:
227253

228254
```java
229-
static Stream<long[]> i64ArrayProvider() { return RandomArrays.i64Arrays(30); }
255+
static Stream<long[]> i64ArrayProvider() {
256+
return RandomArrays.i64Arrays(30);
257+
}
230258

231259
@ParameterizedTest
232260
@MethodSource("i64ArrayProvider")
233-
void roundTrips(long[] data) { ... }
261+
void roundTrips(long[] data) { ...}
234262
```
235263

236264
Keep counts low (10–30) for integration tests that involve file I/O or JNI.

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ Pure-Java reader/writer for the [Vortex](https://github.com/spiraldb/vortex) col
1010
100% Java, no JNI, no `sun.misc.Unsafe`. Uses the FFM API (`MemorySegment`/`Arena`, Java 25+)
1111
for zero-copy memory-mapped reads.
1212

13-
| Project | Language | Notes |
14-
|---|---|---|
15-
| [spiraldb/vortex](https://github.com/spiraldb/vortex) | Rust | Reference implementation + JNI bindings |
16-
| [LaurieRhodes/vortex-go](https://github.com/LaurieRhodes/vortex-go) | Go | Pure-language port |
17-
| **dfa1/vortex-java** | **Java** | **This library** |
13+
| Project | Language | Notes |
14+
|---------------------------------------------------------------------|----------|-----------------------------------------|
15+
| [spiraldb/vortex](https://github.com/spiraldb/vortex) | Rust | Reference implementation + JNI bindings |
16+
| [LaurieRhodes/vortex-go](https://github.com/LaurieRhodes/vortex-go) | Go | Pure-language port |
17+
| **dfa1/vortex-java** | **Java** | **This library** |
1818

1919
## Who is this for
2020

@@ -56,13 +56,13 @@ see the documentation below.
5656

5757
Docs follow the [Diátaxis](https://diataxis.fr/) framework.
5858

59-
| Document | Mode | Contents |
60-
|---|---|---|
61-
| [docs/tutorial.md](docs/tutorial.md) | Tutorial | Step-by-step: write and read your first Vortex file |
62-
| [docs/how-to.md](docs/how-to.md) | How-to | Recipes: count rows, convert Parquet, filter, project, custom encodings |
63-
| [docs/reference.md](docs/reference.md) | Reference | API surface, CLI subcommands, operator tables, file-format trailer |
64-
| [docs/compatibility.md](docs/compatibility.md) | Reference | Encoding support table, S3 fixture status |
65-
| [docs/explanation.md](docs/explanation.md) | Explanation | Design rationale, memory model, testing strategy, benchmarks |
59+
| Document | Mode | Contents |
60+
|------------------------------------------------|-------------|-------------------------------------------------------------------------|
61+
| [docs/tutorial.md](docs/tutorial.md) | Tutorial | Step-by-step: write and read your first Vortex file |
62+
| [docs/how-to.md](docs/how-to.md) | How-to | Recipes: count rows, convert Parquet, filter, project, custom encodings |
63+
| [docs/reference.md](docs/reference.md) | Reference | API surface, CLI subcommands, operator tables, file-format trailer |
64+
| [docs/compatibility.md](docs/compatibility.md) | Reference | Encoding support table, S3 fixture status |
65+
| [docs/explanation.md](docs/explanation.md) | Explanation | Design rationale, memory model, testing strategy, benchmarks |
6666

6767
## Development
6868

0 commit comments

Comments
 (0)