-
Notifications
You must be signed in to change notification settings - Fork 58
[ApiXmlAdjuster] Use different data model structures for better performance #756
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
// It's debatable whether we handle this "properly", as most callers just | ||
// do `First ()`, but it's been working for years so I'm not changing it. | ||
// Exposes an IReadOnlyDictionary so caller cannot bypass our AddType/RemoveType code. | ||
public IReadOnlyDictionary<string, List<JavaType>> Types { get; } |
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.
…alternatively, should this be Set<JavaType>
instead of List<JavaType>
? Does it make sense to allow for the same instance to be added multiple times?
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.
The same "compatibility"/"diff minimization" question/concern applies to Types
vs. AllTypes
: I suspect that if Types
became an IEnumerable<JavaType>
property and AllTypes
were the "Dictionary-like" property, fewer changes would be required.
IMO, the changed I added |
} | ||
|
||
public partial class JavaPackage | ||
{ | ||
private Dictionary<string, List<JavaType>> types = new Dictionary<string, List<JavaType>> (StringComparer.OrdinalIgnoreCase); |
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.
Java type names are not filesystem-bound constructs; they are case sensitive, and it is entirely valid to have a package example
and package Example
in the same app. (It'll cause pain & suffering on case-insensitive filesystems! But Java allows it.)
I think this should use StringComparer.Ordinal
.
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.
Good point, fixed.
@@ -67,11 +70,11 @@ public static void Load (this JavaPackage package, XmlReader reader, bool isRefe | |||
if (reader.LocalName == "class") { | |||
var kls = new JavaClass (package) { IsReferenceOnly = isReferenceOnly }; | |||
kls.Load (reader); | |||
package.Types.Add (kls); |
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.
…back on the "smaller diffs!" front, if we did have a class JavaTypes : KeyedCollection<string, JavaType>
class, this statement wouldn't need to change, nor the many other statements just like it…
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 tested out KeyedCollection
, but it cannot handle duplicate keys:
System.ArgumentException: 'An item with the same key has already been added. Key: key1'
Today, our ApiXmlAdjuster process builds an in-memory model of every Java type we know about, and then queries this model many times in order to ensure we can resolve every needed Java type to build a binding. The data structure of this model is:
Then it is queried using LINQ like this:
In the random GPS package I used for testing,
JavaApi
contained 310 packages and a total of 5941 types. Repeatedly looping through them looking for the correct type takes a considerable amount of time.Instead, we can use a
Dictionary
to store packages and types keyed by name to significantly speed up type resolution:For the GPS project, this reduced time taken considerably:
The only "interesting" detail is that we can have multiple types with the same Java name, such as
MyInterface
andMyInterfaceConsts
. Thus we need to useDictionary<string, List<JavaType>>
to ensure we collect them all.For good measure I ran a XA build with this to ensure
Mono.Android
ApiCompat
didn't find any issues: https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=4282925.