Cache.java

  1. package neureka.common.utility;

  2. import java.util.Arrays;
  3. import java.util.Objects;
  4. import java.util.function.Function;

  5. /**
  6.  *  This is a simple, fixed size cache for immutable objects which are
  7.  *  shared throughout the library runtime...
  8.  *  This is an internal class which should not be used outside Neurekas internals.
  9.  *
  10.  * @param <O> The type that should be cached, this may be an {@link neureka.ndim.config.NDConfiguration} or {@code int[]} array.
  11.  */
  12. public final class Cache<O> {

  13.     private final Object[] _buffer;
  14.     private int _size = 0;

  15.     public Cache( int size ) {
  16.         _buffer = new Object[ size ];
  17.     }

  18.     /**
  19.      * @param newObject The object which may or may not be cached.
  20.      * @return Either the provided object or the object found inside the cache...
  21.      */
  22.     public <T extends O> T process( T newObject ) {

  23.         int index = _indexFor(newObject);

  24.         O found = _getAt(index);

  25.         if ( _equalsFor( found, newObject ) ) return (T) found;
  26.         else _setAt( index, newObject );

  27.         return newObject;
  28.     }

  29.     public boolean has( O o ) {
  30.         O found = (O) _buffer[ _indexFor( o ) ];
  31.         return found != null && found.equals( o );
  32.     }

  33.     public int size() { return _size; }

  34.     private O _getAt( int index ) {
  35.         return (O) _buffer[ index ];
  36.     }

  37.     private void _setAt( int index, O o ) {
  38.         if ( _buffer[ index ] == null && o != null ) _size++;
  39.         _buffer[ index ] = o;
  40.     }

  41.     private boolean _equalsFor( Object a, Object b ) {
  42.         if ( a != null && b != null ) {
  43.             if (a instanceof int[] && b instanceof int[])
  44.                 return Arrays.equals((int[]) a, (int[]) b);
  45.             else
  46.                 return Objects.equals(a, b);
  47.         }
  48.         else return false;
  49.     }

  50.     private int _indexFor( Object o ) {
  51.         return o instanceof int[] ? _index((int[]) o) : _index( o.hashCode() );
  52.     }

  53.     private int _index( int key ) {
  54.         return Math.abs(key)% _buffer.length;
  55.     }

  56.     private int _index( int[] data )
  57.     {
  58.         long key = 0;
  59.         for ( int e : data ) {
  60.             if      ( e <=              10 ) key *=              10;
  61.             else if ( e <=             100 ) key *=             100;
  62.             else if ( e <=           1_000 ) key *=           1_000;
  63.             else if ( e <=          10_000 ) key *=          10_000;
  64.             else if ( e <=         100_000 ) key *=         100_000;
  65.             else if ( e <=       1_000_000 ) key *=       1_000_000;
  66.             else if ( e <=      10_000_000 ) key *=      10_000_000;
  67.             else if ( e <=     100_000_000 ) key *=     100_000_000;
  68.             else if ( e <=   1_000_000_000 ) key *=   1_000_000_000;
  69.             key += Math.abs( e ) + 1;
  70.         }
  71.         int rank = data.length;
  72.         while ( rank != 0 ) {
  73.             rank /= 10;
  74.             key *= 10;
  75.         }
  76.         key += data.length;
  77.         return _index(Long.valueOf(key).hashCode());
  78.     }

  79.     /**
  80.      *  Lazy cache entries are entries whose values will be calculated
  81.      *  only when the entry is being stored in the cache.
  82.      *
  83.      * @param <K> The key type parameter.
  84.      * @param <V> The value type parameter.
  85.      */
  86.     public static class LazyEntry<K,V> {

  87.         private final K _key;
  88.         private final Function<K,V> _valueSupplier;

  89.         private V _value = null;

  90.         public LazyEntry( K directory, Function<K,V> valueSupplier ) {
  91.             _key = directory;
  92.             _valueSupplier = valueSupplier;
  93.         }

  94.         public V getValue() {
  95.             if ( _value == null ) _value = _valueSupplier.apply(_key);
  96.             return _value;
  97.         }

  98.         @Override
  99.         public boolean equals(Object o) {
  100.             if ( this == o ) return true;
  101.             if ( o == null || getClass() != o.getClass() ) return false;
  102.             LazyEntry that = (LazyEntry) o;
  103.             return _key.equals(that._key);
  104.         }

  105.         @Override
  106.         public int hashCode() {
  107.             return Objects.hash(_key);
  108.         }

  109.     }

  110. }