MoveToContentAsync is often called in states where it will immediately
return true without any reading. In this case return AsyncUtils.True
avoiding allocation or async state-machine.
DoReadAsync is a very heavily hit method, and can often be fulfilled
without creating another state machine, so do this.
The remaining looping async case is the only use of ParsePostValueAsync,
so inline it into the calling method, so there is one less task
allocation.
Return value of EatWhitespaceAsync is never used, returning void reduces
the number of locals an hence the size of the state-machine. Do the same
for EatWhitespace though the impact is less.
Skip attempting write when string is empty.
FirstCharToEscape was introduced for the async version and gives a
faster means to identify the first block before any escaping, so may as
well use it here too.
Conversely, WriteEscapedStringThroughBuffer was introduced to share
code between the sync and async versions, but later optimisations meant
it was no longer used by the async. Inline the code back again.
Create an easily-inlinable method that accesses the array used
by Enumerable.Empty (and hence not just shared within this project
but likely with the client assembly or other libraries it uses)
and use it anywhere a zero-element array is used, reducing allocations.
* Remove unnecessary ToArray call.
* Remove Value property.
One use compares with null, so cast to T is a waste.
This leaves just one other use, so it can be inlined.
* Remove _dontFallbackFirst
Is always true. Remove it and branches for it being false.
* Don't use Expression.Convert to reference types to object.
The end-result is a no-op, so don't waste the allocation.
If Operator is Exists or leftResults is empty don't obtain rightResults,
as not relevant.
Otherwise if rightResults is not an ICollection<JToken> load it into an
List so it won't be recomputed on each enumeration of leftResults.
otherValue == null, including obj == null, both result in false and
will also result in false if continued into the Equals(JValue) method
in the first branch, so having separate branches is just extra work.
With Null and Undefined BsonValue's, one such value is
indistinguishable from another, so singletons can be used for them,
reducing allocations.
With BsonValue containing booleans as well as there being only so
there's a similar advantage with the extra benefit that if there is
only one true value then a reference-equals check can be used instead
of unboxing to determine the value to write.
Branch on key being null or not once, rather than once per loop.
Remove up-cast of token to JToken to allow jitter to either elide
JValue path if impossible or turn into null-test when inevitable.
Replace is-and-cast with as-and-null-test for quicker cast in cases
where cast is still done.
Running a spell checker on the whole solution revealed a couple more
typos. This fixes all of those (although internal // line comments are
mostly left alone).
Additionally, convert a very few string.Format occurrences to the pre-
dominant .FormatWith pattern and fix some incorrect message strings.
Primarily where it means one fewer field-access or simplifies
event delegate invocation, though one or two cases have just the
lesser advantage of allowing an IL stack dup rather than local access.