-
-
Notifications
You must be signed in to change notification settings - Fork 29
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
Some refactors to WikiEngine, attempting to switch to ReadOnlySpan<char>
#1906
base: main
Are you sure you want to change the base?
Conversation
a89148a
to
62de2ac
Compare
62de2ac
to
5d2b032
Compare
ReadOnlySpan<char>
ReadOnlySpan<char>
5d2b032
to
dc2ac4e
Compare
Element div = new( | ||
_charRange, | ||
"div", | ||
attributes: [new("class", "module-error")], |
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.
This creates an extra object for the attributes collection compared to the old version of the code. This isn't entirely a new problem, as there were some other callsites that wasted objects before, but it's worse now.
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.
Wasn't it allocating the same number of collections before, just in the Ah I see, this is an array + Element
ctor?ToDictionary
. Should I go back to inserting after init, or should I add constructors which take a Dictionary
?
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.
Passing a Dictionary
seems good so long as we can make sure we never accidentally share those dictionaries (the passed object should be owned by the element that created 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.
Sorry, do you mean owned by the Element
or owned by the call-site? Not that I know how to put either into code—mutation of Element.Attributes
is relied on by a few call-sites, so it can't simply be changed to ImmutableDictionary
for example.
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.
Owned by the element; I don't want to accidentally share a single Dictionary across multiple elements, as that would be too confusing for now.
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.
There are actually fewer mutations than I thought (must have confused it with Children
), but even after encapsulating them, I can't think of a good way to enforce that invariant that's not just defensive copying.
I tried [CallerArgumentExpression]
+ checking for new Dictionary
or .ToDictionary(
, but while it may have worked, it also would have made every callsite verbose. Plus, half the callsites use the Attr
method, so they would have to be new Dictionary(new[] { Attr(..., ...) })
which I believe allocates no less than new KVP<string, string>[] { Attr(..., ...) }.ToDictionary()
.
Unless you have any ideas, I'll go ahead with replacing IEnumerable
s with Dictionary
s, and it will just have to rely on humans not misusing references.
: this((charStart, default), tag, attributes, children: children.AsEnumerable()) { } | ||
|
||
public Element(StringIndices range, string tag) | ||
: this(range, tag, [], children: (IEnumerable<INode>)[]) { } |
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.
Does the use of []
here automatically pool a single Enumerable.Empty or are we making new objects every time?
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.
It just uses Array.Empty.
I feel lukewarm on this PR as a whole. Avoiding needless copies is good for speedup, and that certainly includes Do we have profiling evidence from production that wiki rendering is slow enough to be a problem? What money are we trying to save here anyway; I don't have any access to the cost breakdown of running production? If wiki rendering is the problem, then we could likely save more speed, and with simpler code, by caching partially hydrated pages. |
So to me neither the PR title, nor the PR description explain what this does and what its purpose is.
So basically I have the following questions:
|
I'll try to explain further, though as natt noted, the key change of Merging the start and end indices into a tuple is just a simplification. It also highlights the call-sites where You didn't ask about the The You also didn't ask about the first commit. That contains all the changes I would have had to do in the last commit, but doing them first reduced churn. Some of that I think would be a good idea outside of this PR, namely passing an So yes, with those few exceptions it does all have to be done in 1 PR, since the later commits depend on the previous, and merging only some without actually switching to |
public int CharEnd { get; set; } | ||
public Module(int charStart, int charEnd, string text) | ||
|
||
private StringIndices _charRange = (default, default); |
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.
This field init was necessary at one point, but in the end only the tuple ctor is left, so it can be removed.
I'll clean up the diffs when I'm not so sleep-deprived. At this stage, I'd like to know whether you think this is a good idea at all, whether the final signatures are good, and if you'd like any of the added types/methods placed somewhere else. Oh, and if you have any ideas for removing one of the remainingI think this is finished nowToString
calls.I still hate the StyleCop settings.