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**
|
||||
|
||||
* 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)
|
||||
* needs jdk 9 (VarHandles)
|
||||
* 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
|
||||
* the code is working
|
||||
* 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">
|
||||
|
||||
<parent>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-pom</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
@ -21,12 +21,12 @@
|
|||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-jdbc</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-jackson</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
|
@ -66,7 +66,8 @@
|
|||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.7.12</version>
|
||||
<configuration>
|
||||
<mainClass>nl.sanderhautvast.contiguous.demo.DemoApplication</mainClass>
|
||||
<mainClass>com.github.shautvast.contiguous.demo.DemoApplication</mainClass>
|
||||
|
||||
</configuration>
|
||||
</plugin>
|
||||
</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.SimpleModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import nl.sanderhautvast.contiguous.ListSerializer;
|
||||
import nl.sanderhautvast.contiguous.demo.repository.RandomStuffGenerator;
|
||||
import com.github.shautvast.contiguous.ListSerializer;
|
||||
import com.github.shautvast.contiguous.demo.repository.RandomStuffGenerator;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
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.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 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.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
|
@ -29,7 +29,7 @@ public class CustomerRepository {
|
|||
}
|
||||
|
||||
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("streetname"), rs.getInt("housenumber"),
|
||||
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.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 nl.sanderhautvast.contiguous.ContiguousList;
|
||||
import nl.sanderhautvast.contiguous.demo.model.Customer;
|
||||
import nl.sanderhautvast.contiguous.demo.repository.CustomerRepository;
|
||||
import com.github.shautvast.contiguous.demo.model.Customer;
|
||||
import com.github.shautvast.contiguous.demo.repository.CustomerRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
|
@ -23,7 +23,12 @@ public class DemoRestApi {
|
|||
|
||||
@GetMapping(value = "/api/customers", produces = "application/json")
|
||||
public ContiguousList<Customer> getCustomers() {
|
||||
try {
|
||||
return customerRepository.getAllCustomers();
|
||||
} catch (Exception e) {
|
||||
log.error("",e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping(value = "/api/customers/traditional", produces = "application/json")
|
||||
|
|
@ -35,4 +40,5 @@ public class DemoRestApi {
|
|||
public List<Customer> getCustomersHybrid() {
|
||||
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">
|
||||
|
||||
<parent>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-pom</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
|
@ -7,9 +7,9 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
|||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ListSerializer<E> extends StdSerializer<ContiguousList<?>> {
|
||||
public class ListSerializer extends StdSerializer<ContiguousList<?>> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ListSerializer() {
|
||||
super((Class) ContiguousList.class); // ?
|
||||
}
|
||||
|
|
@ -22,10 +22,12 @@ public class ListSerializer<E> extends StdSerializer<ContiguousList<?>> {
|
|||
|
||||
Iterator<String> jsons = clist.jsonIterator();
|
||||
while (jsons.hasNext()) {
|
||||
generator.writeRawValue(jsons.next());
|
||||
String next = jsons.next();
|
||||
generator.writeRawValue(next);
|
||||
}
|
||||
|
||||
generator.writeEndArray();
|
||||
clist.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
public class AdamsObject {
|
||||
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.databind.ObjectMapper;
|
||||
|
|
@ -10,16 +10,16 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||
|
||||
class ListSerializerTest {
|
||||
|
||||
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
mapper = new ObjectMapper();
|
||||
final SimpleModule module = new SimpleModule("mySerializers");
|
||||
module.addSerializer(new ListSerializer<>());
|
||||
module.addSerializer(new ListSerializer());
|
||||
mapper.registerModule(module);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringList() throws JsonProcessingException {
|
||||
ContiguousList<String> strings = new ContiguousList<>(String.class);
|
||||
|
|
@ -42,7 +42,6 @@ class ListSerializerTest {
|
|||
strings.add(new AdamsObject("Publishing houses of Ursa Minor"));
|
||||
|
||||
|
||||
|
||||
String json = mapper.writeValueAsString(strings);
|
||||
assertEquals("[{\"name\": \"Vogon constructor fleet\"}," +
|
||||
"{\"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">
|
||||
|
||||
<parent>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-pom</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
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.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class JdbcResultsTest {
|
||||
|
||||
@Mock
|
||||
private ResultSet mockResults;
|
||||
|
||||
@Test
|
||||
public void testListOfString() throws SQLException {
|
||||
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||
when(mockResults.next()).thenReturn(true, false);
|
||||
when(mockResults.getObject(1)).thenReturn("Zaphod");
|
||||
|
||||
|
|
@ -36,6 +31,7 @@ class JdbcResultsTest {
|
|||
|
||||
@Test
|
||||
public void testListOfBean() throws SQLException {
|
||||
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||
when(mockResults.next()).thenReturn(true, false);
|
||||
// the shape of the result equals that of the result (name:String, age:int)
|
||||
when(mockResults.getObject("name")).thenReturn("Zaphod");
|
||||
|
|
@ -52,6 +48,7 @@ class JdbcResultsTest {
|
|||
|
||||
@Test
|
||||
public void testNameMapping() throws SQLException {
|
||||
ResultSet mockResults = Mockito.mock(ResultSet.class);
|
||||
when(mockResults.next()).thenReturn(true, false);
|
||||
when(mockResults.getObject("name")).thenReturn("Trillian");
|
||||
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.Data;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
|
@ -16,17 +16,17 @@
|
|||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||
<stringProp name="LoopController.loops">100</stringProp>
|
||||
<stringProp name="LoopController.loops">1000</stringProp>
|
||||
</elementProp>
|
||||
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
||||
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||
<stringProp name="ThreadGroup.num_threads">3</stringProp>
|
||||
<stringProp name="ThreadGroup.ramp_time">10</stringProp>
|
||||
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||
</ThreadGroup>
|
||||
<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">
|
||||
<collectionProp name="Arguments.arguments"/>
|
||||
</elementProp>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
<stringProp name="HTTPSampler.port">8080</stringProp>
|
||||
<stringProp name="HTTPSampler.protocol">http</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>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||
</HTTPSamplerProxy>
|
||||
<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">
|
||||
<collectionProp name="Arguments.arguments"/>
|
||||
</elementProp>
|
||||
|
|
@ -83,6 +83,49 @@
|
|||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||
</HTTPSamplerProxy>
|
||||
<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>
|
||||
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
|
||||
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||
|
|
|
|||
21
lib/pom.xml
21
lib/pom.xml
|
|
@ -5,22 +5,27 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-pom</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<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>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>9</maven.compiler.source>
|
||||
<maven.compiler.target>9</maven.compiler.target>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>reflective</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
|
@ -40,4 +45,12 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
</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>
|
||||
|
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -11,8 +11,8 @@ import java.lang.invoke.MethodHandle;
|
|||
* 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
|
||||
*/
|
||||
public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||
public BuiltinTypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||
abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||
public BuiltinTypeHandler(Class<?> type, String name, MetaMethod getter, MetaMethod setter) {
|
||||
super(type, name, getter, setter);
|
||||
}
|
||||
|
||||
|
|
@ -29,18 +29,19 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
|||
store(propertyValue, typedList);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
||||
store((T) value, contiguousList);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T getValue(Object propertyValue) {
|
||||
// I don't trust this
|
||||
if (getter == null) {
|
||||
return (T) propertyValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) getter.invoke(propertyValue);
|
||||
return (T) getter.invoke(propertyValue).unwrap();
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
|
@ -58,7 +59,7 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
|||
*/
|
||||
public void setValue(Object instance, Object value) {
|
||||
try {
|
||||
setter.invokeWithArguments(instance, cast(value));
|
||||
setter.invoke(instance, cast(value)).unwrap();
|
||||
} catch (Throwable 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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class CompoundTypeHandler extends TypeHandler {
|
||||
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.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
|
@ -56,22 +58,27 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
/*
|
||||
* 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 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??
|
||||
|
||||
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) {
|
||||
inspectType(type);
|
||||
this.rootHandler = inspectType(type);
|
||||
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
|
||||
*
|
||||
|
|
@ -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
|
||||
* object graph. It only knows the 'primitive' values.
|
||||
*/
|
||||
private void inspectType(Class<?> elementClass) {
|
||||
if (PropertyHandlerFactory.isBuiltInType(elementClass)) {
|
||||
this.rootHandler = PropertyHandlerFactory.forType(elementClass);
|
||||
} else {
|
||||
CompoundTypeHandler compoundType = new CompoundTypeHandler(elementClass);
|
||||
this.rootHandler = compoundType;
|
||||
try {
|
||||
addPropertyHandlersForCompoundType(elementClass, compoundType);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
private TypeHandler inspectType(Class<?> elementClass) {
|
||||
return TYPE_HANDLERS.computeIfAbsent(elementClass, k ->
|
||||
PropertyHandlerFactory.forType(elementClass)
|
||||
.orElseGet(() -> {
|
||||
TypeHandler compoundTypeHandler = new CompoundTypeHandler(elementClass);
|
||||
addPropertyHandlersForCompoundType(elementClass, (CompoundTypeHandler) compoundTypeHandler);
|
||||
return compoundTypeHandler;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* using reflection find all properties in the element, recursing down when the property is compound
|
||||
*/
|
||||
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundTypeHandler parentCompoundType) throws IllegalAccessException {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
|
||||
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundTypeHandler parentCompoundType) {
|
||||
MetaClass metaType = Reflective.getMetaClass(type);
|
||||
Arrays.stream(type.getDeclaredFields())
|
||||
.forEach(field -> {
|
||||
try {
|
||||
Class<?> fieldType = field.getType();
|
||||
MethodHandle getter = lookup.findGetter(type, field.getName(), fieldType);
|
||||
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
|
||||
|
||||
if (PropertyHandlerFactory.isBuiltInType(fieldType)) {
|
||||
BuiltinTypeHandler<?> primitiveType =
|
||||
PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
||||
String capitalized = capitalize(field.getName());
|
||||
MetaMethod getter = metaType.getMethod("get" + capitalized).get();
|
||||
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 {
|
||||
CompoundTypeHandler newParent = new CompoundTypeHandler(fieldType, field.getName());
|
||||
newParent.setGetter(getter);
|
||||
newParent.setSetter(setter);
|
||||
parentCompoundType.addChild(field, newParent);
|
||||
CompoundTypeHandler handler = new CompoundTypeHandler(fieldType, field.getName());
|
||||
handler.setGetter(getter);
|
||||
handler.setSetter(setter);
|
||||
parentCompoundType.addChild(field, handler);
|
||||
|
||||
addPropertyHandlersForCompoundType(fieldType, newParent);
|
||||
addPropertyHandlersForCompoundType(fieldType, handler);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
|
|
@ -153,7 +157,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
} else {
|
||||
CompoundTypeHandler child = ((CompoundTypeHandler) property);
|
||||
try {
|
||||
Object result = child.getGetter().invoke(element);
|
||||
Object result = child.getGetter().invoke(element).unwrap();
|
||||
storePropertyData(result, child);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
|
|
@ -205,7 +209,8 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
compoundType.getProperties().forEach(property -> {
|
||||
if (property instanceof BuiltinTypeHandler) {
|
||||
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
|
||||
type.setValue(element, ValueReader.read(data));
|
||||
Object readValue = ValueReader.read(data);
|
||||
type.setValue(element, readValue);
|
||||
} else {
|
||||
try {
|
||||
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
||||
|
|
@ -213,7 +218,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
Object newInstance = p.getType().getDeclaredConstructor().newInstance();
|
||||
|
||||
// set it on the parent
|
||||
p.getSetter().invokeWithArguments(element, newInstance);
|
||||
p.getSetter().invoke(element, newInstance);
|
||||
|
||||
// recurse down
|
||||
copyDataIntoNewObject(newInstance, p);
|
||||
|
|
@ -270,7 +275,6 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
}
|
||||
data.position(elementIndices.get(index));
|
||||
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
||||
|
||||
BuiltinTypeHandler<?> handler = (BuiltinTypeHandler<?>) rootHandler;
|
||||
return getValue(handler);
|
||||
}
|
||||
|
|
@ -280,22 +284,19 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
copyDataIntoStringBuilder(s, (CompoundTypeHandler) rootHandler);
|
||||
s.append("}");
|
||||
return s.toString();
|
||||
|
||||
}
|
||||
|
||||
private String getValue(BuiltinTypeHandler<?> handler) {
|
||||
Object read = ValueReader.read(data);
|
||||
String out = handler.cast(read).toString();
|
||||
String value = String.valueOf(ValueReader.read(data));
|
||||
if (handler instanceof StringHandler) {
|
||||
out = quote(out);
|
||||
return quote(value);
|
||||
}
|
||||
return out;
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String quote(String out) {
|
||||
StringBuilder s = new StringBuilder(out.length() + 2);
|
||||
out = s.append("\"").append(out).append("\"").toString();
|
||||
return out;
|
||||
return s.append("\"").append(out).append("\"").toString();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -305,8 +306,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
compoundType.getProperties().forEach(property -> {
|
||||
if (property instanceof BuiltinTypeHandler) {
|
||||
BuiltinTypeHandler<?> typeHandler = (BuiltinTypeHandler<?>) property;
|
||||
s.append(quote(typeHandler.getName()))
|
||||
.append(": ")
|
||||
s.append("\"")
|
||||
.append(typeHandler.getName())
|
||||
.append("\": ")
|
||||
.append(getValue(typeHandler));
|
||||
} else {
|
||||
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
||||
|
|
@ -608,8 +610,10 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
|
||||
private void ensureFree(int length) {
|
||||
while (bufferPosition + length > data.capacity()) {
|
||||
byte[] bytes = this.data.array();
|
||||
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
|
||||
ByteBuffer bytes = this.data;
|
||||
bytes.position(0);
|
||||
BufferCache.release(this.data);
|
||||
this.data = BufferCache.get((int) (bytes.capacity() * 1.5));
|
||||
this.data.put(bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -738,4 +742,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
|||
} 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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -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> {
|
||||
public FloatHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||
public FloatHandler(String propertyName, MetaMethod getter, MetaMethod 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> {
|
||||
public IntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||
public IntegerHandler(String propertyName, MetaMethod getter, MetaMethod 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> {
|
||||
public LongHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||
public LongHandler(String propertyName, MetaMethod getter, MetaMethod 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.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.
|
||||
*
|
||||
* @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.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/*
|
||||
* Maps the propertyvalue type to a PropertyHandler
|
||||
*/
|
||||
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() {
|
||||
}
|
||||
|
|
@ -35,27 +37,23 @@ final class PropertyHandlerFactory {
|
|||
register(BigDecimal.class, BigDecimalHandler.class);
|
||||
//Date/Timestamp
|
||||
//LocalDate/time
|
||||
|
||||
}
|
||||
|
||||
public static boolean isBuiltInType(Class<?> type) {
|
||||
return TYPE_HANDLERS.containsKey(type);
|
||||
}
|
||||
|
||||
public static <T> BuiltinTypeHandler<T> forType(Class<T> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Optional<TypeHandler> forType(Class<T> type, String name, MetaMethod getter, MetaMethod setter) {
|
||||
return Optional.ofNullable(BUILTIN.get(type)).map(appenderClass -> {
|
||||
try {
|
||||
Class<? extends BuiltinTypeHandler<?>> appenderClass = TYPE_HANDLERS.get(type);
|
||||
if (appenderClass == null) {
|
||||
throw new IllegalStateException("No Handler for " + type.getName());
|
||||
}
|
||||
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class)
|
||||
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MetaMethod.class, MetaMethod.class)
|
||||
.newInstance(name, getter, setter);
|
||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||
InvocationTargetException 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);
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +61,6 @@ final class PropertyHandlerFactory {
|
|||
* register a new TypeHandler that cannot be derived from bean properties
|
||||
*/
|
||||
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> {
|
||||
public ShortHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||
public ShortHandler(String propertyName, MetaMethod getter, MetaMethod 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> {
|
||||
public StringHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||
public StringHandler(String propertyName, MetaMethod getter, MetaMethod 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).
|
||||
* 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
|
||||
|
|
@ -11,8 +11,8 @@ import java.lang.invoke.MethodHandle;
|
|||
*/
|
||||
public abstract class TypeHandler {
|
||||
|
||||
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
|
||||
protected MethodHandle setter;
|
||||
protected MetaMethod getter; // both can be null, if it's for a known ('primitive') type
|
||||
protected MetaMethod setter;
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
|
|
@ -20,26 +20,26 @@ public abstract class TypeHandler {
|
|||
*/
|
||||
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.name = name;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
void setGetter(MethodHandle getter) {
|
||||
void setGetter(MetaMethod getter) {
|
||||
this.getter = getter;
|
||||
}
|
||||
|
||||
public MethodHandle getGetter() {
|
||||
public MetaMethod getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
public MethodHandle getSetter() {
|
||||
public MetaMethod getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
void setSetter(MethodHandle setter) {
|
||||
void setSetter(MetaMethod setter) {
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
|
@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
|
|||
* the layout is SQLite-like type:Varint, value byte[]
|
||||
* Varint: byte[]
|
||||
*/
|
||||
class ValueReader {
|
||||
public class ValueReader {
|
||||
|
||||
/**
|
||||
* Reads a value from the buffer.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ import java.nio.ByteBuffer;
|
|||
* Writes integers to byte representation like Sqlite's putVarint64
|
||||
* not threadsafe (take out B8 and B9 if you need that)
|
||||
*/
|
||||
final class Varint {
|
||||
public final class 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.Data;
|
||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class ByteBean {
|
||||
public class ByteBean {
|
||||
byte value;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -74,7 +74,6 @@ public class ContiguousListTest {
|
|||
|
||||
assertArrayEquals(new byte[]{1, 42},
|
||||
beanList.getData());
|
||||
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -84,7 +83,6 @@ public class ContiguousListTest {
|
|||
|
||||
assertArrayEquals(new byte[]{1, -42},
|
||||
beanList.getData());
|
||||
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -206,7 +204,7 @@ public class ContiguousListTest {
|
|||
|
||||
|
||||
@Test
|
||||
public void testSetterIterator() {
|
||||
void testSetterIterator() {
|
||||
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
||||
ContiguousList<NestedBean>.SetterIterator iterator = integers.setterIterator();
|
||||
|
||||
|
|
@ -222,4 +220,17 @@ public class ContiguousListTest {
|
|||
assertEquals("Magrathea", nestedBean.getStringBean().getName());
|
||||
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.Data;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
|
@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class DoubleBean {
|
||||
public class DoubleBean {
|
||||
private Double value;
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class FloatBean {
|
||||
public class FloatBean {
|
||||
private Float value;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class IntBean {
|
||||
public class IntBean {
|
||||
private int value;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
|
@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class LongBean {
|
||||
public class LongBean {
|
||||
private long value;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
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.Data;
|
||||
|
|
@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
|||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class ShortBean {
|
||||
public class ShortBean {
|
||||
private short value;
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sanderhautvast.contiguous;
|
||||
package com.github.shautvast.contiguous;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>nl.sanderhautvast</groupId>
|
||||
<groupId>com.github.shautvast</groupId>
|
||||
<artifactId>contiguous-pom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
<module>demo</module>
|
||||
<module>jdbc</module>
|
||||
<module>jackson</module>
|
||||
<module>benchmark</module>
|
||||
</modules>
|
||||
<name>contiguous</name>
|
||||
<description>contiguous storage for java</description>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue