SquirrelJME/SquirrelJME

View on GitHub
tools/squirreljme-debugger/src/main/java/cc/squirreljme/debugger/PersistentStoredInfo.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// Multi-Phasic Applications: SquirrelJME
//     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------

package cc.squirreljme.debugger;

import cc.squirreljme.jdwp.JDWPId;
import cc.squirreljme.runtime.cldc.debug.Debugging;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Persistently stored information.
 *
 * @param <I> The information to store.
 * @since 2024/01/25
 */
public class PersistentStoredInfo<I extends Info>
    extends StoredInfo<I>
{
    /** The internal item cache. */
    private final Map<JDWPId, I> _cache =
        new LinkedHashMap<>();
    
    /**
     * Initializes the stored info.
     *
     * @param __type The type to store.
     * @throws NullPointerException On null arguments.
     * @since 2024/01/25
     */
    public PersistentStoredInfo(InfoKind __type)
        throws NullPointerException
    {
        super(__type);
    }
    
    /**
     * Returns all the known values.
     *
     * @param __state The debugger state.
     * @param __basis The basis type.
     * @return All the known values.
     * @since 2024/01/20
     */
    @Override
    @SuppressWarnings("unchecked")
    public I[] all(DebuggerState __state, Class<? extends Info[]> __basis)
    {
        synchronized (this)
        {
            // Get all the known values, perform garbage collection on them
            Collection<I> values = this._cache.values();
            this.__gc(__state);
            
            I[] result = (I[])Arrays.copyOf(
                values.toArray(new Info[values.size()]),
                values.size(),
                __basis);
            
            // Update all values that we can
            for (I item : result)
                item.update(__state, null);
            
            // Perform sorting on the values, where possible, although it is
            // very iffy
            Arrays.sort(result);
            
            // Use everything
            return result;
        }
    }
    
    /**
     * Obtains the given item if it is already known if it is not then it
     * is created accordingly.
     *
     * @param __state Optional state, if passed then there will be an implicit
     * update to the added item.
     * @param __id The ID of the item to get.
     * @param __extra Any extra values if this needs to be seeded.
     * @return The item, if this returns {@code null} then the item was likely
     * disposed of.
     * @since 2024/01/20
     */
    @Override
    @SuppressWarnings("unchecked")
    public I get(DebuggerState __state, JDWPId __id, Object... __extra)
    {
        if (__id == null)
            throw new NullPointerException("NARG");
        
        Map<JDWPId, I> cache = this._cache;
        synchronized (this)
        {
            I rv = cache.get(__id);
            if (rv == null)
            {
                rv = (I)this.type.seed(__state, __id, __extra);
                
                // Perform update of the object?
                if (__state != null)
                    if (!rv.update(__state, null))
                    {
                        // Debug
                        Debugging.debugNote("Initial was disposed?");
                        
                        return null;
                    }
                
                // Store into the cache
                cache.put(__id, rv);
            }
            
            return rv;
        }
    }
    
    /**
     * Performs garbage collection on the given values.
     *
     * @param __state The current debugger state.
     * @since 2024/01/21
     */
    private void __gc(DebuggerState __state)
    {
        synchronized (this)
        {
            Map<JDWPId, I> items = this._cache;
            for (Iterator<Map.Entry<JDWPId, I>> it =
                 items.entrySet().iterator(); it.hasNext();)
            {
                Map.Entry<JDWPId, I> entry = it.next();
                I item = entry.getValue();
                
                // If the item is known to be disposed, remove it
                if (item.isDisposed())
                    it.remove();
                
                // Request an update for this item, if it gets disposed of then
                // remove that as well
                else if (__state != null &&
                    !item.update(__state, null))
                    it.remove();
            }
        }
    }
}