Compare commits
10 commits
f61a1e672d
...
3e63eef1d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e63eef1d1 | ||
|
|
178977d3b9 | ||
|
|
7d7e158b6b | ||
|
|
209e43657d | ||
|
|
938f6e9521 | ||
|
|
d7d4ca06fc | ||
|
|
ccb0bbf662 | ||
|
|
f90102d57f | ||
|
|
0bd9f62be0 | ||
|
|
f7f999bd53 |
56 changed files with 984 additions and 198 deletions
36
README.md
36
README.md
|
|
@ -1,11 +1,45 @@
|
||||||
**Design decisions**
|
**Design decisions**
|
||||||
|
|
||||||
* built for speed and efficiency (within java)
|
* built for speed and efficiency (within java)
|
||||||
* uses storage format borrowed from SQLite with 1 exception: float is stored as f32 (SQLite only uses f64)
|
* uses storage format borrowed from SQLite with 1 exception: float is stored as f32 (SQLite only uses f64)
|
||||||
* needs jdk 9 (VarHandles)
|
* needs jdk 9 (VarHandles)
|
||||||
* minimal reflection (once per creation of the list)
|
* minimal reflection (once per creation of the list)
|
||||||
|
|
||||||
* The only class (for now): [ContiguousList](https://github.com/shautvast/Contiguous/blob/main/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java)
|
* The only class (for
|
||||||
|
now): [ContiguousList](https://github.com/shautvast/Contiguous/blob/main/lib/src/main/java/com/github/shautvast/contiguous/ContiguousList.java)
|
||||||
|
|
||||||
* Still in a very early stage
|
* Still in a very early stage
|
||||||
* the code is working
|
* the code is working
|
||||||
* but it remains to be seen if this is a good idea
|
* but it remains to be seen if this is a good idea
|
||||||
|
|
||||||
|
**JMH Benchmark**
|
||||||
|
|
||||||
|
| Benchmark | Mode | Cnt | Score | Error | Units |
|
||||||
|
|------------|------|----:|-------------:|-------------:|-------|
|
||||||
|
| classic | avgt | 5 | 13312478.471 | ± 259931.663 | ns/op |
|
||||||
|
| contiguous | avgt | 5 | 13063782.511 | ± 451500.662 | ns/op |
|
||||||
|
|
||||||
|
* pretty much on par despite all the overhead for inspecting the list elements
|
||||||
|
* will try to squeeze out more performance
|
||||||
|
|
||||||
|
*Benchmark environment details*
|
||||||
|
|
||||||
|
```
|
||||||
|
[ec2-user@ip-172-31-22-215 Contiguous]$ lscpu
|
||||||
|
Architecture: x86_64
|
||||||
|
CPU op-mode(s): 32-bit, 64-bit
|
||||||
|
Address sizes: 46 bits physical, 48 bits virtual
|
||||||
|
Byte Order: Little Endian
|
||||||
|
CPU(s): 1
|
||||||
|
On-line CPU(s) list: 0
|
||||||
|
Vendor ID: GenuineIntel
|
||||||
|
Model name: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz
|
||||||
|
CPU family: 6
|
||||||
|
Model: 63
|
||||||
|
Thread(s) per core: 1
|
||||||
|
Core(s) per socket: 1
|
||||||
|
Socket(s): 1
|
||||||
|
Stepping: 2
|
||||||
|
BogoMIPS: 4800.04
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
102
benchmark/pom.xml
Normal file
102
benchmark/pom.xml
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.github.shautvast</groupId>
|
||||||
|
<artifactId>contiguous-pom</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>benchmark</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>20</maven.compiler.source>
|
||||||
|
<maven.compiler.target>20</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.shautvast</groupId>
|
||||||
|
<artifactId>contiguous-jdbc</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.shautvast</groupId>
|
||||||
|
<artifactId>contiguous-jackson</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-core</artifactId>
|
||||||
|
<version>1.36</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
|
<version>1.36</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.24</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.15.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<compilerVersion>9</compilerVersion>
|
||||||
|
<source>9</source>
|
||||||
|
<target>9</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<finalName>benchmark</finalName>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||||
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.github.shautvast.contiguous.benchmark;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/* copied from demo, need common module */
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Customer {
|
||||||
|
String name;
|
||||||
|
String email;
|
||||||
|
String streetname;
|
||||||
|
int housenumber;
|
||||||
|
String city;
|
||||||
|
String country;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.github.shautvast.contiguous.benchmark;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.github.shautvast.contiguous.ContiguousList;
|
||||||
|
import com.github.shautvast.contiguous.ListSerializer;
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
@Fork(value = 1)
|
||||||
|
public class JmhBenchmark {
|
||||||
|
|
||||||
|
@org.openjdk.jmh.annotations.State(Scope.Benchmark)
|
||||||
|
public static class State {
|
||||||
|
//mimick database
|
||||||
|
final List<Customer> customers = new ArrayList<>();
|
||||||
|
final ObjectMapper jacksonMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Setup()
|
||||||
|
public void setup() {
|
||||||
|
final SimpleModule contiguousListModule = new SimpleModule("contiguous_module");
|
||||||
|
contiguousListModule.addSerializer(new ListSerializer());
|
||||||
|
jacksonMapper.registerModule(contiguousListModule);
|
||||||
|
|
||||||
|
final RandomStuffGenerator generator = new RandomStuffGenerator();
|
||||||
|
for (int i = 0; i < 10_000; i++) {
|
||||||
|
Customer customer = new Customer();
|
||||||
|
String firstName = generator.generateFirstName();
|
||||||
|
String lastName = generator.generateLastName();
|
||||||
|
customer.name = firstName + " " + lastName;
|
||||||
|
customer.email = firstName + "." + lastName + "@icemail.com";
|
||||||
|
customer.streetname = generator.generateStreetName();
|
||||||
|
customer.housenumber = generator.generateSomeNumber();
|
||||||
|
customer.city = generator.generateSomeCityInIceland();
|
||||||
|
customer.country = generator.generateIceland();
|
||||||
|
customers.add(customer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public String contiguous(State state) throws JsonProcessingException {
|
||||||
|
//naive mimick read from database and add to ContiguousList
|
||||||
|
ContiguousList<Customer> customers = new ContiguousList<>(Customer.class);
|
||||||
|
customers.addAll(state.customers);
|
||||||
|
|
||||||
|
return state.jacksonMapper.writeValueAsString(customers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public String classic(State state) throws JsonProcessingException {
|
||||||
|
//naive mimick read from database and add to ArrayList
|
||||||
|
List<Customer> customers = new ArrayList<>();
|
||||||
|
customers.addAll(state.customers);
|
||||||
|
|
||||||
|
return state.jacksonMapper.writeValueAsString(customers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.github.shautvast.contiguous.benchmark;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/* Duplicate from demo */
|
||||||
|
public class RandomStuffGenerator {
|
||||||
|
|
||||||
|
private final List<String> firstNameParts = List.of("sa", "ka", "zo", "ja", "za", "ka", "po", "ji", "ne", "si", "wi", "ha", "ut", "va", "no", "bo"
|
||||||
|
, "jo", "fe", "gu");
|
||||||
|
|
||||||
|
private final List<String> lastNameParts = List.of("fin", "wil", "cat", "loc", "der", "ter", "asp", "pen", "ill", "raf", "gut", "dax", "yin");
|
||||||
|
private final List<String> cities = List.of("Reykjavík", "Kópavogur", "Hafnarfjörður", "Akureyri", "Reykjanesbær", "Garðabær", "Mosfellsbær", "Selfoss", "Akranes", "Seltjarnarnes", "Vestmannaeyjar", "Grindavík", "Ísafjörður", "Álftanes", "Sauðárkrókur", "Hveragerði", "Egilsstaðir", "Húsavík", "Borgarnes", "Sandgerði", "Höfn", "Þorlákshöfn", "Garður", "Neskaupstaður", "Dalvík", "Reyðarfjörður", "Siglufjörður", "Vogar", "Stykkishólmur", "Eskifjörður", "Ólafsvík", "Hvolsvöllur", "Bolungarvík", "Hella", "Grundarfjörður", "Blönduós", "Ólafsfjörður", "Fáskrúðsfjörður", "Patreksfjörður", "Seyðisfjörður", "Grundarhverfi", "Hvammstangi", "Stokkseyri", "Eyrarbakki", "Vopnafjörður", "Skagaströnd", "Flúðir", "Vík", "Fellabær", "Hellissandur", "Djúpivogur", "Þórshöfn", "Svalbarðseyri", "Hólmavík", "Grenivík", "Hvanneyri", "Þingeyri", "Búðardalur", "Reykholt", "Hrafnagil", "Suðureyri", "Tálknafjörður", "Bíldudalur", "Mosfellsdalur", "Hnífsdalur", "Reykjahlíð", "Laugarvatn", "Raufarhöfn", "Stöðvarfjörður", "Bifröst", "Flateyri", "Kirkjubæjarklaustur", "Súðavík", "Hrísey", "Hofsós", "Breiðdalsvík", "Rif", "Reykhólar", "Varmahlíð", "Kópasker", "Laugarás", "Borg", "Hauganes", "Hafnir", "Laugar", "Melahverfi", "Tjarnabyggð", "Árskógssandur", "Lónsbakki", "Hólar", "Nesjahverfi", "Sólheimar", "Brúnahlíð", "Drangsnes", "Borgarfjörður eystri", "Árbæjarhverfi", "Brautarholt", "Rauðalækur", "Bakkafjörður", "Innnes", "Grímsey", "Þykkvabær", "Laugarbakki", "Reykholt", "Árnes", "Kristnes", "Kleppjárnsreykir");
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
|
public String generateFirstName() {
|
||||||
|
return generateName(firstNameParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateLastName() {
|
||||||
|
return generateName(lastNameParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateStreetName() {
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
int nLastNameParts = random.nextInt(5) + 1;
|
||||||
|
for (int i = 0; i < nLastNameParts; i++) {
|
||||||
|
name.append(firstNameParts.get(random.nextInt(firstNameParts.size())));
|
||||||
|
name.append(lastNameParts.get(random.nextInt(lastNameParts.size())));
|
||||||
|
}
|
||||||
|
name.append("götu");
|
||||||
|
return name.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int generateSomeNumber() {
|
||||||
|
return random.nextInt(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateSomeCityInIceland() {
|
||||||
|
return cities.get(random.nextInt(cities.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateIceland() {
|
||||||
|
return "Iceland"; // meant to be humorous
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateName(List<String> parts) {
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
int size = random.nextInt(2) + 2;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
name.append(parts.get(random.nextInt(parts.size())));
|
||||||
|
}
|
||||||
|
return name.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-pom</artifactId>
|
<artifactId>contiguous-pom</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
@ -21,12 +21,12 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-jdbc</artifactId>
|
<artifactId>contiguous-jdbc</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-jackson</artifactId>
|
<artifactId>contiguous-jackson</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
@ -66,7 +66,8 @@
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<version>2.7.12</version>
|
<version>2.7.12</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<mainClass>nl.sanderhautvast.contiguous.demo.DemoApplication</mainClass>
|
<mainClass>com.github.shautvast.contiguous.demo.DemoApplication</mainClass>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package nl.sanderhautvast.contiguous.demo;
|
package com.github.shautvast.contiguous.demo;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.Module;
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import nl.sanderhautvast.contiguous.ListSerializer;
|
import com.github.shautvast.contiguous.ListSerializer;
|
||||||
import nl.sanderhautvast.contiguous.demo.repository.RandomStuffGenerator;
|
import com.github.shautvast.contiguous.demo.repository.RandomStuffGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.CommandLineRunner;
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous.demo.model;
|
package com.github.shautvast.contiguous.demo.model;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package nl.sanderhautvast.contiguous.demo.repository;
|
package com.github.shautvast.contiguous.demo.repository;
|
||||||
|
|
||||||
|
|
||||||
|
import com.github.shautvast.contiguous.ContiguousList;
|
||||||
|
import com.github.shautvast.contiguous.JdbcResults;
|
||||||
|
import com.github.shautvast.contiguous.demo.model.Customer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import nl.sanderhautvast.contiguous.ContiguousList;
|
|
||||||
import nl.sanderhautvast.contiguous.JdbcResults;
|
|
||||||
import nl.sanderhautvast.contiguous.demo.model.Customer;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
@ -29,7 +29,7 @@ public class CustomerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Customer> getAllCustomersTraditional() {
|
public List<Customer> getAllCustomersTraditional() {
|
||||||
return jdbcTemplate.query("select * from customers", (rs, rowNum) -> new Customer(
|
return jdbcTemplate.query("select * from customers limit 10000", (rs, rowNum) -> new Customer(
|
||||||
rs.getString("name"),rs.getString("email"),
|
rs.getString("name"),rs.getString("email"),
|
||||||
rs.getString("streetname"), rs.getInt("housenumber"),
|
rs.getString("streetname"), rs.getInt("housenumber"),
|
||||||
rs.getString("city"), rs.getString("country")
|
rs.getString("city"), rs.getString("country")
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous.demo.repository;
|
package com.github.shautvast.contiguous.demo.repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous.demo.rest;
|
package com.github.shautvast.contiguous.demo.rest;
|
||||||
|
|
||||||
|
import com.github.shautvast.contiguous.ContiguousList;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import nl.sanderhautvast.contiguous.ContiguousList;
|
import com.github.shautvast.contiguous.demo.model.Customer;
|
||||||
import nl.sanderhautvast.contiguous.demo.model.Customer;
|
import com.github.shautvast.contiguous.demo.repository.CustomerRepository;
|
||||||
import nl.sanderhautvast.contiguous.demo.repository.CustomerRepository;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
@ -23,7 +23,12 @@ public class DemoRestApi {
|
||||||
|
|
||||||
@GetMapping(value = "/api/customers", produces = "application/json")
|
@GetMapping(value = "/api/customers", produces = "application/json")
|
||||||
public ContiguousList<Customer> getCustomers() {
|
public ContiguousList<Customer> getCustomers() {
|
||||||
|
try {
|
||||||
return customerRepository.getAllCustomers();
|
return customerRepository.getAllCustomers();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("",e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/api/customers/traditional", produces = "application/json")
|
@GetMapping(value = "/api/customers/traditional", produces = "application/json")
|
||||||
|
|
@ -35,4 +40,5 @@ public class DemoRestApi {
|
||||||
public List<Customer> getCustomersHybrid() {
|
public List<Customer> getCustomersHybrid() {
|
||||||
return customerRepository.getAllCustomersHybrid();
|
return customerRepository.getAllCustomersHybrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-pom</artifactId>
|
<artifactId>contiguous-pom</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous</artifactId>
|
<artifactId>contiguous</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
|
@ -7,9 +7,9 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class ListSerializer<E> extends StdSerializer<ContiguousList<?>> {
|
public class ListSerializer extends StdSerializer<ContiguousList<?>> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public ListSerializer() {
|
public ListSerializer() {
|
||||||
super((Class) ContiguousList.class); // ?
|
super((Class) ContiguousList.class); // ?
|
||||||
}
|
}
|
||||||
|
|
@ -22,10 +22,12 @@ public class ListSerializer<E> extends StdSerializer<ContiguousList<?>> {
|
||||||
|
|
||||||
Iterator<String> jsons = clist.jsonIterator();
|
Iterator<String> jsons = clist.jsonIterator();
|
||||||
while (jsons.hasNext()) {
|
while (jsons.hasNext()) {
|
||||||
generator.writeRawValue(jsons.next());
|
String next = jsons.next();
|
||||||
|
generator.writeRawValue(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.writeEndArray();
|
generator.writeEndArray();
|
||||||
|
clist.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
public class AdamsObject {
|
public class AdamsObject {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
@ -10,16 +10,16 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
class ListSerializerTest {
|
class ListSerializerTest {
|
||||||
|
|
||||||
|
|
||||||
private ObjectMapper mapper;
|
private ObjectMapper mapper;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup(){
|
public void setup() {
|
||||||
mapper = new ObjectMapper();
|
mapper = new ObjectMapper();
|
||||||
final SimpleModule module = new SimpleModule("mySerializers");
|
final SimpleModule module = new SimpleModule("mySerializers");
|
||||||
module.addSerializer(new ListSerializer<>());
|
module.addSerializer(new ListSerializer());
|
||||||
mapper.registerModule(module);
|
mapper.registerModule(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStringList() throws JsonProcessingException {
|
public void testStringList() throws JsonProcessingException {
|
||||||
ContiguousList<String> strings = new ContiguousList<>(String.class);
|
ContiguousList<String> strings = new ContiguousList<>(String.class);
|
||||||
|
|
@ -42,7 +42,6 @@ class ListSerializerTest {
|
||||||
strings.add(new AdamsObject("Publishing houses of Ursa Minor"));
|
strings.add(new AdamsObject("Publishing houses of Ursa Minor"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String json = mapper.writeValueAsString(strings);
|
String json = mapper.writeValueAsString(strings);
|
||||||
assertEquals("[{\"name\": \"Vogon constructor fleet\"}," +
|
assertEquals("[{\"name\": \"Vogon constructor fleet\"}," +
|
||||||
"{\"name\": \"Restaurant at the end of the Galaxy\"}," +
|
"{\"name\": \"Restaurant at the end of the Galaxy\"}," +
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-pom</artifactId>
|
<artifactId>contiguous-pom</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous</artifactId>
|
<artifactId>contiguous</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
@ -1,27 +1,22 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class JdbcResultsTest {
|
class JdbcResultsTest {
|
||||||
|
|
||||||
@Mock
|
|
||||||
private ResultSet mockResults;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListOfString() throws SQLException {
|
public void testListOfString() throws SQLException {
|
||||||
|
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||||
when(mockResults.next()).thenReturn(true, false);
|
when(mockResults.next()).thenReturn(true, false);
|
||||||
when(mockResults.getObject(1)).thenReturn("Zaphod");
|
when(mockResults.getObject(1)).thenReturn("Zaphod");
|
||||||
|
|
||||||
|
|
@ -36,6 +31,7 @@ class JdbcResultsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListOfBean() throws SQLException {
|
public void testListOfBean() throws SQLException {
|
||||||
|
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||||
when(mockResults.next()).thenReturn(true, false);
|
when(mockResults.next()).thenReturn(true, false);
|
||||||
// the shape of the result equals that of the result (name:String, age:int)
|
// the shape of the result equals that of the result (name:String, age:int)
|
||||||
when(mockResults.getObject("name")).thenReturn("Zaphod");
|
when(mockResults.getObject("name")).thenReturn("Zaphod");
|
||||||
|
|
@ -52,6 +48,7 @@ class JdbcResultsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMapping() throws SQLException {
|
public void testNameMapping() throws SQLException {
|
||||||
|
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||||
when(mockResults.next()).thenReturn(true, false);
|
when(mockResults.next()).thenReturn(true, false);
|
||||||
when(mockResults.getObject("name")).thenReturn("Trillian");
|
when(mockResults.getObject("name")).thenReturn("Trillian");
|
||||||
when(mockResults.getObject("realName")).thenReturn("Tricia MacMillan");
|
when(mockResults.getObject("realName")).thenReturn("Tricia MacMillan");
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -16,17 +16,17 @@
|
||||||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
<stringProp name="LoopController.loops">100</stringProp>
|
<stringProp name="LoopController.loops">1000</stringProp>
|
||||||
</elementProp>
|
</elementProp>
|
||||||
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
<stringProp name="ThreadGroup.num_threads">3</stringProp>
|
||||||
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
<stringProp name="ThreadGroup.ramp_time">10</stringProp>
|
||||||
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
<stringProp name="ThreadGroup.duration"></stringProp>
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
<stringProp name="ThreadGroup.delay"></stringProp>
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||||
</ThreadGroup>
|
</ThreadGroup>
|
||||||
<hashTree>
|
<hashTree>
|
||||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="contiguous" enabled="false">
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="contiguous" enabled="true">
|
||||||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
<collectionProp name="Arguments.arguments"/>
|
<collectionProp name="Arguments.arguments"/>
|
||||||
</elementProp>
|
</elementProp>
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<stringProp name="HTTPSampler.port">8080</stringProp>
|
<stringProp name="HTTPSampler.port">8080</stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol">http</stringProp>
|
<stringProp name="HTTPSampler.protocol">http</stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">/api/customers</stringProp>
|
<stringProp name="HTTPSampler.path">/api/customers/streamon</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
</HTTPSamplerProxy>
|
</HTTPSamplerProxy>
|
||||||
<hashTree/>
|
<hashTree/>
|
||||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="traditional" enabled="true">
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="traditional" enabled="false">
|
||||||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
<collectionProp name="Arguments.arguments"/>
|
<collectionProp name="Arguments.arguments"/>
|
||||||
</elementProp>
|
</elementProp>
|
||||||
|
|
@ -83,6 +83,49 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
</HTTPSamplerProxy>
|
</HTTPSamplerProxy>
|
||||||
<hashTree/>
|
<hashTree/>
|
||||||
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="toy" enabled="false">
|
||||||
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="HTTPSampler.domain">localhost</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.port">8080</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.protocol">http</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.path">api/customers/toy</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
||||||
|
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
|
</HTTPSamplerProxy>
|
||||||
|
<hashTree/>
|
||||||
|
<UniformRandomTimer guiclass="UniformRandomTimerGui" testclass="UniformRandomTimer" testname="Uniform Random Timer" enabled="true">
|
||||||
|
<stringProp name="ConstantTimer.delay">0</stringProp>
|
||||||
|
<stringProp name="RandomTimer.range">100.0</stringProp>
|
||||||
|
</UniformRandomTimer>
|
||||||
|
<hashTree/>
|
||||||
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="streamon" enabled="false">
|
||||||
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="HTTPSampler.domain">localhost</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.port">8080</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.protocol">http</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.path">/api/customers/streamon2</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
||||||
|
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
|
</HTTPSamplerProxy>
|
||||||
|
<hashTree/>
|
||||||
</hashTree>
|
</hashTree>
|
||||||
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
|
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
|
||||||
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
|
|
||||||
21
lib/pom.xml
21
lib/pom.xml
|
|
@ -5,22 +5,27 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-pom</artifactId>
|
<artifactId>contiguous-pom</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>contiguous</artifactId>
|
<artifactId>contiguous</artifactId>
|
||||||
|
|
||||||
<description>Datastructures with contiguous storage. Core library with no external dependencies</description>
|
<description>Datastructures with contiguous storage. Core library</description>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>9</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>9</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.shautvast</groupId>
|
||||||
|
<artifactId>reflective</artifactId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
|
@ -40,4 +45,12 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>github</id>
|
||||||
|
<name>GitHub OWNER Apache Maven Packages</name>
|
||||||
|
<url>https://maven.pkg.github.com/shautvast/Contiguous</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
class BigDecimalHandler extends BuiltinTypeHandler<BigDecimal> {
|
class BigDecimalHandler extends BuiltinTypeHandler<BigDecimal> {
|
||||||
public BigDecimalHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public BigDecimalHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(BigDecimal.class, propertyName, getter, setter);
|
super(BigDecimal.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
class BigIntegerHandler extends BuiltinTypeHandler<BigInteger> {
|
class BigIntegerHandler extends BuiltinTypeHandler<BigInteger> {
|
||||||
public BigIntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public BigIntegerHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(BigInteger.class, propertyName, getter, setter);
|
super(BigInteger.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boundless cache something
|
||||||
|
*/
|
||||||
|
class BufferCache {
|
||||||
|
private static final ConcurrentHashMap<Integer, ByteBuffer> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
static ByteBuffer get(int size) {
|
||||||
|
ByteBuffer byteBuffer = Optional.ofNullable(cache.get(size)).orElseGet(() -> ByteBuffer.allocate(size));
|
||||||
|
byteBuffer.position(0);
|
||||||
|
return byteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release(ByteBuffer byteBuffer) {
|
||||||
|
cache.put(byteBuffer.capacity(), byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage.
|
* Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage.
|
||||||
|
|
@ -11,8 +11,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
* of the bean that it needs to call 'runtime' (after instantiation of the list),
|
* of the bean that it needs to call 'runtime' (after instantiation of the list),
|
||||||
* ie. when a bean is added or retrieved from the list
|
* ie. when a bean is added or retrieved from the list
|
||||||
*/
|
*/
|
||||||
public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
public BuiltinTypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
public BuiltinTypeHandler(Class<?> type, String name, MetaMethod getter, MetaMethod setter) {
|
||||||
super(type, name, getter, setter);
|
super(type, name, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,18 +29,19 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
store(propertyValue, typedList);
|
store(propertyValue, typedList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
||||||
store((T) value, contiguousList);
|
store((T) value, contiguousList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private T getValue(Object propertyValue) {
|
private T getValue(Object propertyValue) {
|
||||||
// I don't trust this
|
// I don't trust this
|
||||||
if (getter == null) {
|
if (getter == null) {
|
||||||
return (T) propertyValue;
|
return (T) propertyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (T) getter.invoke(propertyValue);
|
return (T) getter.invoke(propertyValue).unwrap();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +59,7 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
*/
|
*/
|
||||||
public void setValue(Object instance, Object value) {
|
public void setValue(Object instance, Object value) {
|
||||||
try {
|
try {
|
||||||
setter.invokeWithArguments(instance, cast(value));
|
setter.invoke(instance, cast(value)).unwrap();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a byte value.
|
* Stores a byte value.
|
||||||
*/
|
*/
|
||||||
class ByteHandler extends BuiltinTypeHandler<Byte> {
|
class ByteHandler extends BuiltinTypeHandler<Byte> {
|
||||||
|
|
||||||
public ByteHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public ByteHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Byte.class, propertyName, getter, setter);
|
super(Byte.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
class CompoundTypeHandler extends TypeHandler {
|
class CompoundTypeHandler extends TypeHandler {
|
||||||
private final Map<String, TypeHandler> properties = new LinkedHashMap<>();
|
private final Map<String, TypeHandler> properties = new LinkedHashMap<>();
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
import com.github.shautvast.reflective.MetaClass;
|
||||||
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
import com.github.shautvast.reflective.Reflective;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
@ -56,22 +58,27 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
/*
|
/*
|
||||||
* storage for dehydated objects
|
* storage for dehydated objects
|
||||||
*/
|
*/
|
||||||
private ByteBuffer data = ByteBuffer.allocate(4096);//TODO create constructor with capacity
|
private ByteBuffer data = BufferCache.get(4096);
|
||||||
|
|
||||||
private int bufferPosition;
|
private int bufferPosition;
|
||||||
|
|
||||||
private ArrayList<Integer> elementIndices = new ArrayList<>(); // avoids autoboxing. Could also use standard ArrayList though
|
private final ArrayList<Integer> elementIndices = new ArrayList<>(); // avoids autoboxing. Could also use standard ArrayList though
|
||||||
// is there a standard lib IntList??
|
// is there a standard lib IntList??
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
private TypeHandler rootHandler;
|
private final TypeHandler rootHandler;
|
||||||
|
private static final Map<Class<?>, TypeHandler> TYPE_HANDLERS = new HashMap<>();
|
||||||
|
|
||||||
public ContiguousList(Class<E> type) {
|
public ContiguousList(Class<E> type) {
|
||||||
inspectType(type);
|
this.rootHandler = inspectType(type);
|
||||||
elementIndices.add(0); // index of first element
|
elementIndices.add(0); // index of first element
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
BufferCache.release(this.data);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a list of setters and getters to execute later on to get/set the values of the object
|
* Get a list of setters and getters to execute later on to get/set the values of the object
|
||||||
*
|
*
|
||||||
|
|
@ -80,44 +87,41 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
* The advantage of the current implementation is that the binary data is not aware of the actual
|
* The advantage of the current implementation is that the binary data is not aware of the actual
|
||||||
* object graph. It only knows the 'primitive' values.
|
* object graph. It only knows the 'primitive' values.
|
||||||
*/
|
*/
|
||||||
private void inspectType(Class<?> elementClass) {
|
private TypeHandler inspectType(Class<?> elementClass) {
|
||||||
if (PropertyHandlerFactory.isBuiltInType(elementClass)) {
|
return TYPE_HANDLERS.computeIfAbsent(elementClass, k ->
|
||||||
this.rootHandler = PropertyHandlerFactory.forType(elementClass);
|
PropertyHandlerFactory.forType(elementClass)
|
||||||
} else {
|
.orElseGet(() -> {
|
||||||
CompoundTypeHandler compoundType = new CompoundTypeHandler(elementClass);
|
TypeHandler compoundTypeHandler = new CompoundTypeHandler(elementClass);
|
||||||
this.rootHandler = compoundType;
|
addPropertyHandlersForCompoundType(elementClass, (CompoundTypeHandler) compoundTypeHandler);
|
||||||
try {
|
return compoundTypeHandler;
|
||||||
addPropertyHandlersForCompoundType(elementClass, compoundType);
|
})
|
||||||
} catch (IllegalAccessException e) {
|
);
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* using reflection find all properties in the element, recursing down when the property is compound
|
* using reflection find all properties in the element, recursing down when the property is compound
|
||||||
*/
|
*/
|
||||||
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundTypeHandler parentCompoundType) throws IllegalAccessException {
|
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundTypeHandler parentCompoundType) {
|
||||||
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
|
MetaClass metaType = Reflective.getMetaClass(type);
|
||||||
Arrays.stream(type.getDeclaredFields())
|
Arrays.stream(type.getDeclaredFields())
|
||||||
.forEach(field -> {
|
.forEach(field -> {
|
||||||
try {
|
try {
|
||||||
Class<?> fieldType = field.getType();
|
Class<?> fieldType = field.getType();
|
||||||
MethodHandle getter = lookup.findGetter(type, field.getName(), fieldType);
|
|
||||||
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
|
|
||||||
|
|
||||||
if (PropertyHandlerFactory.isBuiltInType(fieldType)) {
|
String capitalized = capitalize(field.getName());
|
||||||
BuiltinTypeHandler<?> primitiveType =
|
MetaMethod getter = metaType.getMethod("get" + capitalized).get();
|
||||||
PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
MetaMethod setter = metaType.getMethod("set" + capitalized).get();
|
||||||
|
|
||||||
parentCompoundType.addHandler(field.getName(), primitiveType);
|
Optional<TypeHandler> typeHandler = PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
||||||
|
if (typeHandler.isPresent()) {
|
||||||
|
parentCompoundType.addHandler(field.getName(), (BuiltinTypeHandler<?>) typeHandler.get());
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler newParent = new CompoundTypeHandler(fieldType, field.getName());
|
CompoundTypeHandler handler = new CompoundTypeHandler(fieldType, field.getName());
|
||||||
newParent.setGetter(getter);
|
handler.setGetter(getter);
|
||||||
newParent.setSetter(setter);
|
handler.setSetter(setter);
|
||||||
parentCompoundType.addChild(field, newParent);
|
parentCompoundType.addChild(field, handler);
|
||||||
|
|
||||||
addPropertyHandlersForCompoundType(fieldType, newParent);
|
addPropertyHandlersForCompoundType(fieldType, handler);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
@ -153,7 +157,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler child = ((CompoundTypeHandler) property);
|
CompoundTypeHandler child = ((CompoundTypeHandler) property);
|
||||||
try {
|
try {
|
||||||
Object result = child.getGetter().invoke(element);
|
Object result = child.getGetter().invoke(element).unwrap();
|
||||||
storePropertyData(result, child);
|
storePropertyData(result, child);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
@ -205,7 +209,8 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
compoundType.getProperties().forEach(property -> {
|
compoundType.getProperties().forEach(property -> {
|
||||||
if (property instanceof BuiltinTypeHandler) {
|
if (property instanceof BuiltinTypeHandler) {
|
||||||
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
|
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
|
||||||
type.setValue(element, ValueReader.read(data));
|
Object readValue = ValueReader.read(data);
|
||||||
|
type.setValue(element, readValue);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
||||||
|
|
@ -213,7 +218,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
Object newInstance = p.getType().getDeclaredConstructor().newInstance();
|
Object newInstance = p.getType().getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
// set it on the parent
|
// set it on the parent
|
||||||
p.getSetter().invokeWithArguments(element, newInstance);
|
p.getSetter().invoke(element, newInstance);
|
||||||
|
|
||||||
// recurse down
|
// recurse down
|
||||||
copyDataIntoNewObject(newInstance, p);
|
copyDataIntoNewObject(newInstance, p);
|
||||||
|
|
@ -270,7 +275,6 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
data.position(elementIndices.get(index));
|
data.position(elementIndices.get(index));
|
||||||
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
||||||
|
|
||||||
BuiltinTypeHandler<?> handler = (BuiltinTypeHandler<?>) rootHandler;
|
BuiltinTypeHandler<?> handler = (BuiltinTypeHandler<?>) rootHandler;
|
||||||
return getValue(handler);
|
return getValue(handler);
|
||||||
}
|
}
|
||||||
|
|
@ -280,22 +284,19 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
copyDataIntoStringBuilder(s, (CompoundTypeHandler) rootHandler);
|
copyDataIntoStringBuilder(s, (CompoundTypeHandler) rootHandler);
|
||||||
s.append("}");
|
s.append("}");
|
||||||
return s.toString();
|
return s.toString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getValue(BuiltinTypeHandler<?> handler) {
|
private String getValue(BuiltinTypeHandler<?> handler) {
|
||||||
Object read = ValueReader.read(data);
|
String value = String.valueOf(ValueReader.read(data));
|
||||||
String out = handler.cast(read).toString();
|
|
||||||
if (handler instanceof StringHandler) {
|
if (handler instanceof StringHandler) {
|
||||||
out = quote(out);
|
return quote(value);
|
||||||
}
|
}
|
||||||
return out;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String quote(String out) {
|
private static String quote(String out) {
|
||||||
StringBuilder s = new StringBuilder(out.length() + 2);
|
StringBuilder s = new StringBuilder(out.length() + 2);
|
||||||
out = s.append("\"").append(out).append("\"").toString();
|
return s.append("\"").append(out).append("\"").toString();
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -305,8 +306,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
compoundType.getProperties().forEach(property -> {
|
compoundType.getProperties().forEach(property -> {
|
||||||
if (property instanceof BuiltinTypeHandler) {
|
if (property instanceof BuiltinTypeHandler) {
|
||||||
BuiltinTypeHandler<?> typeHandler = (BuiltinTypeHandler<?>) property;
|
BuiltinTypeHandler<?> typeHandler = (BuiltinTypeHandler<?>) property;
|
||||||
s.append(quote(typeHandler.getName()))
|
s.append("\"")
|
||||||
.append(": ")
|
.append(typeHandler.getName())
|
||||||
|
.append("\": ")
|
||||||
.append(getValue(typeHandler));
|
.append(getValue(typeHandler));
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
||||||
|
|
@ -608,8 +610,10 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
|
|
||||||
private void ensureFree(int length) {
|
private void ensureFree(int length) {
|
||||||
while (bufferPosition + length > data.capacity()) {
|
while (bufferPosition + length > data.capacity()) {
|
||||||
byte[] bytes = this.data.array();
|
ByteBuffer bytes = this.data;
|
||||||
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
|
bytes.position(0);
|
||||||
|
BufferCache.release(this.data);
|
||||||
|
this.data = BufferCache.get((int) (bytes.capacity() * 1.5));
|
||||||
this.data.put(bytes);
|
this.data.put(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -738,4 +742,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
} else return Varint.write(6);
|
} else return Varint.write(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String capitalize(String text) {
|
||||||
|
return text.substring(0, 1).toUpperCase() + text.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a double value.
|
* Stores a double value.
|
||||||
*/
|
*/
|
||||||
class DoubleHandler extends BuiltinTypeHandler<Double> {
|
class DoubleHandler extends BuiltinTypeHandler<Double> {
|
||||||
public DoubleHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public DoubleHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Double.class, propertyName, getter, setter);
|
super(Double.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
class FloatHandler extends BuiltinTypeHandler<Float> {
|
class FloatHandler extends BuiltinTypeHandler<Float> {
|
||||||
public FloatHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public FloatHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Float.class, propertyName, getter, setter);
|
super(Float.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
class IntegerHandler extends BuiltinTypeHandler<Integer> {
|
class IntegerHandler extends BuiltinTypeHandler<Integer> {
|
||||||
public IntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public IntegerHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Integer.class, propertyName, getter, setter);
|
super(Integer.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
class LongHandler extends BuiltinTypeHandler<Long> {
|
class LongHandler extends BuiltinTypeHandler<Long> {
|
||||||
public LongHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public LongHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Long.class, propertyName, getter, setter);
|
super(Long.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class that is a list of all the methods live that will likely not be implemented (pun intended)
|
* Base class with all the methods that will not be implemented
|
||||||
* Only purpose: reduce linecount in the subclass.
|
* Only purpose: reduce linecount in the subclass.
|
||||||
*
|
*
|
||||||
* @param <E>
|
* @param <E>
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maps the propertyvalue type to a PropertyHandler
|
* Maps the propertyvalue type to a PropertyHandler
|
||||||
*/
|
*/
|
||||||
final class PropertyHandlerFactory {
|
final class PropertyHandlerFactory {
|
||||||
private static final Map<Class<?>, Class<? extends BuiltinTypeHandler<?>>> TYPE_HANDLERS = new HashMap<>();
|
private static final Map<Class<?>, Class<? extends BuiltinTypeHandler<?>>> BUILTIN = new HashMap<>();
|
||||||
|
|
||||||
private PropertyHandlerFactory() {
|
private PropertyHandlerFactory() {
|
||||||
}
|
}
|
||||||
|
|
@ -35,27 +37,23 @@ final class PropertyHandlerFactory {
|
||||||
register(BigDecimal.class, BigDecimalHandler.class);
|
register(BigDecimal.class, BigDecimalHandler.class);
|
||||||
//Date/Timestamp
|
//Date/Timestamp
|
||||||
//LocalDate/time
|
//LocalDate/time
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBuiltInType(Class<?> type) {
|
@SuppressWarnings("unchecked")
|
||||||
return TYPE_HANDLERS.containsKey(type);
|
public static <T> Optional<TypeHandler> forType(Class<T> type, String name, MetaMethod getter, MetaMethod setter) {
|
||||||
}
|
return Optional.ofNullable(BUILTIN.get(type)).map(appenderClass -> {
|
||||||
|
|
||||||
public static <T> BuiltinTypeHandler<T> forType(Class<T> type, String name, MethodHandle getter, MethodHandle setter) {
|
|
||||||
try {
|
try {
|
||||||
Class<? extends BuiltinTypeHandler<?>> appenderClass = TYPE_HANDLERS.get(type);
|
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MetaMethod.class, MetaMethod.class)
|
||||||
if (appenderClass == null) {
|
|
||||||
throw new IllegalStateException("No Handler for " + type.getName());
|
|
||||||
}
|
|
||||||
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class)
|
|
||||||
.newInstance(name, getter, setter);
|
.newInstance(name, getter, setter);
|
||||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||||
InvocationTargetException e) {
|
InvocationTargetException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> BuiltinTypeHandler<T> forType(Class<T> type) {
|
public static <T> Optional<TypeHandler> forType(Class<T> type) {
|
||||||
return forType(type, null, null, null);
|
return forType(type, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,6 +61,6 @@ final class PropertyHandlerFactory {
|
||||||
* register a new TypeHandler that cannot be derived from bean properties
|
* register a new TypeHandler that cannot be derived from bean properties
|
||||||
*/
|
*/
|
||||||
public static void register(Class<?> type, Class<? extends BuiltinTypeHandler<?>> typehandler) {
|
public static void register(Class<?> type, Class<? extends BuiltinTypeHandler<?>> typehandler) {
|
||||||
TYPE_HANDLERS.put(type, typehandler);
|
BUILTIN.put(type, typehandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
class ShortHandler extends BuiltinTypeHandler<Short> {
|
class ShortHandler extends BuiltinTypeHandler<Short> {
|
||||||
public ShortHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public ShortHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(Short.class, propertyName, getter, setter);
|
super(Short.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
class StringHandler extends BuiltinTypeHandler<String> {
|
class StringHandler extends BuiltinTypeHandler<String> {
|
||||||
public StringHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
public StringHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
|
||||||
super(String.class, propertyName, getter, setter);
|
super(String.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import com.github.shautvast.reflective.MetaMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract basertype over handlers for 'primitives' (ie. long, but also Long,
|
* Abstract basetype over handlers for 'primitives' (ie. long, but also Long,
|
||||||
* String..=> built-in types) and compound types (your own).
|
* String..=> built-in types) and compound types (your own).
|
||||||
* Common ancestor primarily to iterator over properties of any type.
|
* Common ancestor primarily to iterator over properties of any type.
|
||||||
* The respective functions are completely different though, and we need `instanceof` to check for the
|
* The respective functions are completely different though, and we need `instanceof` to check for the
|
||||||
|
|
@ -11,8 +11,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
*/
|
*/
|
||||||
public abstract class TypeHandler {
|
public abstract class TypeHandler {
|
||||||
|
|
||||||
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
|
protected MetaMethod getter; // both can be null, if it's for a known ('primitive') type
|
||||||
protected MethodHandle setter;
|
protected MetaMethod setter;
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -20,26 +20,26 @@ public abstract class TypeHandler {
|
||||||
*/
|
*/
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public TypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
public TypeHandler(Class<?> type, String name, MetaMethod getter, MetaMethod setter) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGetter(MethodHandle getter) {
|
void setGetter(MetaMethod getter) {
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodHandle getGetter() {
|
public MetaMethod getGetter() {
|
||||||
return getter;
|
return getter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodHandle getSetter() {
|
public MetaMethod getSetter() {
|
||||||
return setter;
|
return setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSetter(MethodHandle setter) {
|
void setSetter(MetaMethod setter) {
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
* the layout is SQLite-like type:Varint, value byte[]
|
* the layout is SQLite-like type:Varint, value byte[]
|
||||||
* Varint: byte[]
|
* Varint: byte[]
|
||||||
*/
|
*/
|
||||||
class ValueReader {
|
public class ValueReader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a value from the buffer.
|
* Reads a value from the buffer.
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ import java.nio.ByteBuffer;
|
||||||
* Writes integers to byte representation like Sqlite's putVarint64
|
* Writes integers to byte representation like Sqlite's putVarint64
|
||||||
* not threadsafe (take out B8 and B9 if you need that)
|
* not threadsafe (take out B8 and B9 if you need that)
|
||||||
*/
|
*/
|
||||||
final class Varint {
|
public final class Varint {
|
||||||
|
|
||||||
private Varint() {
|
private Varint() {
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
package com.github.shautvast.contiguous.asm;
|
||||||
|
|
||||||
|
import com.github.shautvast.contiguous.ValueReader;
|
||||||
|
import com.github.shautvast.contiguous.Varint;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class AsmContiguousList<E> {
|
||||||
|
|
||||||
|
private static final byte[] DOUBLE_TYPE = {7};
|
||||||
|
private static final byte[] FLOAT_TYPE = {10}; // not in line with SQLite anymore
|
||||||
|
private static final int STRING_OFFSET = 13;
|
||||||
|
private static final int BYTES_OFFSET = 12; // blob TODO decide if include
|
||||||
|
public static final int MAX_24BITS = 8388607;
|
||||||
|
public static final long MAX_48BITS = 140737488355327L;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* storage for dehydrated objects
|
||||||
|
*/
|
||||||
|
private ByteBuffer data = ByteBuffer.allocate(4096);//TODO create constructor with capacity
|
||||||
|
|
||||||
|
private int bufferPosition;
|
||||||
|
|
||||||
|
private final ArrayList<Integer> elementIndices = new ArrayList<>();
|
||||||
|
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
private final AsmTypeHandler<?> rootHandler;
|
||||||
|
// private static final Map<Class<?>, TypeHandler> TYPE_HANDLERS = new HashMap<>();
|
||||||
|
|
||||||
|
public AsmContiguousList(Class<E> elementType) {
|
||||||
|
this.rootHandler = new StringHandler();
|
||||||
|
elementIndices.add(0); // index of first element
|
||||||
|
bufferPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(E element) {
|
||||||
|
if (element == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
storePropertyData(element, rootHandler);
|
||||||
|
extend();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public E get(int index) {
|
||||||
|
checkbounds(index);
|
||||||
|
data.position(elementIndices.get(index));
|
||||||
|
Object read = ValueReader.read(data);
|
||||||
|
return (E) rootHandler.cast(read);
|
||||||
|
// create a new instance of the list element type
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAsJson(int index) {
|
||||||
|
checkbounds(index);
|
||||||
|
data.position(elementIndices.get(index));
|
||||||
|
if (rootHandler instanceof BuiltinHandler<?>) {
|
||||||
|
return getValue(rootHandler);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkbounds(int index) {
|
||||||
|
if (index < 0 || index >= size) {
|
||||||
|
throw new IndexOutOfBoundsException("index <0 or >" + size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValue(AsmTypeHandler<?> handler) {
|
||||||
|
String value = String.valueOf(ValueReader.read(data));
|
||||||
|
if (handler instanceof BuiltinHandler<?>) {
|
||||||
|
return quote(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storePropertyData(Object element, AsmTypeHandler<?> typeHandler) {
|
||||||
|
if (typeHandler instanceof BuiltinHandler<?>) {
|
||||||
|
typeHandler.storePropertyValue(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String quote(String out) {
|
||||||
|
out = "\"" + out + "\"";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void store(byte[] bytes) {
|
||||||
|
ensureFree(bytes.length);
|
||||||
|
data.position(bufferPosition); // ensures intermittent reads/writes are safe
|
||||||
|
data.put(bytes);
|
||||||
|
bufferPosition += bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void store0() {
|
||||||
|
ensureFree(1);
|
||||||
|
data.put((byte) 0);
|
||||||
|
bufferPosition += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeString(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
store0();
|
||||||
|
} else {
|
||||||
|
byte[] utf = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
store(Varint.write(((long) (utf.length) << 1) + STRING_OFFSET));
|
||||||
|
store(utf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureFree(int length) {
|
||||||
|
while (bufferPosition + length > data.capacity()) {
|
||||||
|
ByteBuffer bytes = this.data;
|
||||||
|
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
|
||||||
|
this.data.put(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void extend() {
|
||||||
|
size += 1;
|
||||||
|
// keep track of index of element in data
|
||||||
|
elementIndices.add(bufferPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
class StringHandler extends BuiltinHandler<String> {
|
||||||
|
@Override
|
||||||
|
protected String getValue(Object instance) {
|
||||||
|
return instance.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void store(String value){
|
||||||
|
storeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.github.shautvast.contiguous.asm;
|
||||||
|
|
||||||
|
public abstract class AsmTypeHandler<T> {
|
||||||
|
public Object cast(Object value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storePropertyValue(Object instance) {
|
||||||
|
T propertyValue = getValue(instance);
|
||||||
|
store(propertyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T getValue(Object instance);
|
||||||
|
|
||||||
|
public abstract void store(T value);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.github.shautvast.contiguous.asm;
|
||||||
|
|
||||||
|
public abstract class BuiltinHandler<T> extends AsmTypeHandler<T> {
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class ByteBean {
|
public class ByteBean {
|
||||||
byte value;
|
byte value;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -74,7 +74,6 @@ public class ContiguousListTest {
|
||||||
|
|
||||||
assertArrayEquals(new byte[]{1, 42},
|
assertArrayEquals(new byte[]{1, 42},
|
||||||
beanList.getData());
|
beanList.getData());
|
||||||
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -84,7 +83,6 @@ public class ContiguousListTest {
|
||||||
|
|
||||||
assertArrayEquals(new byte[]{1, -42},
|
assertArrayEquals(new byte[]{1, -42},
|
||||||
beanList.getData());
|
beanList.getData());
|
||||||
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -206,7 +204,7 @@ public class ContiguousListTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetterIterator() {
|
void testSetterIterator() {
|
||||||
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
||||||
ContiguousList<NestedBean>.SetterIterator iterator = integers.setterIterator();
|
ContiguousList<NestedBean>.SetterIterator iterator = integers.setterIterator();
|
||||||
|
|
||||||
|
|
@ -222,4 +220,17 @@ public class ContiguousListTest {
|
||||||
assertEquals("Magrathea", nestedBean.getStringBean().getName());
|
assertEquals("Magrathea", nestedBean.getStringBean().getName());
|
||||||
assertEquals(42, nestedBean.getIntBean().getValue());
|
assertEquals(42, nestedBean.getIntBean().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLargeAllocations(){
|
||||||
|
ContiguousList<String> strings = new ContiguousList<>(String.class);
|
||||||
|
for (int i=0; i<1000; i++){
|
||||||
|
strings.add("...................");
|
||||||
|
}
|
||||||
|
|
||||||
|
ContiguousList<String> strings3 = new ContiguousList<>(String.class);
|
||||||
|
for (int i=0; i<1000; i++){
|
||||||
|
strings3.add("...................");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class DoubleBean {
|
public class DoubleBean {
|
||||||
private Double value;
|
private Double value;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class FloatBean {
|
public class FloatBean {
|
||||||
private Float value;
|
private Float value;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class IntBean {
|
public class IntBean {
|
||||||
private int value;
|
private int value;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class LongBean {
|
public class LongBean {
|
||||||
private long value;
|
private long value;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
|
public class NestedBeanHandler extends CompoundTypeHandler{
|
||||||
|
NestedBeanHandler(Class<NestedBean> type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedBeanHandler(Class<?> type, String propertyName) {
|
||||||
|
super(type, propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
class ShortBean {
|
public class ShortBean {
|
||||||
private short value;
|
private short value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package com.github.shautvast.contiguous;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
package com.github.shautvast.contiguous.asm;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class AsmContiguousListTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAndGetString() {
|
||||||
|
AsmContiguousList<String> list = new AsmContiguousList<>(String.class);
|
||||||
|
assertTrue(list.isEmpty());
|
||||||
|
|
||||||
|
list.add("hitchhikersguide to the galaxy");
|
||||||
|
assertFalse(list.isEmpty());
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
|
||||||
|
list.add("the publishing houses of Ursa Minor");
|
||||||
|
assertFalse(list.isEmpty());
|
||||||
|
assertEquals(2, list.size());
|
||||||
|
|
||||||
|
String title = list.get(0);
|
||||||
|
assertEquals("hitchhikersguide to the galaxy", title);
|
||||||
|
|
||||||
|
String titleJson = list.getAsJson(0);
|
||||||
|
assertEquals("\"hitchhikersguide to the galaxy\"", titleJson);
|
||||||
|
|
||||||
|
String publisher = list.get(1);
|
||||||
|
assertEquals("the publishing houses of Ursa Minor", publisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testStringBean() {
|
||||||
|
// ContiguousList<StringBean> beanList = new ContiguousList<>(StringBean.class);
|
||||||
|
// beanList.add(new StringBean("Douglas Adams"));
|
||||||
|
//
|
||||||
|
// assertArrayEquals(new byte[]{39, 68, 111, 117, 103, 108, 97, 115, 32, 65, 100, 97, 109, 115}, beanList.getData());
|
||||||
|
//
|
||||||
|
// StringBean douglas = beanList.get(0);
|
||||||
|
// assertEquals("Douglas Adams", douglas.getName());
|
||||||
|
//
|
||||||
|
// String douglasJson = beanList.getAsJson(0);
|
||||||
|
// assertEquals("{\"name\": \"Douglas Adams\"}", douglasJson);
|
||||||
|
//
|
||||||
|
// // now add new data to see if existing data remains intact
|
||||||
|
// beanList.add(new StringBean("Ford Prefect"));
|
||||||
|
//
|
||||||
|
// assertEquals("Douglas Adams", beanList.get(0).getName());
|
||||||
|
// assertEquals("Ford Prefect", beanList.get(1).getName());
|
||||||
|
//
|
||||||
|
// assertEquals(2, beanList.size());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testIntBean() {
|
||||||
|
// ContiguousList<IntBean> beanList = new ContiguousList<>(IntBean.class);
|
||||||
|
// beanList.add(new IntBean(42));
|
||||||
|
//
|
||||||
|
// assertArrayEquals(new byte[]{1, 42},
|
||||||
|
// beanList.getData());
|
||||||
|
// assertEquals(42, beanList.get(0).getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testLong() {
|
||||||
|
// ContiguousList<LongBean> beanList = new ContiguousList<>(LongBean.class);
|
||||||
|
// beanList.add(new LongBean(42));
|
||||||
|
//
|
||||||
|
// assertArrayEquals(new byte[]{1, 42},
|
||||||
|
// beanList.getData());
|
||||||
|
// assertEquals(42, beanList.get(0).getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testShort() {
|
||||||
|
// ContiguousList<ShortBean> beanList = new ContiguousList<>(ShortBean.class);
|
||||||
|
// beanList.add(new ShortBean((short) 42));
|
||||||
|
//
|
||||||
|
// assertArrayEquals(new byte[]{1, 42},
|
||||||
|
// beanList.getData());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testByte() {
|
||||||
|
// ContiguousList<ByteBean> beanList = new ContiguousList<>(ByteBean.class);
|
||||||
|
// beanList.add(new ByteBean((byte) -42));
|
||||||
|
//
|
||||||
|
// assertArrayEquals(new byte[]{1, -42},
|
||||||
|
// beanList.getData());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testNestedBean() {
|
||||||
|
// ContiguousList<NestedBean> beanList = new ContiguousList<>(NestedBean.class);
|
||||||
|
// beanList.add(new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42)));
|
||||||
|
//
|
||||||
|
// NestedBean expected = new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42));
|
||||||
|
// assertEquals(expected, beanList.get(0));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testFloat() {
|
||||||
|
// ContiguousList<FloatBean> beanList = new ContiguousList<>(FloatBean.class);
|
||||||
|
// beanList.add(new FloatBean(1.1F));
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// assertEquals(1.1F, beanList.get(0).getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testDouble() {
|
||||||
|
// ContiguousList<DoubleBean> beanList = new ContiguousList<>(DoubleBean.class);
|
||||||
|
// beanList.add(new DoubleBean(1.1));
|
||||||
|
//
|
||||||
|
// assertEquals(1.1, beanList.get(0).getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testNullFloat() {
|
||||||
|
// ContiguousList<FloatBean> beanList = new ContiguousList<>(FloatBean.class);
|
||||||
|
// beanList.add(new FloatBean(null));
|
||||||
|
//
|
||||||
|
// assertNull(beanList.get(0).getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testNullString() {
|
||||||
|
// ContiguousList<StringBean> beanList = new ContiguousList<>(StringBean.class);
|
||||||
|
// beanList.add(new StringBean(null));
|
||||||
|
//
|
||||||
|
// assertNull(beanList.get(0).getName());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void test100Elements() {
|
||||||
|
// ContiguousList<StringBean> beanList = new ContiguousList<>(StringBean.class);
|
||||||
|
// for (int i = 0; i < 100; i++) {
|
||||||
|
// beanList.add(new StringBean(null));
|
||||||
|
// }
|
||||||
|
// assertEquals(100, beanList.size());
|
||||||
|
// for (int i = 0; i < 100; i++) {
|
||||||
|
// assertNull(beanList.get(i).getName());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testBigInteger() {
|
||||||
|
// ContiguousList<BigInteger> bigIntegers = new ContiguousList<>(BigInteger.class);
|
||||||
|
// bigIntegers.add(new BigInteger("1000000000"));
|
||||||
|
// assertEquals(1_000_000_000L, bigIntegers.get(0).longValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testIterator() {
|
||||||
|
// ContiguousList<Integer> integers = new ContiguousList<>(Integer.class);
|
||||||
|
// for (int i = 0; i < 100; i++) {
|
||||||
|
// integers.add(i);
|
||||||
|
// }
|
||||||
|
// int prevValue = -1;
|
||||||
|
// for (int value : integers) {
|
||||||
|
// assertEquals(prevValue, value - 1);
|
||||||
|
// prevValue = value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// integers.add(100);
|
||||||
|
//
|
||||||
|
// assertEquals(100, integers.get(100));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testPrimitiveIterator() {
|
||||||
|
// ContiguousList<Integer> integers = new ContiguousList<>(Integer.class);
|
||||||
|
// for (int i = 0; i < 100; i++) {
|
||||||
|
// integers.add(i);
|
||||||
|
// }
|
||||||
|
// long prevValue = -1;
|
||||||
|
// for (Iterator<?> intIter = integers.valueIterator(); intIter.hasNext(); ) {
|
||||||
|
// int value = (int) intIter.next();
|
||||||
|
// assertEquals(prevValue, value - 1);
|
||||||
|
// prevValue = value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// integers.add(100);
|
||||||
|
//
|
||||||
|
// assertEquals(100, integers.get(100));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testCompoundValueIterator() {
|
||||||
|
// ContiguousList<IntBean> integers = new ContiguousList<>(IntBean.class);
|
||||||
|
// for (int i = 0; i < 100; i++) {
|
||||||
|
// integers.add(new IntBean(i));
|
||||||
|
// }
|
||||||
|
// long prevValue = -1;
|
||||||
|
// for (Iterator<?> intIter = integers.valueIterator(); intIter.hasNext(); ) {
|
||||||
|
// int value = (int) intIter.next();
|
||||||
|
// assertEquals(prevValue, value - 1);
|
||||||
|
// prevValue = value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// integers.add(new IntBean(100));
|
||||||
|
//
|
||||||
|
// assertEquals(new IntBean(100), integers.get(100)); // here an instance
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testSetterIterator() {
|
||||||
|
// ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
||||||
|
// ContiguousList<NestedBean>.SetterIterator iterator = integers.setterIterator();
|
||||||
|
//
|
||||||
|
// if (iterator.hasNext()) {
|
||||||
|
// iterator.next().set("Magrathea");
|
||||||
|
// }
|
||||||
|
// if (iterator.hasNext()) {
|
||||||
|
// iterator.next().set(42);
|
||||||
|
// }
|
||||||
|
// iterator.finishObject();
|
||||||
|
//
|
||||||
|
// NestedBean nestedBean = integers.get(0);
|
||||||
|
// assertEquals("Magrathea", nestedBean.getStringBean().getName());
|
||||||
|
// assertEquals(42, nestedBean.getIntBean().getValue());
|
||||||
|
// }
|
||||||
|
}
|
||||||
3
pom.xml
3
pom.xml
|
|
@ -3,7 +3,7 @@
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>com.github.shautvast</groupId>
|
||||||
<artifactId>contiguous-pom</artifactId>
|
<artifactId>contiguous-pom</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
<module>demo</module>
|
<module>demo</module>
|
||||||
<module>jdbc</module>
|
<module>jdbc</module>
|
||||||
<module>jackson</module>
|
<module>jackson</module>
|
||||||
|
<module>benchmark</module>
|
||||||
</modules>
|
</modules>
|
||||||
<name>contiguous</name>
|
<name>contiguous</name>
|
||||||
<description>contiguous storage for java</description>
|
<description>contiguous storage for java</description>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue