BindingSetSerializer.java
/*******************************************************************************
* Copyright (c) 2023 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.collection.factory.mapdb;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.MutableBindingSet;
import org.mapdb.DataInput2;
import org.mapdb.DataOutput2;
import org.mapdb.Serializer;
import org.mapdb.serializer.SerializerBoolean;
import org.mapdb.serializer.SerializerIntegerPacked;
class BindingSetSerializer implements Serializer<BindingSet> {
// Insertion order is very important
private final LinkedHashSet<String> names = new LinkedHashSet<String>();
private final List<Predicate<BindingSet>> has = new ArrayList<>();
private final List<Function<BindingSet, Value>> get = new ArrayList<>();
private final List<BiConsumer<Value, MutableBindingSet>> set = new ArrayList<>();
private final Serializer<Value> vs;
private final SerializerBoolean sb = new SerializerBoolean();
private final SerializerIntegerPacked si = new SerializerIntegerPacked();
private final Supplier<MutableBindingSet> create;
private final Function<String, Predicate<BindingSet>> getHas;
private final Function<String, Function<BindingSet, Value>> getGet;
private final Function<String, BiConsumer<Value, MutableBindingSet>> getSet;
public BindingSetSerializer(Serializer<Value> valueSerializer, Supplier<MutableBindingSet> create,
Function<String, Predicate<BindingSet>> getHas, Function<String, Function<BindingSet, Value>> getGet,
Function<String, BiConsumer<Value, MutableBindingSet>> getSet) {
this.vs = valueSerializer;
this.create = create;
this.getHas = getHas;
this.getGet = getGet;
this.getSet = getSet;
}
@Override
public void serialize(DataOutput2 out, BindingSet bs) throws IOException {
final Set<String> bindingNames = bs.getBindingNames();
if (names.addAll(bindingNames)) {
// new name found
int i = has.size();
final Iterator<String> nameI = names.iterator();
// Don't get setters that we already got.
while (nameI.hasNext() && i > 0) {
i--;
}
while (nameI.hasNext()) {
String name = nameI.next();
has.add(getHas.apply(name));
get.add(getGet.apply(name));
set.add(getSet.apply(name));
}
}
// all binding names where present
for (int i = 0; i < has.size(); i++) {
if (has.get(i).test(bs)) {
sb.serialize(out, true);
si.serialize(out, i);
vs.serialize(out, get.get(i).apply(bs));
}
}
sb.serialize(out, false); // marks the end
}
@Override
public BindingSet deserialize(DataInput2 input, int available) throws IOException {
boolean hasMore = sb.deserialize(input, available);
MutableBindingSet bs = create.get();
while (hasMore) {
int nextName = si.deserialize(input, available);
Value nextValue = vs.deserialize(input, available);
set.get(nextName).accept(nextValue, bs);
hasMore = sb.deserialize(input, available);
}
return bs;
}
}