Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

219
LINES

< > BotCompany Repo | #1036017 // IntIntHashMap - by Mikhail Vorontsov, originally called IntIntMap4a

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (365L/3K).

sclass IntIntHashMap is IIntIntMap {
  private static final int FREE_KEY = 0;

  public static final int NO_VALUE = 0;

  /** Keys and values */
  private int[] m_data;

  /** Do we have 'free' key in the map? */
  private boolean m_hasFreeKey;
  /** Value of 'free' key */
  private int m_freeValue;

  /** Fill factor, must be between (0 and 1) */
  private final float m_fillFactor;
  /** We will resize a map once it reaches this size */
  private int m_threshold;
  /** Current map size */
  private int m_size;

  /** Mask to calculate the original position */
  private int m_mask;
  private int m_mask2;

  *( final int size, final float fillFactor )
  {
      if ( fillFactor <= 0 || fillFactor >= 1 )
          throw new IllegalArgumentException( "FillFactor must be in (0, 1)" );
      if ( size <= 0 )
          throw new IllegalArgumentException( "Size must be positive!" );
      final int capacity = arraySize(size, fillFactor);
      m_mask = capacity - 1;
      m_mask2 = capacity*2 - 1;
      m_fillFactor = fillFactor;

      m_data = new int[capacity * 2];
      m_threshold = (int) (capacity * fillFactor);
  }

  public int get( final int key )
  {
      int ptr = ( phiMix( key ) & m_mask) << 1;

      if ( key == FREE_KEY )
          return m_hasFreeKey ? m_freeValue : NO_VALUE;

      int k = m_data[ ptr ];

      if ( k == FREE_KEY )
          return NO_VALUE;  //end of chain already
      if ( k == key ) //we check FREE prior to this call
          return m_data[ ptr + 1 ];

      while ( true )
      {
          ptr = (ptr + 2) & m_mask2; //that's next index
          k = m_data[ ptr ];
          if ( k == FREE_KEY )
              return NO_VALUE;
          if ( k == key )
              return m_data[ ptr + 1 ];
      }
  }

  public int put( final int key, final int value )
  {
      if ( key == FREE_KEY )
      {
          final int ret = m_freeValue;
          if ( !m_hasFreeKey )
              ++m_size;
          m_hasFreeKey = true;
          m_freeValue = value;
          return ret;
      }

      int ptr = ( phiMix( key ) & m_mask) << 1;
      int k = m_data[ptr];
      if ( k == FREE_KEY ) //end of chain already
      {
          m_data[ ptr ] = key;
          m_data[ ptr + 1 ] = value;
          if ( m_size >= m_threshold )
              rehash( m_data.length * 2 ); //size is set inside
          else
              ++m_size;
          return NO_VALUE;
      }
      else if ( k == key ) //we check FREE prior to this call
      {
          final int _ret = m_data[ ptr + 1 ];
          m_data[ ptr + 1 ] = value;
          return _ret;
      }

      while ( true )
      {
          ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
          k = m_data[ ptr ];
          if ( k == FREE_KEY )
          {
              m_data[ ptr ] = key;
              m_data[ ptr + 1 ] = value;
              if ( m_size >= m_threshold )
                  rehash( m_data.length * 2 ); //size is set inside
              else
                  ++m_size;
              return NO_VALUE;
          }
          else if ( k == key )
          {
              final int _ret = m_data[ ptr + 1 ];
              m_data[ ptr + 1 ] = value;
              return _ret;
          }
      }
  }

  public int remove( final int key )
  {
      if ( key == FREE_KEY )
      {
          if ( !m_hasFreeKey )
              return NO_VALUE;
          m_hasFreeKey = false;
          --m_size;
          return m_freeValue; //value is not cleaned
      }

      int ptr = ( phiMix( key ) & m_mask) << 1;
      int k = m_data[ ptr ];
      if ( k == key ) //we check FREE prior to this call
      {
          final int res = m_data[ ptr + 1 ];
          shiftKeys( ptr );
          --m_size;
          return res;
      }
      else if ( k == FREE_KEY )
          return NO_VALUE;  //end of chain already
      while ( true )
      {
          ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation
          k = m_data[ ptr ];
          if ( k == key )
          {
              final int res = m_data[ ptr + 1 ];
              shiftKeys( ptr );
              --m_size;
              return res;
          }
          else if ( k == FREE_KEY )
              return NO_VALUE;
      }
  }

  private int shiftKeys(int pos)
  {
      // Shift entries with the same hash.
      int last, slot;
      int k;
      final int[] data = this.m_data;
      while ( true )
      {
          pos = ((last = pos) + 2) & m_mask2;
          while ( true )
          {
              if ((k = data[pos]) == FREE_KEY)
              {
                  data[last] = FREE_KEY;
                  return last;
              }
              slot = ( phiMix( k ) & m_mask) << 1; //calculate the starting slot for the current key
              if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) break;
              pos = (pos + 2) & m_mask2; //go to the next entry
          }
          data[last] = k;
          data[last + 1] = data[pos + 1];
      }
  }


  public int size()
  {
      return m_size;
  }

  private void rehash( final int newCapacity )
  {
      m_threshold = (int) (newCapacity/2 * m_fillFactor);
      m_mask = newCapacity/2 - 1;
      m_mask2 = newCapacity - 1;

      final int oldCapacity = m_data.length;
      final int[] oldData = m_data;

      m_data = new int[ newCapacity ];
      m_size = m_hasFreeKey ? 1 : 0;

      for ( int i = 0; i < oldCapacity; i += 2 ) {
          final int oldKey = oldData[ i ];
          if( oldKey != FREE_KEY )
              put( oldKey, oldData[ i + 1 ]);
      }
  }
  
  static int arraySize( final int expected, final float f ) {
      final long s = Math.max( 2, nextPowerOfTwo( (long)Math.ceil( expected / f ) ) );
      if ( s > (1 << 30) ) throw new IllegalArgumentException( "Too large (" + expected + " expected elements with load factor " + f + ")" );
      return (int)s;
    }

  static final int INT_PHI = 0x9E3779B9;

  static int phiMix( final int x ) {
    final int h = x * INT_PHI;
    return h ^ (h >> 16);
  }
}

Author comment

Began life as a copy of #1026144

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): elmgxqgtpvxh, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1036017
Snippet name: IntIntHashMap - by Mikhail Vorontsov, originally called IntIntMap4a
Eternal ID of this version: #1036017/1
Text MD5: 8ce9a3657d46ca0b27d0e8fb60246609
Transpilation MD5: afb8a8ab383f2e8ef2700f711f6a1f1f
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-08-30 18:35:36
Source code size: 6260 bytes / 219 lines
Pitched / IR pitched: No / No
Views / Downloads: 129 / 187
Referenced in: #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167)