-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Override == and hashCode in PbMap #224
Changes from 1 commit
103434e
fba29e8
94b9e5c
3f4e34e
e2d88d8
3663527
92389c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,35 @@ class PbMap<K, V> extends MapBase<K, V> { | |
_wrappedMap[key] = value; | ||
} | ||
|
||
@override | ||
bool operator ==(other) { | ||
if (identical(other, this)) { | ||
return true; | ||
} | ||
if (other is! PbMap) { | ||
return false; | ||
} | ||
if (other.length != length) { | ||
return false; | ||
} | ||
if (other.hashCode != hashCode) { | ||
return false; | ||
} | ||
for (final key in keys) { | ||
if (other[key] != this[key]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As a TODO - It might be more efficient to check all the keys first, since they are usually smaller than the values. |
||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
int get hashCode { | ||
sigurdm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return hashObjects(_wrappedMap.keys | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally we should be able to share code with _FieldSet.hashCode and PbList.hashCode |
||
.map((key) => hash2(key.hashCode, _wrappedMap[key].hashCode)) | ||
.toList(growable: false) | ||
..sort()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can just rely on the default dart map being ordered (it is a LinkedHashMap)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No of course not! - different order of insertion should still result in the same hashcode. I think we can xor the hashcodes of all the entries. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hash2 takes two Objects, and calls their hashCodes. hashObjects takes an Iterable of Objects and calls the hashCodes. In effect we are doing a lot of x.hashCode.hashCode. |
||
} | ||
|
||
@override | ||
void clear() { | ||
if (_isReadonly) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
name: protobuf | ||
version: 0.13.5 | ||
version: 0.13.6 | ||
author: Dart Team <misc@dartlang.org> | ||
description: > | ||
Runtime library for protocol buffers support. | ||
|
@@ -9,6 +9,7 @@ environment: | |
sdk: '>=2.0.0-dev.17.0 <3.0.0' | ||
dependencies: | ||
fixnum: '>=0.9.0 <0.11.0' | ||
quiver: ^2.0.2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer we do not get further dependencies if we can avoid it. I think it is better to duplicate it. |
||
dev_dependencies: | ||
test: '>=1.2.0' | ||
benchmark_harness: any | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ library map_field_test; | |
|
||
import 'dart:convert'; | ||
|
||
import 'package:protobuf/protobuf.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import '../out/protos/map_field.pb.dart'; | ||
|
@@ -212,6 +213,27 @@ void main() { | |
_expectEmpty(testMap); | ||
}); | ||
|
||
test( | ||
'PbMap` is equal to another PbMap with equal key/value pairs in any order', | ||
() { | ||
TestMap t = TestMap() | ||
..int32ToStringField[2] = 'test2' | ||
..int32ToStringField[1] = 'test'; | ||
TestMap t2 = TestMap() | ||
..int32ToStringField[1] = 'test' | ||
..int32ToStringField[2] = 'test2'; | ||
|
||
PbMap<int, String> m = t.int32ToStringField; | ||
PbMap<int, String> m2 = t2.int32ToStringField; | ||
|
||
expect(t, t2); | ||
expect(t.hashCode, t2.hashCode); | ||
|
||
expect(m, m2); | ||
expect(m == m2, isTrue); | ||
expect(m.hashCode, m2.hashCode); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a negative test? |
||
}); | ||
|
||
test('merge from other message', () { | ||
TestMap testMap = TestMap(); | ||
_setValues(testMap); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think calculating the hash code during equality testing is slower than just doing structural equality testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much slower if the first key is not in the other map!
It is also exponential in the nesting depth of the PbMaps when the map values contain PbMaps -
you walk the maps for this hashCode call, and again in the
!=
below.Perhaps you can make a benchmark for PbMaps nested 20x deep to prove we avoid this problem.