SquirrelJME/SquirrelJME

View on GitHub
modules/cldc-compact/src/main/java/java/lang/__InternMini__.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// 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 java.lang;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

/**
 * Miniature intern holding table, used as a basic implementation of a hash
 * table for storing intern strings.
 *
 * @since 2022/06/19
 */
final class __InternMini__
{
    /** The size of the minor intern table. */
    private static final int _MINOR_TABLE_SIZE =
        16;
    
    /** The mask of the minor intern table. */
    private static final int _MINOR_TABLE_MASK =
        15;
    
    /** Internal interns. */
    private final __InternMicro__[] _interns =
        new __InternMicro__[__InternMini__._MINOR_TABLE_SIZE];
    
    /**
     * Performs internal intern logic for the string.
     * 
     * @param __hashCode The hash code.
     * @param __str The string to intern.
     * @return The interned string.
     * @since 2022/06/19
     */
    String __intern(int __hashCode, String __str)
    {
        // Find the actual micro table to use
        int minorKey = __hashCode & __InternMini__._MINOR_TABLE_MASK;
        __InternMicro__[] interns = this._interns;
        __InternMicro__ intern;
        synchronized (this)
        {
            intern = interns[minorKey];
            if (intern == null)
                interns[minorKey] = (intern = new __InternMicro__());
        }
        
        // Perform intern logic on this
        return intern.__intern(__str);
    }
    
    /**
     * Intern micro table, for individual linked list treads.
     * 
     * @since 2022/06/19
     */
    private static final class __InternMicro__
    {
        /** Size bump for the array. */
        private static final int _SIZE_BUMP =
            8;
        
        /** Interned strings that are available. */
        private volatile Reference<String>[] _store =
            __InternMicro__.newArray(__InternMicro__._SIZE_BUMP);
        
        /**
         * Initializes the table.
         * 
         * @since 2022/06/19
         */
        __InternMicro__()
        {
        }
        
        /**
         * Interns the given string.
         * 
         * @param __str The string to intern.
         * @return The interned string.
         * @since 2022/06/19
         */
        String __intern(String __str)
        {
            // Need to lock on ourselves so that we only touch our own table
            // Previously a LinkedList was used however that can cause lots
            // of objects to be allocated for intern strings and arrays are
            // a bit cheaper and save more memory since the linked list nodes
            // can take up extra memory.
            synchronized (this)
            {
                // Scan through and try to find a reference, but if missing we
                // want to use the free slot that is available
                int freeSlot = -1;
                Reference<String>[] store = this._store;
                int storeLen = store.length;
                for (int i = 0; i < storeLen; i++)
                {
                    Reference<String> ref = store[i];
                    
                    // If nothing is here, we can claim it later if we never
                    // find anything
                    if (ref == null)
                    {
                        freeSlot = i;
                        continue;
                    }
                    
                    // Check to see if the other string is missing, then we
                    // can just wipe the reference away
                    String other = ref.get();
                    if (other == null)
                    {
                        // Wipe reference so it gets thrown away
                        store[i] = null;
                        
                        // Counts as a free slot
                        freeSlot = i;
                        continue;
                    }
                    
                    // If this string matches, then it is the interned string
                    // so use it!
                    if (__str.equals(other))
                        return other;
                }
                
                // If there is no free slot then the array is too small, so
                // grow it accordingly
                if (freeSlot < 0)
                {
                    // Setup new array and copy there
                    Reference<String>[] newStore = __InternMicro__.newArray(
                        storeLen + __InternMicro__._SIZE_BUMP);
                    System.arraycopy(store, 0,
                        newStore, 0, storeLen);
                    
                    // Use this reference instead
                    this._store = newStore;
                    store = newStore;
                    
                    // Free slot is at the end of the length
                    freeSlot = storeLen;
                }
                
                // Store weak reference to the string so that it is kept
                // cached and referencable until it is not needed anymore
                store[freeSlot] = new WeakReference<>(__str);
                
                // This string becomes interned now
                __str._quickFlags |= String._QUICK_INTERN;
                return __str;
            }
        }
        
        /**
         * Allocates a new array.
         * 
         * @param __len The array length.
         * @return The reference type.
         * @since 2022/06/19
         */
        @SuppressWarnings("unchecked")
        private static Reference<String>[] newArray(int __len)
        {
            return (Reference<String>[])new Reference[__len];
        }
    }
}