Skip to content

Commit 478b744

Browse files
committed
Minor tweaking; unify String/prop hash areas (needs casting), revert back to older findIndex + call
1 parent 5646c93 commit 478b744

File tree

2 files changed

+106
-71
lines changed

2 files changed

+106
-71
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,17 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt, Object bean
214214
}
215215
do {
216216
p.nextToken();
217-
if (!_beanProperties.findDeserializeAndSet(p, ctxt, bean, propName)) {
218-
handleUnknownVanilla(p, ctxt, bean, propName);
217+
SettableBeanProperty prop = _beanProperties.find(propName);
218+
219+
if (prop != null) { // normal case
220+
try {
221+
prop.deserializeAndSet(p, ctxt, bean);
222+
} catch (Exception e) {
223+
wrapAndThrow(e, bean, propName, ctxt);
224+
}
225+
continue;
219226
}
227+
handleUnknownVanilla(p, ctxt, bean, propName);
220228
} while ((propName = p.nextFieldName()) != null);
221229
return bean;
222230
}
@@ -242,9 +250,17 @@ private final Object vanillaDeserialize(JsonParser p,
242250
String propName = p.getCurrentName();
243251
do {
244252
p.nextToken();
245-
if (!_beanProperties.findDeserializeAndSet(p, ctxt, bean, propName)) {
246-
handleUnknownVanilla(p, ctxt, bean, propName);
253+
SettableBeanProperty prop = _beanProperties.find(propName);
254+
255+
if (prop != null) { // normal case
256+
try {
257+
prop.deserializeAndSet(p, ctxt, bean);
258+
} catch (Exception e) {
259+
wrapAndThrow(e, bean, propName, ctxt);
260+
}
261+
continue;
247262
}
263+
handleUnknownVanilla(p, ctxt, bean, propName);
248264
} while ((propName = p.nextFieldName()) != null);
249265
}
250266
return bean;
@@ -316,9 +332,16 @@ public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) t
316332
String propName = p.getCurrentName();
317333
do {
318334
p.nextToken();
319-
if (!_beanProperties.findDeserializeAndSet(p, ctxt, bean, propName)) {
320-
handleUnknownVanilla(p, ctxt, bean, propName);
335+
SettableBeanProperty prop = _beanProperties.find(propName);
336+
if (prop != null) { // normal case
337+
try {
338+
prop.deserializeAndSet(p, ctxt, bean);
339+
} catch (Exception e) {
340+
wrapAndThrow(e, bean, propName, ctxt);
341+
}
342+
continue;
321343
}
344+
handleUnknownVanilla(p, ctxt, bean, propName);
322345
} while ((propName = p.nextFieldName()) != null);
323346
}
324347
return bean;

src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -501,16 +501,19 @@ protected final static class Default extends BeanPropertyMap
501501
{
502502
private static final long serialVersionUID = 1L;
503503

504-
private int _hashMask, _size, _spillCount;
504+
private int _hashMask;
505505

506-
private String[] _keys;
506+
/**
507+
* Number of entries stored in the hash area.
508+
*/
509+
private int _size;
510+
511+
private int _spillCount;
507512

508513
/**
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.
512515
*/
513-
private SettableBeanProperty[] _propsHash;
516+
private Object[] _hashArea;
514517

515518
/**
516519
* Array of properties in the exact order they were handed in. This is
@@ -534,10 +537,9 @@ protected void init(Collection<SettableBeanProperty> props)
534537
_hashMask = size-1;
535538

536539
// 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;
541543

542544
for (SettableBeanProperty prop : props) {
543545
// Due to removal, renaming, theoretically possible we'll have "holes" so:
@@ -546,36 +548,33 @@ protected void init(Collection<SettableBeanProperty> props)
546548
}
547549

548550
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);
551553

552554
// primary slot not free?
553-
if (keys[slot] != null) {
555+
if (hashed[ix] != null) {
554556
// secondary?
555-
slot = size + (slot >> 1);
556-
if (keys[slot] != null) {
557+
ix = (size + (slot >> 1)) << 1;
558+
if (hashed[ix] != null) {
557559
// 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);
563564
}
564565
}
565566
}
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;
569570
}
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]);
573574
}
574575
*/
575-
576-
_keys = keys;
577-
_propsHash = propHash;
578-
_spillCount = spills;
576+
_hashArea = hashed;
577+
_spillCount = spillCount;
579578
}
580579

581580
private final static int findSize(int size)
@@ -620,37 +619,35 @@ public BeanPropertyMap withProperty(SettableBeanProperty newProp)
620619
{
621620
// First: may be able to just replace?
622621
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];
625625
if ((prop != null) && prop.getName().equals(key)) {
626-
_propsHash[i] = newProp;
626+
_hashArea[i] = newProp;
627627
_propsInOrder[_findFromOrdered(prop)] = newProp;
628628
return this;
629629
}
630630
}
631631
// If not, append
632-
633-
// int slot = _hashCode(key);
634-
int slot = key.hashCode() & _hashMask;
635-
632+
int slot = _hashCode(key);
636633
int hashSize = _hashMask+1;
637634

638635
// primary slot not free?
639-
if (_keys[slot] != null) {
636+
if (_hashArea[slot << 1] != null) {
640637
// secondary?
641638
slot = hashSize + (slot >> 1);
642-
if (_keys[slot] != null) {
639+
if (_hashArea[slot << 1] != null) {
643640
// ok, spill over.
644641
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);
649645
}
650646
}
651647
}
652-
_keys[slot] = key;
653-
_propsHash[slot] = newProp;
648+
int ix = slot << 1;
649+
_hashArea[ix] = key;
650+
_hashArea[ix+1] = newProp;
654651

655652
int last = _propsInOrder.length;
656653
_propsInOrder = Arrays.copyOf(_propsInOrder, last+1);
@@ -666,7 +663,8 @@ public BeanPropertyMap assignIndexes()
666663
{
667664
// order is arbitrary, but stable:
668665
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];
670668
if (prop != null) {
671669
prop.assignIndex(index++);
672670
}
@@ -683,7 +681,9 @@ public void remove(SettableBeanProperty propToRm)
683681
ArrayList<SettableBeanProperty> props = new ArrayList<SettableBeanProperty>(_size);
684682
String key = getPropertyName(propToRm);
685683
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];
687687
if (prop == null) {
688688
continue;
689689
}
@@ -708,10 +708,10 @@ public void remove(SettableBeanProperty propToRm)
708708
public void replace(SettableBeanProperty newProp)
709709
{
710710
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];
713713
if ((prop != null) && prop.getName().equals(key)) {
714-
_propsHash[i] = newProp;
714+
_hashArea[i] = newProp;
715715
// also, replace in in-order
716716
_propsInOrder[_findFromOrdered(prop)] = newProp;
717717
return;
@@ -722,7 +722,8 @@ public void replace(SettableBeanProperty newProp)
722722

723723
private List<SettableBeanProperty> properties() {
724724
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];
726727
if (prop != null) {
727728
p.add(prop);
728729
}
@@ -743,7 +744,8 @@ public SettableBeanProperty[] getPropertiesInInsertionOrder() {
743744
@Override
744745
public SettableBeanProperty find(int index)
745746
{
746-
for (SettableBeanProperty prop : _propsHash) {
747+
for (int i = 1, end = _hashArea.length; i < end; i += 2) {
748+
SettableBeanProperty prop = (SettableBeanProperty) _hashArea[i];
747749
if ((prop != null) && (index == prop.getPropertyIndex())) {
748750
return prop;
749751
}
@@ -760,20 +762,25 @@ public SettableBeanProperty find(String key)
760762
if (_caseInsensitive) {
761763
key = key.toLowerCase();
762764
}
763-
// int slot = _hashCode(key);
765+
766+
// inlined `_hashCode(key)`
764767
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];
766773
if ((match == key) || key.equals(match)) {
767-
return _propsHash[slot];
774+
return (SettableBeanProperty) _hashArea[ix+1];
768775
}
769776
if (match == null) {
770777
return null;
771778
}
772779
// no? secondary?
773-
slot = (_hashMask+1) + (slot>>1);
774-
match = _keys[slot];
780+
ix = ((_hashMask+1) + (slot>>1)) << 1;
781+
match = _hashArea[ix];
775782
if (key.equals(match)) {
776-
return _propsHash[slot];
783+
return (SettableBeanProperty) _hashArea[ix+1];
777784
}
778785
// or spill?
779786
return _findFromSpill(key);
@@ -798,10 +805,11 @@ public boolean findDeserializeAndSet(JsonParser p, DeserializationContext ctxt,
798805
private SettableBeanProperty _findFromSpill(String key)
799806
{
800807
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];
805813
}
806814
}
807815
return null;
@@ -816,12 +824,16 @@ private int _findFromOrdered(SettableBeanProperty prop) {
816824
throw new IllegalStateException("Illegal state: property '"+prop.getName()+"' missing from _propsInOrder");
817825
}
818826

819-
/*
827+
// Offlined version for convenience if we want to change hashing scheme
820828
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+
/*
821832
int h = key.hashCode();
822-
h ^= h >> 13;
833+
h = h + (h >> 13);
823834
return h & _hashMask;
835+
*/
836+
return key.hashCode() & _hashMask;
824837
}
825-
*/
826838
}
827839
}

0 commit comments

Comments
 (0)