All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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