Skip to content

Commit

Permalink
remove the need of having a separate stack of ids that are being pars…
Browse files Browse the repository at this point in the history
…ed by reusing the knowledge about whether given Id was already in the IncompleteObjects hash set or not
  • Loading branch information
adamsitnik committed Jun 12, 2024
1 parent cd54d66 commit daa7431
Showing 1 changed file with 6 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ internal sealed partial class Deserializer : IDeserializer
private Queue<PendingSerializationInfo>? _pendingSerializationInfo;
private HashSet<SerializationRecordId>? _pendingSerializationInfoIds;

// Keeping a separate stack for ids for fast infinite loop checks.
private readonly Stack<SerializationRecordId> _parseStack = [];
private readonly Stack<ObjectRecordDeserializer> _parserStack = [];

/// <inheritdoc cref="IDeserializer.IncompleteObjects"/>
Expand Down Expand Up @@ -183,41 +181,36 @@ private object Deserialize()
[RequiresUnreferencedCode("Calls DeserializeNew(SerializationRecordId)")]
private void DeserializeRoot(SerializationRecordId rootId)
{
object root = DeserializeNew(rootId);
object root = DeserializeNew(rootId, out _);
if (root is not ObjectRecordDeserializer parser)
{
return;
}

_parseStack.Push(rootId);
_parserStack.Push(parser);

while (_parserStack.Count > 0)
{
ObjectRecordDeserializer? currentParser = _parserStack.Pop();
SerializationRecordId currentId = _parseStack.Pop();
Debug.Assert(currentId.Equals(currentParser.ObjectRecord.Id));

SerializationRecordId requiredId;
while (!(requiredId = currentParser.Continue()).Equals(default(SerializationRecordId)))
{
// Beside ObjectRecordDeserializer, DeserializeNew can return a raw value like int, string or an array.
if (DeserializeNew(requiredId) is ObjectRecordDeserializer requiredParser)
if (DeserializeNew(requiredId, out bool wasAddedToIncompleteObjects) is ObjectRecordDeserializer requiredParser)
{
// The required object is not complete.

if (_parseStack.Contains(requiredId))
if (!wasAddedToIncompleteObjects)
{
// All objects should be available before they're asked for a second time.
throw new SerializationException(SR.Serialization_Cycle);
}

// Push our current parser.
_parseStack.Push(currentId);
_parserStack.Push(currentParser);

// Push the required parser so we can complete it.
_parseStack.Push(requiredId);
_parserStack.Push(requiredParser);

break;
Expand All @@ -227,7 +220,7 @@ private void DeserializeRoot(SerializationRecordId rootId)

[MethodImpl(MethodImplOptions.AggressiveInlining)]
[RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.ObjectRecordParser.Create(SerializationRecordId, IRecord, IDeserializer)")]
object DeserializeNew(SerializationRecordId id)
object DeserializeNew(SerializationRecordId id, out bool wasAddedToIncompleteObjects)
{
// Strings, string arrays, and primitive arrays can be completed without creating a
// parser object. Single primitives don't normally show up as records unless they are top
Expand All @@ -249,11 +242,12 @@ object DeserializeNew(SerializationRecordId id)
if (value is not null)
{
_deserializedObjects.Add(record.Id, value);
wasAddedToIncompleteObjects = false;

This comment has been minimized.

Copy link
@JeremyKuhne

JeremyKuhne Jun 12, 2024

Member

Why not just throw here?

return value;
}

// Not a simple case, need to do a full deserialization of the record.
_incompleteObjects.Add(id);
wasAddedToIncompleteObjects = _incompleteObjects.Add(id);

var deserializer = ObjectRecordDeserializer.Create(record, this);

Expand Down

0 comments on commit daa7431

Please sign in to comment.