Skip to content

Commit a0976da

Browse files
committed
Implement fast path when merging fields of same message
Fixes google#60
1 parent 0419af7 commit a0976da

File tree

1 file changed

+53
-10
lines changed

1 file changed

+53
-10
lines changed

protobuf/lib/src/protobuf/field_set.dart

+53-10
Original file line numberDiff line numberDiff line change
@@ -768,14 +768,16 @@ class _FieldSet {
768768
/// in this message. Repeated fields are appended. Singular sub-messages are
769769
/// recursively merged.
770770
void _mergeFromMessage(_FieldSet other) {
771-
// TODO(https://github.com/google/protobuf.dart/issues/60): Recognize
772-
// when `this` and [other] are the same protobuf (e.g. from cloning). In
773-
// this case, we can merge the non-extension fields without field lookups or
774-
// validation checks.
775-
771+
final sameMessage = identical(_meta, other._meta);
776772
for (var fi in other._infosSortedByTag) {
777773
var value = other._values[fi.index!];
778-
if (value != null) _mergeField(fi, value, isExtension: false);
774+
if (value != null) {
775+
if (sameMessage) {
776+
_mergeNonExtensionFieldUnchecked(fi, value);
777+
} else {
778+
_mergeField(fi, value, isExtension: false);
779+
}
780+
}
779781
}
780782
if (other._hasExtensions) {
781783
var others = other._extensions!;
@@ -791,14 +793,55 @@ class _FieldSet {
791793
}
792794
}
793795

794-
void _mergeField(FieldInfo otherFi, fieldValue, {bool? isExtension}) {
796+
void _mergeNonExtensionFieldUnchecked(FieldInfo fi, dynamic fieldValue) {
797+
if (fi.isMapField) {
798+
final mapInfo = fi as MapFieldInfo<dynamic, dynamic>;
799+
final map =
800+
mapInfo._ensureMapField(_meta, this) as PbMap<dynamic, dynamic>;
801+
if (_isGroupOrMessage(mapInfo.valueFieldType)) {
802+
for (MapEntry entry in fieldValue.entries) {
803+
map[entry.key] = (entry.value as GeneratedMessage).deepCopy();
804+
}
805+
} else {
806+
map.addAll(fieldValue);
807+
}
808+
return;
809+
}
810+
811+
if (fi.isRepeated) {
812+
if (_isGroupOrMessage(fi.type)) {
813+
PbListBase<GeneratedMessage> pbList = fieldValue;
814+
var repeatedFields = fi._ensureRepeatedField(_meta, this);
815+
for (var i = 0; i < pbList.length; ++i) {
816+
repeatedFields.add(pbList[i].deepCopy());
817+
}
818+
} else {
819+
PbListBase pbList = fieldValue;
820+
fi._ensureRepeatedField(_meta, this).addAll(pbList);
821+
}
822+
return;
823+
}
824+
825+
if (fi.isGroupOrMessage) {
826+
final currentFieldValue = _values[fi.index!];
827+
if (currentFieldValue == null) {
828+
fieldValue = (fieldValue as GeneratedMessage).deepCopy();
829+
} else {
830+
fieldValue = currentFieldValue..mergeFromMessage(fieldValue);
831+
}
832+
}
833+
834+
_setNonExtensionFieldUnchecked(_meta, fi, fieldValue);
835+
}
836+
837+
void _mergeField(FieldInfo otherFi, fieldValue, {required bool isExtension}) {
795838
final tagNumber = otherFi.tagNumber;
796839

797840
// Determine the FieldInfo to use.
798841
// Don't allow regular fields to be overwritten by extensions.
799842
final meta = _meta;
800843
var fi = _nonExtensionInfo(meta, tagNumber);
801-
if (fi == null && isExtension!) {
844+
if (fi == null && isExtension) {
802845
// This will overwrite any existing extension field info.
803846
fi = otherFi;
804847
}
@@ -836,7 +879,7 @@ class _FieldSet {
836879
}
837880

838881
if (otherFi.isGroupOrMessage) {
839-
final currentFi = isExtension!
882+
final currentFi = isExtension
840883
? _ensureExtensions()._getFieldOrNull(fi as Extension<dynamic>)
841884
: _values[fi.index!];
842885

@@ -847,7 +890,7 @@ class _FieldSet {
847890
}
848891
}
849892

850-
if (isExtension!) {
893+
if (isExtension) {
851894
_ensureExtensions()
852895
._setFieldAndInfo(fi as Extension<dynamic>, fieldValue);
853896
} else {

0 commit comments

Comments
 (0)