
io.permazen.core.SetField Maven / Gradle / Ivy
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package io.permazen.core;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import io.permazen.core.util.ObjIdMap;
import io.permazen.util.ByteReader;
import io.permazen.util.ByteWriter;
import io.permazen.util.CloseableIterator;
import java.util.NavigableSet;
import java.util.TreeSet;
/**
* Set field.
*
* @param Java type for the set elements
*/
public class SetField extends CollectionField, E> {
/**
* Constructor.
*
* @param name the name of the field
* @param storageId field content storage ID
* @param schema schema version
* @param elementField this field's element sub-field
* @throws IllegalArgumentException if any parameter is null
* @throws IllegalArgumentException if {@code storageId} is non-positive
*/
@SuppressWarnings("serial")
SetField(String name, int storageId, Schema schema, SimpleField elementField) {
super(name, storageId, schema, new TypeToken>() { }
.where(new TypeParameter() { }, elementField.typeToken.wrap()), elementField);
}
// Public methods
@Override
@SuppressWarnings("unchecked")
public NavigableSet getValue(Transaction tx, ObjId id) {
Preconditions.checkArgument(tx != null, "null tx");
return (NavigableSet)tx.readSetField(id, this.storageId, false);
}
@Override
public R visit(FieldSwitch target) {
return target.caseSetField(this);
}
@Override
public String toString() {
return "set field `" + this.name + "' containing " + this.elementField;
}
// Non-public methods
@Override
NavigableSet getValueInternal(Transaction tx, ObjId id) {
return new JSSet<>(tx, this, id);
}
@Override
NavigableSet getValueReadOnlyCopy(Transaction tx, ObjId id) {
return Sets.unmodifiableNavigableSet(new TreeSet(this.getValueInternal(tx, id)));
}
@Override
SetElementStorageInfo toStorageInfo(SimpleField> subField) {
assert subField == this.elementField;
return new SetElementStorageInfo<>(this);
}
@Override
void copy(ObjId srcId, ObjId dstId, Transaction srcTx, Transaction dstTx, ObjIdMap objectIdMap) {
final FieldType fieldType = this.elementField.fieldType;
final NavigableSet src = this.getValue(srcTx, srcId);
final NavigableSet dst = this.getValue(dstTx, dstId);
try (final CloseableIterator si = CloseableIterator.wrap(src.iterator());
final CloseableIterator di = CloseableIterator.wrap(dst.iterator())) {
// Check for empty
if (!si.hasNext()) {
dst.clear();
return;
}
// If we're not remapping anything, walk forward through both sets and synchronize dst to src
if (objectIdMap == null || objectIdMap.isEmpty() || !this.elementField.remapsObjectId()) {
if (!di.hasNext()) {
dst.addAll(src);
return;
}
E s = si.next();
E d = di.next();
while (true) {
final int diff = fieldType.compare(s, d);
boolean sadvance = true;
boolean dadvance = true;
if (diff < 0) {
dst.add(s);
dadvance = false;
} else if (diff > 0) {
di.remove();
sadvance = false;
}
if (sadvance) {
if (!si.hasNext()) {
dst.tailSet(s, false).clear();
return;
}
s = si.next();
}
if (dadvance) {
if (!di.hasNext()) {
dst.addAll(src.tailSet(s, true));
return;
}
d = di.next();
}
}
} else {
dst.clear();
while (si.hasNext())
dst.add(this.elementField.remapObjectId(objectIdMap, si.next()));
}
}
}
@Override
void buildIndexEntry(ObjId id, SimpleField> subField, ByteReader reader, byte[] value, ByteWriter writer) {
assert subField == this.elementField;
writer.write(reader);
id.writeTo(writer);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy