meyfa/scratchlib

View on GitHub
src/main/java/scratchlib/objects/fixed/collections/ScratchObjectAbstractDictionary.java

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
package scratchlib.objects.fixed.collections;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

import scratchlib.objects.IScratchReferenceType;
import scratchlib.objects.ScratchObject;
import scratchlib.objects.ScratchObjects;
import scratchlib.objects.ScratchOptionalField;
import scratchlib.objects.ScratchReferenceTable;
import scratchlib.project.ScratchProject;
import scratchlib.reader.ScratchInputStream;
import scratchlib.writer.ScratchOutputStream;


/**
 * Base class for all {@code Map}-like Scratch collection classes, that is,
 * {@link ScratchObjectDictionary} and {@link ScratchObjectIdentityDictionary}.
 *
 * <p>
 * Allows elements (values) to be associated with other elements (keys), and
 * later retrieved, updated or removed through the same keys again.
 */
public abstract class ScratchObjectAbstractDictionary extends ScratchObject implements IScratchReferenceType
{
    private final Map<ScratchOptionalField, ScratchOptionalField> entriesBeforeResolve = new LinkedHashMap<>();
    private final Map<ScratchObject, ScratchObject> entries = new LinkedHashMap<>();

    /**
     * @param classID The ID of the class this object belongs to.
     */
    public ScratchObjectAbstractDictionary(int classID)
    {
        super(classID);
    }

    /**
     * @return The number of elements in this dictionary.
     */
    public int size()
    {
        return entries.size() + entriesBeforeResolve.size();
    }

    /**
     * Finds the object associated with the given key.
     *
     * @param key The key whose associated value shall be found.
     * @return The associated value.
     */
    public ScratchObject get(ScratchObject key)
    {
        return entries.get(key);
    }

    /**
     * Associates the given key with the given value. Behaves exactly like the
     * equivalent Java Map operation.
     *
     * @param key The entry's key.
     * @param value The entry's value.
     * @throws NullPointerException If key or value are null.
     */
    public void put(ScratchObject key, ScratchObject value)
    {
        Objects.requireNonNull(key);
        Objects.requireNonNull(value);

        entries.put(key, value);
    }

    /**
     * Removes the entry with the given key from this dictionary.
     *
     * @param key The entry's key.
     */
    public void remove(ScratchObject key)
    {
        entries.remove(key);
    }

    /**
     * @return A writable set of all keys in this dictionary.
     */
    public Set<ScratchObject> keySet()
    {
        return entries.keySet();
    }

    /**
     * @return A writable collection of all values in this dictionary.
     */
    public Collection<ScratchObject> values()
    {
        return entries.values();
    }

    /**
     * @return A writable set of all mappings in this dictionary.
     */
    public Set<Entry<ScratchObject, ScratchObject>> entrySet()
    {
        return entries.entrySet();
    }

    @Override
    public boolean createReferences(ScratchReferenceTable ref, ScratchProject project)
    {
        if (!super.createReferences(ref, project)) {
            return false;
        }

        for (Entry<ScratchObject, ScratchObject> entry : entries.entrySet()) {
            entry.getKey().createReferences(ref, project);
            entry.getValue().createReferences(ref, project);
        }

        return true;
    }

    @Override
    public void resolveReferences(ScratchReferenceTable ref)
    {
        super.resolveReferences(ref);

        entries.clear();
        for (Entry<ScratchOptionalField, ScratchOptionalField> entry : entriesBeforeResolve.entrySet()) {
            entry.getKey().resolve(ref);
            entry.getValue().resolve(ref);

            entries.put(entry.getKey().get(), entry.getValue().get());
        }
        entriesBeforeResolve.clear();
    }

    @Override
    public void writeTo(ScratchOutputStream out, ScratchReferenceTable ref, ScratchProject project) throws IOException
    {
        super.writeTo(out, ref, project);

        out.write32bitUnsignedInt(entries.size());
        for (Entry<ScratchObject, ScratchObject> entry : entries.entrySet()) {
            ref.writeField(entry.getKey(), out, project);
            ref.writeField(entry.getValue(), out, project);
        }
    }

    @Override
    public void readFrom(int id, ScratchInputStream in, ScratchProject project) throws IOException
    {
        super.readFrom(id, in, project);

        int size = in.read32bitUnsignedInt();
        for (int i = 0; i < size; ++i) {
            ScratchOptionalField key = ScratchObjects.read(in, project);
            ScratchOptionalField value = ScratchObjects.read(in, project);
            entriesBeforeResolve.put(key, value);
        }
    }
}