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

org.hibernate.internal.util.collections.LazyIndexedMap Maven / Gradle / Ivy

There is a newer version: 5.6.15.Final
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.internal.util.collections;

import java.util.Arrays;
import java.util.function.Function;

/**
 * This is an internal data structure designed for very specific needs;
 * it will most often be used as a replacement for EnumMap, although
 * the focus on the Enum aspect is modelled as an int primitive:
 * think of using the ordinals of an Enum to simulate the EnumMap.
 * Proper abstraction of the indexing strategy is left to subclasses.
 * 

* There are various reasons to not expose the Enum on this class API; * the primary is that in some of the cases in which we need the pattern, * there is the need to hold an additional couple of values beyond the * ones modelled by the Enum, essentially having some extra keys in the map; * this could be modelled by defining a new Enum but that's also not ideal. *

* Another reason is that the goal of this class is to allow the host to * save memory, as we typically need to keep references to many of these * objects for a long time; being able to refer purely to an array is * less practical but gets us benefits in memory layout and total retained * memory. * * @param the types used to model the key * @param the types used to model the value */ public abstract class LazyIndexedMap { private volatile Object[] values; private static final Object NOT_INITIALIZED = new Object(); protected LazyIndexedMap(final int size) { final Object[] vs = new Object[size]; //could rely on null, then then we should ensure that the valueGenerator function never returns null. //Seems safer to guard with a custom token: the memory impact is negligible since it's a constant, //and we're not needing to create these objects frequently. Arrays.fill( vs, NOT_INITIALIZED ); this.values = vs; } /** * Both the index and the original key are requested for efficiency reasons. * It is the responsibility of the caller to ensure there is a 1:1 matching relation between them. * @param index storage index in the array * @param originalKey the original key object, used to efficiently pass it into the valueGenerator function * @param valueGenerator if no value was generated before for this index, then the valueGenerator is invoked to * associate a new value and store it into the internal array at the provided index. * @return the associated value to this index/key. */ protected V computeIfAbsent(final int index, final K1 originalKey, final Function valueGenerator) { final Object value = this.values[index]; if ( value != NOT_INITIALIZED ) { return (V) value; } else { return lockedComputeIfAbsent( index, originalKey, valueGenerator ); } } private synchronized V lockedComputeIfAbsent(final int index, final K1 originalKey, final Function valueGenerator) { //Get a fresh copy from the volatile read, while holding the global pessimistic lock in this: final Object[] values = this.values; final Object value = values[index]; //Check again if ( value != NOT_INITIALIZED ) { return (V) value; } else { //Actually need to generate the value final V generated = valueGenerator.apply( originalKey ); values[index] = generated; //re-write on the volatile reference to publish any changes to the array this.values = values; return generated; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy