Remove a closure in `_FieldSet.hashCode` (#633)
* 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
diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart
index 9e702b6..2316d24 100644
--- a/protobuf/lib/src/protobuf/field_set.dart
+++ b/protobuf/lib/src/protobuf/field_set.dart
@@ -654,29 +654,6 @@
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);
@@ -686,7 +663,7 @@
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.
@@ -695,7 +672,7 @@
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));
}
}
@@ -710,6 +687,30 @@
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) {