meyfa/scratchlib

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

Summary

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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 List}-like Scratch collection classes, e.g.
 * {@link ScratchObjectArray} or {@link ScratchObjectOrderedCollection}.
 *
 * <p>
 * Allows objects to be stored, retrieved, replaced, inserted and removed via
 * indices.
 */
public abstract class ScratchObjectAbstractCollection extends ScratchObject
        implements IScratchReferenceType, Iterable<ScratchObject>
{
    private final List<ScratchOptionalField> entries;

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

        this.entries = new ArrayList<>();
    }

    /**
     * @param classID The ID of the class this object belongs to.
     * @param entries The entries to initialize this collection with.
     */
    public ScratchObjectAbstractCollection(int classID, Collection<? extends ScratchObject> entries)
    {
        super(classID);

        this.entries = entries.stream().map(ScratchOptionalField::new)
                .collect(Collectors.toCollection(ArrayList::new));
    }

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

    /**
     * Retrieves an element from this collection.
     *
     * @param index The object's index.
     * @return The object at the given index.
     */
    public ScratchObject get(int index)
    {
        return entries.get(index).get();
    }

    /**
     * Replaces an element in this collection with a different object.
     *
     * @param index The object's index.
     * @param object The object to replace the current one with.
     * @throws NullPointerException If object is null.
     */
    public void set(int index, ScratchObject object)
    {
        Objects.requireNonNull(object);
        entries.set(index, new ScratchOptionalField(object));
    }

    /**
     * Adds an element to this collection.
     *
     * @param object The element to add.
     * @throws NullPointerException If object is null.
     */
    public void add(ScratchObject object)
    {
        Objects.requireNonNull(object);
        entries.add(new ScratchOptionalField(object));
    }

    /**
     * Inserts an element into this collection, shifting the current and all
     * subsequent elements to the right (adding one to their indices).
     *
     * @param index The position at which to insert.
     * @param object The element to add.
     * @throws NullPointerException If object is null.
     */
    public void add(int index, ScratchObject object)
    {
        Objects.requireNonNull(object);
        entries.add(index, new ScratchOptionalField(object));
    }

    /**
     * Removes an element from this collection.
     *
     * @param index The index of the element to remove.
     * @return The removed element.
     */
    public ScratchObject remove(int index)
    {
        return entries.remove(index).get();
    }

    /**
     * Removes a given element from this collection.
     *
     * @param object The element to remove.
     */
    public void remove(ScratchObject object)
    {
        entries.removeIf(optionalField -> Objects.equals(optionalField.get(), object));
    }

    /**
     * Removes all elements from this collection.
     */
    public void clear()
    {
        entries.clear();
    }

    @Override
    public Iterator<ScratchObject> iterator()
    {
        return entries.stream().map(ScratchOptionalField::get).iterator();
    }

    /**
     * @return A sequential stream of all objects in this collection.
     */
    public Stream<ScratchObject> stream()
    {
        return entries.stream().map(ScratchOptionalField::get);
    }

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

        for (ScratchOptionalField entry : entries) {
            entry.get().createReferences(ref, project);
        }

        return true;
    }

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

        for (ScratchOptionalField entry : entries) {
            entry.resolve(ref);
        }
    }

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

        out.write32bitUnsignedInt(entries.size());
        for (ScratchOptionalField entry : entries) {
            ref.writeField(entry.get(), 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) {
            entries.add(ScratchObjects.read(in, project));
        }
    }
}