@@ -501,16 +501,19 @@ protected final static class Default extends BeanPropertyMap
501
501
{
502
502
private static final long serialVersionUID = 1L ;
503
503
504
- private int _hashMask , _size , _spillCount ;
504
+ private int _hashMask ;
505
505
506
- private String [] _keys ;
506
+ /**
507
+ * Number of entries stored in the hash area.
508
+ */
509
+ private int _size ;
510
+
511
+ private int _spillCount ;
507
512
508
513
/**
509
- * Hash area for properties, sparsely populated. Starts with the primary
510
- * hash (size of {@link #_size}), followed by secondary (with half the size
511
- * of primary), and with optional variable size spillover.
514
+ * Hash area that contains key/property pairs in adjacent elements.
512
515
*/
513
- private SettableBeanProperty [] _propsHash ;
516
+ private Object [] _hashArea ;
514
517
515
518
/**
516
519
* Array of properties in the exact order they were handed in. This is
@@ -534,10 +537,9 @@ protected void init(Collection<SettableBeanProperty> props)
534
537
_hashMask = size -1 ;
535
538
536
539
// and allocate enough to contain primary/secondary, expand for spillovers as need be
537
- int alloc = size + (size >>1 );
538
- String [] keys = new String [alloc ];
539
- SettableBeanProperty [] propHash = new SettableBeanProperty [alloc ];
540
- int spills = 0 ;
540
+ int alloc = (size + (size >>1 )) * 2 ;
541
+ Object [] hashed = new Object [alloc ];
542
+ int spillCount = 0 ;
541
543
542
544
for (SettableBeanProperty prop : props ) {
543
545
// Due to removal, renaming, theoretically possible we'll have "holes" so:
@@ -546,36 +548,33 @@ protected void init(Collection<SettableBeanProperty> props)
546
548
}
547
549
548
550
String key = getPropertyName (prop );
549
- // int slot = _hashCode(key);
550
- int slot = key . hashCode () & _hashMask ;
551
+ int slot = _hashCode (key );
552
+ int ix = ( slot << 1 ) ;
551
553
552
554
// primary slot not free?
553
- if (keys [ slot ] != null ) {
555
+ if (hashed [ ix ] != null ) {
554
556
// secondary?
555
- slot = size + (slot >> 1 );
556
- if (keys [ slot ] != null ) {
557
+ ix = ( size + (slot >> 1 )) << 1 ;
558
+ if (hashed [ ix ] != null ) {
557
559
// ok, spill over.
558
- slot = size + (size >> 1 ) + spills ;
559
- ++spills ;
560
- if (slot >= keys .length ) {
561
- keys = Arrays .copyOf (keys , keys .length + 4 );
562
- propHash = Arrays .copyOf (propHash , propHash .length + 4 );
560
+ ix = ((size + (size >> 1 ) ) << 1 ) + spillCount ;
561
+ spillCount += 2 ;
562
+ if (ix >= hashed .length ) {
563
+ hashed = Arrays .copyOf (hashed , hashed .length + 4 );
563
564
}
564
565
}
565
566
}
566
- //System.err.println(" add '"+key+" at #"+slot +"/"+size+" (hashed at "+_hashCode(key) +")");
567
- keys [ slot ] = key ;
568
- propHash [ slot ] = prop ;
567
+ //System.err.println(" add '"+key+" at #"+(ix>>1) +"/"+size+" (hashed at "+slot +")");
568
+ hashed [ ix ] = key ;
569
+ hashed [ ix + 1 ] = prop ;
569
570
}
570
- /*
571
- for (int i = 0; i < keys .length; ++i ) {
572
- System.err.printf("#%02d: %s\n", i, (keys [i] == null) ? "-" : keys [i]);
571
+ /*
572
+ for (int i = 0; i < hashed .length; i += 2 ) {
573
+ System.err.printf("#%02d: %s\n", i>>1 , (hashed [i] == null) ? "-" : hashed [i]);
573
574
}
574
575
*/
575
-
576
- _keys = keys ;
577
- _propsHash = propHash ;
578
- _spillCount = spills ;
576
+ _hashArea = hashed ;
577
+ _spillCount = spillCount ;
579
578
}
580
579
581
580
private final static int findSize (int size )
@@ -620,37 +619,35 @@ public BeanPropertyMap withProperty(SettableBeanProperty newProp)
620
619
{
621
620
// First: may be able to just replace?
622
621
String key = getPropertyName (newProp );
623
- for (int i = 0 , end = _propsHash .length ; i < end ; ++i ) {
624
- SettableBeanProperty prop = _propsHash [i ];
622
+
623
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
624
+ SettableBeanProperty prop = (SettableBeanProperty ) _hashArea [i ];
625
625
if ((prop != null ) && prop .getName ().equals (key )) {
626
- _propsHash [i ] = newProp ;
626
+ _hashArea [i ] = newProp ;
627
627
_propsInOrder [_findFromOrdered (prop )] = newProp ;
628
628
return this ;
629
629
}
630
630
}
631
631
// If not, append
632
-
633
- // int slot = _hashCode(key);
634
- int slot = key .hashCode () & _hashMask ;
635
-
632
+ int slot = _hashCode (key );
636
633
int hashSize = _hashMask +1 ;
637
634
638
635
// primary slot not free?
639
- if (_keys [slot ] != null ) {
636
+ if (_hashArea [slot << 1 ] != null ) {
640
637
// secondary?
641
638
slot = hashSize + (slot >> 1 );
642
- if (_keys [slot ] != null ) {
639
+ if (_hashArea [slot << 1 ] != null ) {
643
640
// ok, spill over.
644
641
slot = hashSize + (hashSize >> 1 ) + _spillCount ;
645
- ++_spillCount ;
646
- if (slot >= _keys .length ) {
647
- _keys = Arrays .copyOf (_keys , _keys .length + 4 );
648
- _propsHash = Arrays .copyOf (_propsHash , _propsHash .length + 4 );
642
+ _spillCount += 2 ;
643
+ if ((slot << 1 ) >= _hashArea .length ) {
644
+ _hashArea = Arrays .copyOf (_hashArea , _hashArea .length + 4 );
649
645
}
650
646
}
651
647
}
652
- _keys [slot ] = key ;
653
- _propsHash [slot ] = newProp ;
648
+ int ix = slot << 1 ;
649
+ _hashArea [ix ] = key ;
650
+ _hashArea [ix +1 ] = newProp ;
654
651
655
652
int last = _propsInOrder .length ;
656
653
_propsInOrder = Arrays .copyOf (_propsInOrder , last +1 );
@@ -666,7 +663,8 @@ public BeanPropertyMap assignIndexes()
666
663
{
667
664
// order is arbitrary, but stable:
668
665
int index = 0 ;
669
- for (SettableBeanProperty prop : _propsHash ) {
666
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
667
+ SettableBeanProperty prop = (SettableBeanProperty ) _hashArea [i ];
670
668
if (prop != null ) {
671
669
prop .assignIndex (index ++);
672
670
}
@@ -683,7 +681,9 @@ public void remove(SettableBeanProperty propToRm)
683
681
ArrayList <SettableBeanProperty > props = new ArrayList <SettableBeanProperty >(_size );
684
682
String key = getPropertyName (propToRm );
685
683
boolean found = false ;
686
- for (SettableBeanProperty prop : _propsHash ) {
684
+
685
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
686
+ SettableBeanProperty prop = (SettableBeanProperty ) _hashArea [i ];
687
687
if (prop == null ) {
688
688
continue ;
689
689
}
@@ -708,10 +708,10 @@ public void remove(SettableBeanProperty propToRm)
708
708
public void replace (SettableBeanProperty newProp )
709
709
{
710
710
String key = getPropertyName (newProp );
711
- for (int i = 0 , end = _propsHash .length ; i < end ; ++ i ) {
712
- SettableBeanProperty prop = _propsHash [i ];
711
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
712
+ SettableBeanProperty prop = ( SettableBeanProperty ) _hashArea [i ];
713
713
if ((prop != null ) && prop .getName ().equals (key )) {
714
- _propsHash [i ] = newProp ;
714
+ _hashArea [i ] = newProp ;
715
715
// also, replace in in-order
716
716
_propsInOrder [_findFromOrdered (prop )] = newProp ;
717
717
return ;
@@ -722,7 +722,8 @@ public void replace(SettableBeanProperty newProp)
722
722
723
723
private List <SettableBeanProperty > properties () {
724
724
ArrayList <SettableBeanProperty > p = new ArrayList <SettableBeanProperty >(_size );
725
- for (SettableBeanProperty prop : _propsHash ) {
725
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
726
+ SettableBeanProperty prop = (SettableBeanProperty ) _hashArea [i ];
726
727
if (prop != null ) {
727
728
p .add (prop );
728
729
}
@@ -743,7 +744,8 @@ public SettableBeanProperty[] getPropertiesInInsertionOrder() {
743
744
@ Override
744
745
public SettableBeanProperty find (int index )
745
746
{
746
- for (SettableBeanProperty prop : _propsHash ) {
747
+ for (int i = 1 , end = _hashArea .length ; i < end ; i += 2 ) {
748
+ SettableBeanProperty prop = (SettableBeanProperty ) _hashArea [i ];
747
749
if ((prop != null ) && (index == prop .getPropertyIndex ())) {
748
750
return prop ;
749
751
}
@@ -760,20 +762,25 @@ public SettableBeanProperty find(String key)
760
762
if (_caseInsensitive ) {
761
763
key = key .toLowerCase ();
762
764
}
763
- // int slot = _hashCode(key);
765
+
766
+ // inlined `_hashCode(key)`
764
767
int slot = key .hashCode () & _hashMask ;
765
- String match = _keys [slot ];
768
+
769
+ // int slot = key.hashCode() & _hashMask;
770
+
771
+ int ix = (slot <<1 );
772
+ Object match = _hashArea [ix ];
766
773
if ((match == key ) || key .equals (match )) {
767
- return _propsHash [ slot ];
774
+ return ( SettableBeanProperty ) _hashArea [ ix + 1 ];
768
775
}
769
776
if (match == null ) {
770
777
return null ;
771
778
}
772
779
// no? secondary?
773
- slot = (_hashMask +1 ) + (slot >>1 );
774
- match = _keys [ slot ];
780
+ ix = (( _hashMask +1 ) + (slot >>1 )) << 1 ;
781
+ match = _hashArea [ ix ];
775
782
if (key .equals (match )) {
776
- return _propsHash [ slot ];
783
+ return ( SettableBeanProperty ) _hashArea [ ix + 1 ];
777
784
}
778
785
// or spill?
779
786
return _findFromSpill (key );
@@ -798,10 +805,11 @@ public boolean findDeserializeAndSet(JsonParser p, DeserializationContext ctxt,
798
805
private SettableBeanProperty _findFromSpill (String key )
799
806
{
800
807
int hashSize = _hashMask +1 ;
801
- int i = hashSize + (hashSize >>1 );
802
- for (int end = i + _spillCount ; i < end ; ++i ) {
803
- if (key .equals (_keys [i ])) {
804
- return _propsHash [i ];
808
+ int i = (hashSize + (hashSize >>1 )) << 1 ;
809
+ for (int end = i + _spillCount ; i < end ; i += 2 ) {
810
+ Object match = _hashArea [i ];
811
+ if ((match == key ) || key .equals (match )) {
812
+ return (SettableBeanProperty ) _hashArea [i +1 ];
805
813
}
806
814
}
807
815
return null ;
@@ -816,12 +824,16 @@ private int _findFromOrdered(SettableBeanProperty prop) {
816
824
throw new IllegalStateException ("Illegal state: property '" +prop .getName ()+"' missing from _propsInOrder" );
817
825
}
818
826
819
- /*
827
+ // Offlined version for convenience if we want to change hashing scheme
820
828
private final int _hashCode (String key ) {
829
+ // This method produces better hash, fewer collisions... yet for some
830
+ // reason produces slightly worse performance. Very strange.
831
+ /*
821
832
int h = key.hashCode();
822
- h ^ = h >> 13;
833
+ h = h + (h >> 13) ;
823
834
return h & _hashMask;
835
+ */
836
+ return key .hashCode () & _hashMask ;
824
837
}
825
- */
826
838
}
827
839
}
0 commit comments