diff --git a/demo/pom.xml b/demo/pom.xml new file mode 100644 index 0000000..73685be --- /dev/null +++ b/demo/pom.xml @@ -0,0 +1,86 @@ + + + + nl.sanderhautvast + contiguous-demo + 1.1 + + 4.0.0 + + + 11 + 11 + UTF-8 + + + + + nl.sanderhautvast + contiguous + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + 2.7.12 + + + org.springframework.boot + spring-boot-starter-data-jdbc + 2.7.12 + + + org.projectlombok + lombok + 1.18.24 + + + org.postgresql + postgresql + 42.5.4 + runtime + + + + org.springframework.boot + spring-boot-starter-test + 2.7.12 + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.7.10 + + nl.sanderhautvast.contiguous.demo.DemoApplication + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + \ No newline at end of file diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java new file mode 100644 index 0000000..24d495c --- /dev/null +++ b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java @@ -0,0 +1,74 @@ +package nl.sanderhautvast.contiguous.demo; + +import lombok.extern.slf4j.Slf4j; +import nl.sanderhautvast.contiguous.demo.repository.RandomStuffGenerator; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.sql.DataSource; + +@Slf4j +@SpringBootApplication +public class DemoApplication { + @Value("${spring.datasource.url}") + private String url; + + @Value("${spring.datasource.driverClass}") + private String driverClass; + + @Value("${spring.datasource.username}") + private String username; + + @Value("${spring.datasource.password}") + private String password; + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + + @Bean + public CommandLineRunner commandLineRunner(ApplicationContext ctx) { + return args -> { + log.info("Loading the database with test data"); + JdbcTemplate jdbcTemplate = new JdbcTemplate(datasource()); + jdbcTemplate.execute("drop table if exists customers"); + jdbcTemplate.execute("create table customers (name varchar(100), email varchar(100), streetname varchar(100), housenumber integer, city varchar(100), country varchar(100))"); + final RandomStuffGenerator generator = new RandomStuffGenerator(); + for (int i = 0; i < 100_000; i++) { + jdbcTemplate.update("insert into customers (name, email, streetname, housenumber, city, country) values(?,?,?,?,?,?)", + ps -> { + String firstName = generator.generateFirstName(); + String lastName = generator.generateLastName(); + ps.setString(1, firstName + " " + lastName); + ps.setString(2, firstName + "." + lastName + "@icemail.com"); + ps.setString(3, generator.generateStreetName()); + ps.setInt(4, generator.generateSomeNumber()); + ps.setString(5, generator.generateSomeCityInIceland()); + ps.setString(6, generator.generateIceland()); + }); + } + log.info("Database loading finished successfully"); + }; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(datasource()); + } + + @Bean + public DataSource datasource() { + DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); + dataSourceBuilder.driverClassName(driverClass); + dataSourceBuilder.url(url); + dataSourceBuilder.username(username); + dataSourceBuilder.password(password); + return dataSourceBuilder.build(); + } +} diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java new file mode 100644 index 0000000..7c8bde2 --- /dev/null +++ b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java @@ -0,0 +1,15 @@ +package nl.sanderhautvast.contiguous.demo.model; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class Customer { + String name; + String email; + String streetname; + int housenumber; + String city; + String country; +} diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java new file mode 100644 index 0000000..20a15cb --- /dev/null +++ b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java @@ -0,0 +1,40 @@ +package nl.sanderhautvast.contiguous.demo.repository; + + +import lombok.extern.slf4j.Slf4j; +import nl.sanderhautvast.contiguous.ContiguousList; +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; + +@Repository +@Slf4j +public class CustomerRepository { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public CustomerRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public ContiguousList getAllCustomers() { + return jdbcTemplate.query("select * from customers limit 5", rs -> { + ContiguousList customers = new ContiguousList<>(Customer.class); + while (rs.next()) { + Customer customer = Customer.builder() + .name(rs.getString("name")) + .email(rs.getString("email")) + .streetname(rs.getString("streetname")) + .housenumber(rs.getInt("housenumber")) + .city(rs.getString("city")) + .country(rs.getString("country")) + .build(); + log.info("{}", customer); + customers.add(customer); + } + return customers; + }); + } +} diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java new file mode 100644 index 0000000..b7ad345 --- /dev/null +++ b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java @@ -0,0 +1,54 @@ +package nl.sanderhautvast.contiguous.demo.repository; + +import java.util.List; +import java.util.Random; + +public class RandomStuffGenerator { + + private final List 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 lastNameParts = List.of("fin", "wil", "cat", "loc", "der", "ter", "asp", "pen", "ill", "raf", "gut", "dax", "yin"); + private final List 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 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(); + } +} diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java new file mode 100644 index 0000000..f4fa1e2 --- /dev/null +++ b/demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java @@ -0,0 +1,35 @@ +package nl.sanderhautvast.contiguous.demo.rest; + +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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@Slf4j +public class DemoRestApi { + + private final CustomerRepository customerRepository; + + @Autowired + public DemoRestApi(CustomerRepository customerRepository) { + this.customerRepository = customerRepository; + } + + @GetMapping(value = "/api/customers", produces = "application/json") + public List getCustomers() { + try { + ContiguousList customers = customerRepository.getAllCustomers(); + log.info("customers {}", customers.size()); + return customers; + } catch (Exception e) { + log.error("Error", e); + throw new RuntimeException(e); + } + } +} diff --git a/demo/src/main/resources/application.properties b/demo/src/main/resources/application.properties new file mode 100644 index 0000000..03a223e --- /dev/null +++ b/demo/src/main/resources/application.properties @@ -0,0 +1,6 @@ +logging.level.org.springframework=ERROR +spring.jpa.hibernate.ddl-auto=none +spring.datasource.driverClass=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.username=postgres +spring.datasource.password=unsafe diff --git a/demo/start_demo.sh b/demo/start_demo.sh new file mode 100644 index 0000000..1594751 --- /dev/null +++ b/demo/start_demo.sh @@ -0,0 +1,4 @@ +docker stop postgres +docker rm postgres +docker run -d -p5432:5432 -e POSTGRES_PASSWORD=unsafe --name postgres postgres:latest +mvn -f pom.xml -DskipTests clean spring-boot:run & diff --git a/jackson/pom.xml b/jackson/pom.xml new file mode 100644 index 0000000..bf681a5 --- /dev/null +++ b/jackson/pom.xml @@ -0,0 +1,31 @@ + + + + nl.sanderhautvast + contiguous-jackson + 1.1 + + 4.0.0 + + + 11 + 11 + UTF-8 + + + + + nl.sanderhautvast + contiguous + 1.0-SNAPSHOT + + + com.fasterxml.jackson.core + jackson-databind + 2.15.1 + + + + \ No newline at end of file diff --git a/jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java b/jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java new file mode 100644 index 0000000..70de235 --- /dev/null +++ b/jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java @@ -0,0 +1,30 @@ +package nl.sanderhautvast.contiguous; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import java.io.IOException; + +public class ListSerializer extends StdSerializer> { + + public ListSerializer(Class> t) { + super(t); + } + + @Override + public void serialize( + ContiguousList value, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonProcessingException { + +// value. + +// jgen.writeStartObject(); +// jgen.writeNumberField("id", value.id); +// jgen.writeStringField("itemName", value.itemName); +// jgen.writeNumberField("owner", value.owner.id); +// jgen.writeEndObject(); + } +} + diff --git a/lib/pom.xml b/lib/pom.xml new file mode 100644 index 0000000..a2968a0 --- /dev/null +++ b/lib/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + nl.sanderhautvast + contiguous + Datastructures with contiguous storage + 1.0-SNAPSHOT + jar + + + 9 + 9 + UTF-8 + + + + org.junit.jupiter + junit-jupiter-engine + 5.8.2 + test + + + org.junit.jupiter + junit-jupiter-api + 5.8.2 + test + + + org.projectlombok + lombok + 1.18.26 + test + + + \ No newline at end of file diff --git a/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java similarity index 82% rename from src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java index 1641f72..e5f0578 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java @@ -5,9 +5,10 @@ import java.lang.invoke.MethodHandle; /** * Stores a byte value. */ -class ByteHandler extends PropertyHandler { +class ByteHandler extends PrimitiveType { + public ByteHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Byte.class, getter, setter); } @Override diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/CompoundType.java b/lib/src/main/java/nl/sanderhautvast/contiguous/CompoundType.java new file mode 100644 index 0000000..baabfc5 --- /dev/null +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/CompoundType.java @@ -0,0 +1,51 @@ +package nl.sanderhautvast.contiguous; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.*; + +class CompoundType extends Type { + private final Map properties = new LinkedHashMap<>(); + + private MethodHandle getter; + private MethodHandle setter; + + + CompoundType(Class type) { + super(type, null,null); + } + + void setGetter(MethodHandle getter) { + this.getter = getter; + } + + public MethodHandle getGetter() { + return getter; + } + + public MethodHandle getSetter() { + return setter; + } + + void setSetter(MethodHandle setter) { + this.setter = setter; + } + + public Class getType() { + return type; + } + + Collection getProperties() { + return properties.values(); + } + + void addHandler(String propertyName, PrimitiveType primitiveType) { + properties.put(propertyName, primitiveType); + } + + void addChild(Field property, CompoundType childCompoundType) { + this.properties.put(property.getName(), childCompoundType); + } + + +} diff --git a/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java b/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java similarity index 63% rename from src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java index 44b0532..53d18f7 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java @@ -9,7 +9,7 @@ import java.util.*; import java.util.function.UnaryOperator; /** - * Experimental List implementation + * Short for Contiguous Layout List, an Experimental List implementation * Behaves like an ArrayList in that it's resizable and indexed. * The difference is that it uses an efficiently dehydrated version of the object in a cpu cache friendly, contiguous storage in a bytearray, * without object instance overhead. @@ -46,21 +46,17 @@ public class ContiguousList implements List { */ private ByteBuffer data = ByteBuffer.allocate(32); - private int currentValueIndex; + private int currentElementIndex; - private int[] valueIndices = new int[10]; + private int[] elementIndices = new int[10]; private int size; - private final Class type; - - private final List propertyHandlers = new LinkedList<>(); + private Type type; public ContiguousList(Class type) { - this.type = type; - //have to make this recursive - inspectType(type, new ArrayList<>()); - valueIndices[0] = 0; + inspectType(type); + elementIndices[0] = currentElementIndex; // index of first element } /* @@ -71,58 +67,168 @@ public class ContiguousList implements List { * 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 type, List childGetters) { - try { - final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup()); - 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.isKnownType(fieldType)) { - PropertyHandler propertyHandler = PropertyHandlerFactory.forType(fieldType, getter, setter); - - // not empty if there has been recursion - if (!childGetters.isEmpty()) { - childGetters.forEach(propertyHandler::addChildGetter); - } - - propertyHandlers.add(propertyHandler); - } else { - // assume nested bean - childGetters.add(getter); - inspectType(fieldType, childGetters); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + private void inspectType(Class type) { + if (PropertyHandlerFactory.isKnownType(type)) { + this.type = PropertyHandlerFactory.forType(type); + } else { + CompoundType compoundType = new CompoundType(type); + this.type = compoundType; + try { + addPropertyHandlersForCompoundType(type, compoundType); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } } } + private void addPropertyHandlersForCompoundType(Class type, CompoundType parentCompoundType) throws IllegalAccessException { + final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup()); + 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.isKnownType(fieldType)) { + PrimitiveType primitiveType = PropertyHandlerFactory.forType(fieldType, getter, setter); + + parentCompoundType.addHandler(field.getName(), primitiveType); + } else { + CompoundType newParent = new CompoundType(fieldType); + newParent.setGetter(getter); + newParent.setSetter(setter); + parentCompoundType.addChild(field, newParent); + + addPropertyHandlersForCompoundType(fieldType, newParent); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + + @Override + @SuppressWarnings("Contract") + public boolean add(E element) { + if (element == null) { + return false; + } + getProperties(element, type); + size += 1; + + // keep track of where the objects are stored + if (elementIndices.length < size + 1) { + this.elementIndices = Arrays.copyOf(this.elementIndices, this.elementIndices.length * 2); + } + elementIndices[size] = currentElementIndex; + return true; + } + + private void getProperties(Object element, Type type) { + // passed type is primitive + if (type instanceof PrimitiveType) { + ((PrimitiveType) type).storePropertyValue(element, this); + } else { + // passed type is compund ie. has child properties + ((CompoundType)type).getProperties().forEach(property -> { + if (property instanceof PrimitiveType) { + // recurse once more -> property is stored + getProperties(element, property); + } else { + CompoundType child = ((CompoundType) property); + try { + Object result = child.getGetter().invoke(element); + getProperties(result, child); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + }); + } + } + + @Override + public boolean remove(Object o) { + throw new RuntimeException("Not yet implemented"); + } + + @Override + @SuppressWarnings("NullableProblems") + public boolean containsAll(Collection collection) { + throw new RuntimeException("Not yet implemented"); + } + + @Override + @SuppressWarnings("unchecked") + public E get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("index <0 or >" + size); + } + data.position(elementIndices[index]); + try { + if (type instanceof PrimitiveType) { + return (E) ValueReader.read(data); + } + // create a new instance of the list element type + E newInstance = (E) type.type.getDeclaredConstructor().newInstance(); + + // set the data + setProperties(newInstance, (CompoundType) type); + + return newInstance; + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + + private void setProperties(Object element, CompoundType compoundType) { + compoundType.getProperties().forEach(property -> { + if (property instanceof PrimitiveType) { + ((PrimitiveType) property).setValue(element, ValueReader.read(data)); + } else { + try { + CompoundType p = (CompoundType) property; + // create a new instance of the property + Object newInstance = p.getType().getDeclaredConstructor().newInstance(); + + // set it on the parent + p.getSetter().invokeWithArguments(element, newInstance); + + // recurse down + setProperties(newInstance, p); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + }); + } + public boolean addAll(Collection collection) { - for (E element: collection){ + for (E element : collection) { add(element); } return true; } + @Override + @SuppressWarnings("NullableProblems") public boolean addAll(int i, Collection collection) { throw new RuntimeException("Not yet implemented"); } @Override + @SuppressWarnings("NullableProblems") public boolean removeAll(Collection collection) { - throw new RuntimeException("Not yet implemented"); + throw new RuntimeException("Not implemented"); } @Override + @SuppressWarnings("NullableProblems") public boolean retainAll(Collection collection) { - throw new RuntimeException("Not yet implemented"); + throw new RuntimeException("Not implemented"); } @Override @@ -136,56 +242,10 @@ public class ContiguousList implements List { } public void clear() { - this.currentValueIndex = 0; + this.currentElementIndex = 0; this.size = 0; } - @Override - public boolean add(E element) { - if (element == null) { - return false; - } - propertyHandlers.forEach(appender -> appender.storeValue(element, this)); - size += 1; - - // keep track of where the objects are stored - if (size > valueIndices.length) { - this.valueIndices = Arrays.copyOf(this.valueIndices, this.valueIndices.length * 2); - } - valueIndices[size] = currentValueIndex; - return true; - } - - @Override - public boolean remove(Object o) { - throw new RuntimeException("Not yet implemented"); - } - - @Override - public boolean containsAll(Collection collection) { - throw new RuntimeException("Not yet implemented"); - } - - @SuppressWarnings("unchecked") - @Override - public E get(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException("index <0 or >" + size); - } - data.position(valueIndices[index]); - try { - E newInstance = (E) type.getDeclaredConstructor().newInstance(); - propertyHandlers.forEach(appender -> { - appender.setValue(newInstance, ValueReader.read(data)); - }); - - return newInstance; - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | - InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - @Override public E set(int i, E e) { throw new RuntimeException("Not implemented"); @@ -198,17 +258,17 @@ public class ContiguousList implements List { @Override public E remove(int i) { - throw new RuntimeException("Not yet implemented"); + throw new RuntimeException("Not implemented"); } @Override public int indexOf(Object o) { - throw new RuntimeException("Not yet implemented"); + throw new RuntimeException("Not implemented"); } @Override public int lastIndexOf(Object o) { - throw new RuntimeException("Not yet implemented"); + throw new RuntimeException("Not implemented"); } @Override @@ -247,7 +307,7 @@ public class ContiguousList implements List { @Override public Iterator iterator() { - return new Iter(); + return new Iter<>(); } @Override @@ -260,6 +320,7 @@ public class ContiguousList implements List { } @Override + @SuppressWarnings("unchecked") public T[] toArray(T[] ts) { if (size > ts.length) { return (T[]) toArray(); @@ -281,27 +342,28 @@ public class ContiguousList implements List { } @Override + @SuppressWarnings("unchecked") public F next() { return (F) get(curIndex++); } } private void store(byte[] bytes) { - ensureCapacity(bytes.length); - data.position(currentValueIndex); // ensures intermittent reads/writes + ensureFree(bytes.length); + data.position(currentElementIndex); // ensures intermittent reads/writes data.put(bytes); - currentValueIndex += bytes.length; + currentElementIndex += bytes.length; } - private void store(byte singlebyte) { - ensureCapacity(1); - data.put(singlebyte); - currentValueIndex += 1; + private void store0() { + ensureFree(1); + data.put((byte) 0); + currentElementIndex += 1; } void storeString(String value) { if (value == null) { - store(Varint.write(0)); + store0(); } else { byte[] utf = value.getBytes(StandardCharsets.UTF_8); store(Varint.write(((long) (utf.length) << 1) + STRING_OFFSET)); @@ -311,7 +373,7 @@ public class ContiguousList implements List { void storeLong(Long value) { if (value == null) { - store((byte) 0); + store0(); } else { byte[] valueAsBytes = getValueAsBytes(value); store(getIntegerType(value, valueAsBytes.length)); @@ -321,7 +383,7 @@ public class ContiguousList implements List { void storeInteger(Integer value) { if (value == null) { - store((byte) 0); + store0(); } else { byte[] valueAsBytes = getValueAsBytes(value); store(getIntegerType(value, valueAsBytes.length)); @@ -331,7 +393,17 @@ public class ContiguousList implements List { void storeByte(Byte value) { if (value == null) { - store((byte) 0); + store0(); + } else { + byte[] valueAsBytes = getValueAsBytes(value); + store(getIntegerType(value, valueAsBytes.length)); + store(valueAsBytes); + } + } + + void storeShort(Short value) { + if (value == null) { + store0(); } else { byte[] valueAsBytes = getValueAsBytes(value); store(getIntegerType(value, valueAsBytes.length)); @@ -341,7 +413,7 @@ public class ContiguousList implements List { void storeDouble(Double value) { if (value == null) { - store((byte) 0); + store0(); } else { store(DOUBLE_TYPE); store(ByteBuffer.wrap(new byte[8]).putDouble(0, value).array()); @@ -350,7 +422,7 @@ public class ContiguousList implements List { void storeFloat(Float value) { if (value == null) { - store((byte) 0); + store0(); } else { store(FLOAT_TYPE); store(ByteBuffer.wrap(new byte[4]).putFloat(0, value).array()); @@ -358,15 +430,15 @@ public class ContiguousList implements List { } byte[] getData() { - return Arrays.copyOfRange(data.array(), 0, currentValueIndex); + return Arrays.copyOfRange(data.array(), 0, currentElementIndex); } - int[] getValueIndices() { - return Arrays.copyOfRange(valueIndices, 0, size + 1); + int[] getElementIndices() { + return Arrays.copyOfRange(elementIndices, 0, size + 1); } - private void ensureCapacity(int length) { - while (currentValueIndex + length > data.capacity()) { + private void ensureFree(int length) { + while (currentElementIndex + length > data.capacity()) { byte[] bytes = this.data.array(); this.data = ByteBuffer.allocate(this.data.capacity() * 2); this.data.put(bytes); diff --git a/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java similarity index 75% rename from src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java index 9758688..2ee47dc 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java @@ -5,9 +5,9 @@ import java.lang.invoke.MethodHandle; /** * Stores a double value. */ -class DoubleHandler extends PropertyHandler { +class DoubleHandler extends PrimitiveType { public DoubleHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Double.class, getter, setter); } @Override diff --git a/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java similarity index 74% rename from src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java index f13a8da..c38bcfb 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java @@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -class FloatHandler extends PropertyHandler { +class FloatHandler extends PrimitiveType { public FloatHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Float.class, getter, setter); } @Override diff --git a/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java similarity index 61% rename from src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java index 396319f..3eb31a2 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java @@ -2,19 +2,14 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -class IntegerHandler extends PropertyHandler { +class IntegerHandler extends PrimitiveType { public IntegerHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Integer.class, getter, setter); } - /** - * TODO improve - * it's first extended to long (s64) and then stored with variable length. - * With a little more code for s64, s16 and s8 specifically we can avoid the lenghtening and shortening - */ @Override public void store(Integer value, ContiguousList list) { - list.storeInteger((Integer)value); + list.storeInteger(value); } /* diff --git a/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java similarity index 74% rename from src/main/java/nl/sanderhautvast/contiguous/LongHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java index 25f88ee..9f9dc4d 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java @@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -class LongHandler extends PropertyHandler { +class LongHandler extends PrimitiveType { public LongHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Long.class, getter, setter); } @Override diff --git a/src/main/java/nl/sanderhautvast/contiguous/PropertyHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java similarity index 62% rename from src/main/java/nl/sanderhautvast/contiguous/PropertyHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java index 557d87f..888ec28 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/PropertyHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java @@ -1,8 +1,6 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -import java.util.ArrayList; -import java.util.List; /* * Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage. @@ -13,10 +11,7 @@ import java.util.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 */ -public abstract class PropertyHandler { - - private final MethodHandle getter; - private final MethodHandle setter; +public abstract class PrimitiveType extends Type { /* * Apology: @@ -31,33 +26,33 @@ public abstract class PropertyHandler { * Ideally you'd do this only once per containing class. In the current implementation it's once per * property in the containing class. */ - private final List childGetters = new ArrayList<>(); +// private final List childGetters = new ArrayList<>(); - public PropertyHandler(MethodHandle getter, MethodHandle setter) { - this.getter = getter; - this.setter = setter; + public PrimitiveType(Class type, MethodHandle getter, MethodHandle setter) { + super(type, getter, setter); } /** * Subclasses call the appropriate store method on the ContiguousList * * @param value the value to store - * @param list where to store the value + * @param list where to store the value */ public abstract void store(T value, ContiguousList list); - void storeValue(T instance, ContiguousList typedList) { - store(getValue(instance), typedList); + void storePropertyValue(Object instance, ContiguousList typedList) { + T propertyValue = getValue(instance); + store(propertyValue, typedList); } - private T getValue(Object instance) { - Object objectToCall = instance; + private T getValue(Object propertyValue) { + // I don't trust this + if (getter == null) { + return (T) propertyValue; + } try { - for (MethodHandle childGetter:childGetters){ - objectToCall = childGetter.invoke(instance); - } - return (T)getter.invoke(objectToCall); + return (T) getter.invoke(propertyValue); } catch (Throwable e) { throw new IllegalStateException(e); } @@ -66,28 +61,19 @@ public abstract class PropertyHandler { /** * This is used when get() is called on the list. * As this will create a new instance of the type, it's property values need to be set. - * + *

* Can be overridden to do transformations on the value after it has been retrieved, but make sure * to call super.setValue() or the value won't be set. * * @param instance the created type - * @param value the value that has been read from ContiguousList storage + * @param value the value that has been read from ContiguousList storage */ - public void setValue(Object instance, Object value){ - Object objectToCall = instance; - + public void setValue(Object instance, Object value) { try { - for (MethodHandle childGetter:childGetters){ - objectToCall = childGetter.invoke(instance); - } - setter.invokeWithArguments(objectToCall, value); + setter.invokeWithArguments(instance, value); } catch (Throwable e) { throw new IllegalStateException(e); } - } - void addChildGetter(MethodHandle childGetter){ - childGetters.add(childGetter); - } } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java b/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java new file mode 100644 index 0000000..de946bc --- /dev/null +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java @@ -0,0 +1,58 @@ +package nl.sanderhautvast.contiguous; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +/* + * Maps the propertyvalue type to a PropertyHandler + */ +final class PropertyHandlerFactory { + private static final Map, Class>> STANDARD_HANDLERS = new HashMap<>(); + + private PropertyHandlerFactory() { + } + + static { + STANDARD_HANDLERS.put(String.class, StringHandler.class); + STANDARD_HANDLERS.put(byte.class, ByteHandler.class); + STANDARD_HANDLERS.put(Byte.class, ByteHandler.class); + STANDARD_HANDLERS.put(int.class, IntegerHandler.class); + STANDARD_HANDLERS.put(Integer.class, IntegerHandler.class); + STANDARD_HANDLERS.put(short.class, ShortHandler.class); + STANDARD_HANDLERS.put(Short.class, ShortHandler.class); + STANDARD_HANDLERS.put(long.class, LongHandler.class); + STANDARD_HANDLERS.put(Long.class, LongHandler.class); + STANDARD_HANDLERS.put(float.class, FloatHandler.class); + STANDARD_HANDLERS.put(Float.class, FloatHandler.class); + STANDARD_HANDLERS.put(double.class, DoubleHandler.class); + STANDARD_HANDLERS.put(Double.class, DoubleHandler.class); + //Date/Timestamp + //LocalDate/time + //BigDecimal + //BigInteger + } + + public static boolean isKnownType(Class type) { + return STANDARD_HANDLERS.containsKey(type); + } + + public static PrimitiveType forType(Class type, MethodHandle getter, MethodHandle setter) { + try { + Class> appenderClass = STANDARD_HANDLERS.get(type); + if (appenderClass == null) { + throw new IllegalStateException("No Handler for " + type.getName()); + } + return (PrimitiveType) appenderClass.getDeclaredConstructor(MethodHandle.class, MethodHandle.class) + .newInstance(getter, setter); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + + public static PrimitiveType forType(Class type) { + return forType(type, null, null); + } +} diff --git a/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java similarity index 71% rename from src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java index 8dd8ad7..1d80c4a 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java @@ -2,14 +2,14 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -class ShortHandler extends PropertyHandler { +class ShortHandler extends PrimitiveType { public ShortHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(Short.class, getter, setter); } @Override public void store(Short value, ContiguousList list) { - list.storeInteger(value == null ? null : value.intValue()); + list.storeShort(value); } @Override diff --git a/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java similarity index 73% rename from src/main/java/nl/sanderhautvast/contiguous/StringHandler.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java index 28988ac..0714c98 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java @@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -class StringHandler extends PropertyHandler { +class StringHandler extends PrimitiveType { public StringHandler(MethodHandle getter, MethodHandle setter) { - super(getter, setter); + super(String.class, getter, setter); } @Override diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java b/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java new file mode 100644 index 0000000..5a745e4 --- /dev/null +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java @@ -0,0 +1,19 @@ +package nl.sanderhautvast.contiguous; + +import java.lang.invoke.MethodHandle; + +/** + * ok, sorry + */ +public abstract class Type { + + protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type + protected MethodHandle setter; + protected Class type; + + public Type(Class type, MethodHandle getter, MethodHandle setter) { + this.type = type; + this.getter = getter; + this.setter = setter; + } +} diff --git a/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java b/lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java similarity index 70% rename from src/main/java/nl/sanderhautvast/contiguous/ValueReader.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java index 1a58f33..9d051a7 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java @@ -1,7 +1,6 @@ package nl.sanderhautvast.contiguous; import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /* @@ -20,7 +19,7 @@ class ValueReader { */ public static Object read(ByteBuffer buffer) { long type = Varint.read(buffer); - return read(buffer, type, StandardCharsets.UTF_8); + return read(buffer, type); } /** @@ -28,11 +27,10 @@ class ValueReader { * * @param buffer Bytebuffer containing the storage. * @param columnType type representation borrowed from SQLite - * @param charset database charset * * @return the value implementation */ - private static Object read(ByteBuffer buffer, long columnType, Charset charset) { + private static Object read(ByteBuffer buffer, long columnType) { if (columnType == 0) { return null; } else if (columnType < 6L) { @@ -54,7 +52,7 @@ class ValueReader { } else if (columnType >= 13) { byte[] bytes = new byte[getvalueLengthForType(columnType)]; buffer.get(bytes); - return new String(bytes, charset); + return new String(bytes, StandardCharsets.UTF_8); } else throw new IllegalStateException("unknown column type" + columnType); } @@ -79,47 +77,6 @@ class ValueReader { } } - static int getLengthOfByteEncoding(long value) { - long u; - if (value < 0) { - u = ~value; - } else { - u = value; - } - if (u <= 127) { - return 1; - } else if (u <= 32767) { - return 2; - } else if (u <= 8388607) { - return 3; - } else if (u <= 2147483647) { - return 4; - } else if (u <= 140737488355327L) { - return 6; - } else { - return 8; - } - } - - public static byte[] getValueAsBytes(long value) { - if (value == 0) { - return new byte[0]; - } else if (value == 1) { - return new byte[0]; - } else { - return longToBytes(value, getLengthOfByteEncoding(value)); - } - } - - public static byte[] longToBytes(long n, int nbytes) { - byte[] b = new byte[nbytes]; - for (int i = 0; i < nbytes; i++) { - b[i] = (byte) ((n >> (nbytes - i - 1) * 8) & 0xFF); - } - - return b; - } - public static long bytesToLong(final byte[] b) { long n = 0; for (int i = 0; i < b.length; i++) { diff --git a/src/main/java/nl/sanderhautvast/contiguous/Varint.java b/lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java similarity index 90% rename from src/main/java/nl/sanderhautvast/contiguous/Varint.java rename to lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java index 4517cbc..877082d 100644 --- a/src/main/java/nl/sanderhautvast/contiguous/Varint.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java @@ -40,15 +40,6 @@ final class Varint { } } - /* - * read a long value from a variable nr of bytes in varint format - * NB the end is encoded in the bytes, and the passed byte array may be bigger, but the - * remainder is not read. It's up to the caller to do it right. - */ - public static long read(byte[] bytes) { - return read(ByteBuffer.wrap(bytes)); - } - /* * read a long value from a variable nr of bytes in varint format * @@ -58,8 +49,6 @@ final class Varint { * * Does not have the issue that the read(byte[] bytes) method has. The nr of bytes read is determined * by the varint64 format. - * - * TODO write specialized version for u32 */ public static long read(ByteBuffer buffer) { int SLOT_2_0 = 0x001fc07f; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java new file mode 100644 index 0000000..093a911 --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java @@ -0,0 +1,12 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class ByteBean { + byte value; +} diff --git a/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java b/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java similarity index 72% rename from src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java rename to lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java index 8ed8d07..809dfb3 100644 --- a/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java @@ -2,11 +2,27 @@ package nl.sanderhautvast.contiguous; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.junit.jupiter.api.Assertions.*; public class ContiguousListTest { + @Test - public void testString() { + public void testAddAndGetString() { + List list = new ContiguousList<>(String.class); + assertTrue(list.isEmpty()); + + list.add("hitchhikersguide to the galaxy"); + assertFalse(list.isEmpty()); + assertEquals(1, list.size()); + + String title = list.get(0); + assertEquals("hitchhikersguide to the galaxy", title); + } + + @Test + public void testStringBean() { ContiguousList beanList = new ContiguousList<>(StringBean.class); beanList.add(new StringBean("Douglas Adams")); @@ -25,7 +41,7 @@ public class ContiguousListTest { } @Test - public void testInt() { + public void testIntBean() { ContiguousList beanList = new ContiguousList<>(IntBean.class); beanList.add(new IntBean(42)); @@ -51,7 +67,7 @@ public class ContiguousListTest { assertArrayEquals(new byte[]{1, 42}, beanList.getData()); - assertArrayEquals(new int[]{0, 2}, beanList.getValueIndices()); + assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices()); } @Test @@ -61,17 +77,16 @@ public class ContiguousListTest { assertArrayEquals(new byte[]{1, -42}, beanList.getData()); - assertArrayEquals(new int[]{0, 2}, beanList.getValueIndices()); + assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices()); } @Test public void testNestedBean() { ContiguousList beanList = new ContiguousList<>(NestedBean.class); - beanList.add(new NestedBean(new StringBean("42"))); + beanList.add(new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42))); - assertArrayEquals(new byte[]{17, 52, 50}, - beanList.getData()); - assertArrayEquals(new int[]{0, 3}, beanList.getValueIndices()); + NestedBean expected = new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42)); + assertEquals(expected, beanList.get(0)); } @Test @@ -106,4 +121,13 @@ public class ContiguousListTest { assertNull(beanList.get(0).getName()); } + + @Test + public void test100Elements() { + ContiguousList beanList = new ContiguousList<>(StringBean.class); + for (int i = 0; i < 100; i++) { + beanList.add(new StringBean(null)); + } + assertEquals(100, beanList.size()); + } } diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java new file mode 100644 index 0000000..2b4bcaf --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java @@ -0,0 +1,14 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class DoubleBean { + private Double value; + + +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java new file mode 100644 index 0000000..e70c3c3 --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java @@ -0,0 +1,12 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class FloatBean { + private Float value; +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java new file mode 100644 index 0000000..07c87b8 --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java @@ -0,0 +1,12 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class IntBean { + private int value; +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java new file mode 100644 index 0000000..fd08cfb --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java @@ -0,0 +1,12 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class LongBean { + private long value; +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java new file mode 100644 index 0000000..fb01307 --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java @@ -0,0 +1,13 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class NestedBean { + private StringBean stringBean; + private IntBean intBean; +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java new file mode 100644 index 0000000..76906fe --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java @@ -0,0 +1,13 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +class ShortBean { + private short value; + +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java b/lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java new file mode 100644 index 0000000..16b59ed --- /dev/null +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java @@ -0,0 +1,13 @@ +package nl.sanderhautvast.contiguous; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class StringBean { + private String name; +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5854c99..341903a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,25 +1,32 @@ - + 4.0.0 nl.sanderhautvast - contiguous - Datastructures with contiguous storage - 1.0-SNAPSHOT - + contiguous-pom + pom + 1.1 + + lib + demo + jackson + + contiguous + contiguous storage for java - 9 - 9 - UTF-8 + 9 - - - org.junit.jupiter - junit-jupiter - 5.8.2 - test - - - \ No newline at end of file + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 9 + + + + + diff --git a/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java b/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java deleted file mode 100644 index 852b514..0000000 --- a/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -package nl.sanderhautvast.contiguous; - -import java.lang.invoke.MethodHandle; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; - -/* - * Maps the propertyvalue type to a PropertyHandler - */ -final class PropertyHandlerFactory { - private static final Map, Class> APPENDERS = new HashMap<>(); - - private PropertyHandlerFactory() { - } - - static { - APPENDERS.put(String.class, StringHandler.class); - APPENDERS.put(byte.class, ByteHandler.class); - APPENDERS.put(Byte.class, ByteHandler.class); - APPENDERS.put(int.class, IntegerHandler.class); - APPENDERS.put(Integer.class, IntegerHandler.class); - APPENDERS.put(short.class, ShortHandler.class); - APPENDERS.put(Short.class, ShortHandler.class); - APPENDERS.put(long.class, LongHandler.class); - APPENDERS.put(Long.class, LongHandler.class); - APPENDERS.put(float.class, FloatHandler.class); - APPENDERS.put(Float.class, FloatHandler.class); - APPENDERS.put(double.class, DoubleHandler.class); - APPENDERS.put(Double.class, DoubleHandler.class); - //Date/Timestamp - //LocalDate/time - //BigDecimal - //BigInteger - } - - public static boolean isKnownType(Class type) { - return APPENDERS.containsKey(type); - } - - public static PropertyHandler forType(Class type, MethodHandle getter, MethodHandle setter) { - try { - Class appenderClass = APPENDERS.get(type); - if (appenderClass == null) { - throw new IllegalStateException("No ListAppender for " + type.getName()); - } - return appenderClass.getDeclaredConstructor(MethodHandle.class, MethodHandle.class) - .newInstance(getter, setter); - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | - InvocationTargetException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java b/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java deleted file mode 100644 index 5f4d254..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java +++ /dev/null @@ -1,13 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class ByteBean { - private byte value; - - ByteBean(byte value) { - this.value = value; - } - - public byte getValue() { - return value; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java b/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java deleted file mode 100644 index 48e482e..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java +++ /dev/null @@ -1,16 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class DoubleBean { - private Double value; - - public DoubleBean() { - } - - public DoubleBean(Double value) { - this.value = value; - } - - public Double getValue() { - return value; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java b/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java deleted file mode 100644 index 932447d..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java +++ /dev/null @@ -1,16 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class FloatBean { - private Float value; - - public FloatBean() { - } - - public FloatBean(Float value) { - this.value = value; - } - - public Float getValue() { - return value; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/IntBean.java b/src/test/java/nl/sanderhautvast/contiguous/IntBean.java deleted file mode 100644 index d630103..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/IntBean.java +++ /dev/null @@ -1,17 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class IntBean { - private int value; - - public IntBean(){ - - } - IntBean(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/LongBean.java b/src/test/java/nl/sanderhautvast/contiguous/LongBean.java deleted file mode 100644 index af1d850..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/LongBean.java +++ /dev/null @@ -1,17 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class LongBean { - private long value; - - public LongBean(){ - - } - - LongBean(long value) { - this.value = value; - } - - public long getValue() { - return value; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java b/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java deleted file mode 100644 index ceda051..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java +++ /dev/null @@ -1,20 +0,0 @@ -package nl.sanderhautvast.contiguous; - -public class NestedBean { - private StringBean stringBean; - - public NestedBean() { - } - - public NestedBean(StringBean stringBean) { - this.stringBean = stringBean; - } - - public StringBean getStringBean() { - return stringBean; - } - - public void setStringBean(StringBean stringBean) { - this.stringBean = stringBean; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java b/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java deleted file mode 100644 index cad746a..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java +++ /dev/null @@ -1,13 +0,0 @@ -package nl.sanderhautvast.contiguous; - -class ShortBean { - private short value; - - ShortBean(short value) { - this.value = value; - } - - public short getValue() { - return value; - } -} diff --git a/src/test/java/nl/sanderhautvast/contiguous/StringBean.java b/src/test/java/nl/sanderhautvast/contiguous/StringBean.java deleted file mode 100644 index ff1b0b8..0000000 --- a/src/test/java/nl/sanderhautvast/contiguous/StringBean.java +++ /dev/null @@ -1,20 +0,0 @@ -package nl.sanderhautvast.contiguous; - -public class StringBean { - private String name; - - public StringBean(){ - - } - public StringBean(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} \ No newline at end of file