Skip to content

Commit

Permalink
Remove a closure in _FieldSet.hashCode (#633)
Browse files Browse the repository at this point in the history
* Remove a closure in `_FieldSet.hashCode`

Improves HashCode benchmark up to 3%.

JIT before:

    HashCode(RunTime): 1981.9821782178217 us.
    HashCode(RunTime): 1974.7068114511353 us.
    HashCode(RunTime): 1970.9261083743843 us.

JIT after:

    HashCode(RunTime): 1899.034155597723 us.
    HashCode(RunTime): 1912.0917782026768 us.
    HashCode(RunTime): 1908.1782650142993 us.

Native AOT before:

    HashCode(RunTime): 5164.038659793814 us.
    HashCode(RunTime): 5177.984496124031 us.
    HashCode(RunTime): 5192.199481865285 us.

Native AOT after:

    HashCode(RunTime): 5027.246231155779 us.
    HashCode(RunTime): 5045.488664987405 us.
    HashCode(RunTime): 5134.379487179487 us.

JS before:

    HashCode(RunTime): 6944.444444444444 us.
    HashCode(RunTime): 6913.793103448276 us.
    HashCode(RunTime): 6927.335640138408 us.

JS after:

    HashCode(RunTime): 6846.41638225256 us.
    HashCode(RunTime): 6965.277777777777 us.
    HashCode(RunTime): 6920.415224913495 us.

Fixes #632
  • Loading branch information
osa1 authored Apr 26, 2022
1 parent 5731242 commit 1b12ac9
Showing 1 changed file with 26 additions and 25 deletions.
51 changes: 26 additions & 25 deletions protobuf/lib/src/protobuf/field_set.dart
Original file line number Diff line number Diff line change
Expand Up @@ -654,29 +654,6 @@ class _FieldSet {
if (_hashCodesCanBeMemoized && _memoizedHashCode != null) {
return _memoizedHashCode!;
}
// Hashes the value of one field (recursively).
int hashField(int hash, FieldInfo fi, value) {
if (value is List && value.isEmpty) {
return hash; // It's either repeated or an empty byte array.
}

hash = _HashUtils._combine(hash, fi.tagNumber);
if (_isBytes(fi.type)) {
// Bytes are represented as a List<int> (Usually with byte-data).
// We special case that to match our equality semantics.
hash = _HashUtils._combine(hash, _HashUtils._hashObjects(value));
} else if (!_isEnum(fi.type)) {
hash = _HashUtils._combine(hash, value.hashCode);
} else if (fi.isRepeated) {
hash = _HashUtils._combine(
hash, _HashUtils._hashObjects(value.map((enm) => enm.value)));
} else {
ProtobufEnum enm = value;
hash = _HashUtils._combine(hash, enm.value);
}

return hash;
}

// Hash with descriptor.
var hash = _HashUtils._combine(0, _meta.hashCode);
Expand All @@ -686,7 +663,7 @@ class _FieldSet {
for (final fi in _infosSortedByTag) {
final value = values[fi.index!];
if (value == null) continue;
hash = hashField(hash, fi, value);
hash = _hashField(hash, fi, value);
}

// Hash with extension fields.
Expand All @@ -695,7 +672,7 @@ class _FieldSet {
final sortedByTagNumbers = _sorted(extensions._tagNumbers);
for (final tagNumber in sortedByTagNumbers) {
final fi = extensions._getInfoOrNull(tagNumber)!;
hash = hashField(hash, fi, extensions._getFieldOrNull(fi));
hash = _hashField(hash, fi, extensions._getFieldOrNull(fi));
}
}

Expand All @@ -710,6 +687,30 @@ class _FieldSet {
return hash;
}

// Hashes the value of one field (recursively).
static int _hashField(int hash, FieldInfo fi, value) {
if (value is List && value.isEmpty) {
return hash; // It's either repeated or an empty byte array.
}

hash = _HashUtils._combine(hash, fi.tagNumber);
if (_isBytes(fi.type)) {
// Bytes are represented as a List<int> (Usually with byte-data).
// We special case that to match our equality semantics.
hash = _HashUtils._combine(hash, _HashUtils._hashObjects(value));
} else if (!_isEnum(fi.type)) {
hash = _HashUtils._combine(hash, value.hashCode);
} else if (fi.isRepeated) {
hash = _HashUtils._combine(
hash, _HashUtils._hashObjects(value.map((enm) => enm.value)));
} else {
ProtobufEnum enm = value;
hash = _HashUtils._combine(hash, enm.value);
}

return hash;
}

void writeString(StringBuffer out, String indent) {
void renderValue(key, value) {
if (value is GeneratedMessage) {
Expand Down

0 comments on commit 1b12ac9

Please sign in to comment.