Skip to content

Commit

Permalink
Simplify InputStream constructors in C# (zeroc-ice#3077)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardnormier authored Nov 6, 2024
1 parent b3e5b20 commit a2cbac1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 198 deletions.
216 changes: 45 additions & 171 deletions csharp/src/Ice/InputStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

#nullable enable

using Ice.Internal;
using System.Diagnostics;
using System.Globalization;

using Protocol = Ice.Internal.Protocol;

namespace Ice;
Expand All @@ -26,89 +26,60 @@ public class InputStream
/// Initializes a new instance of the <see cref="InputStream" /> class. This constructor uses the communicator's
/// default encoding version.
/// </summary>
/// <param name="communicator">The communicator to use when initializing the stream.</param>
/// <param name="communicator">The communicator to use when unmarshaling classes, exceptions and proxies.</param>
/// <param name="data">The byte array containing encoded Slice types.</param>
public InputStream(Communicator communicator, byte[] data)
: this(
communicator.instance,
communicator.instance.defaultsAndOverrides().defaultEncoding,
new Internal.Buffer(data))
{
initialize(communicator);
_buf = new Ice.Internal.Buffer(data);
}

/// <summary>
/// Initializes a new instance of the <see cref="InputStream" /> class. This constructor uses the given encoding
/// version.
/// Initializes a new instance of the <see cref="InputStream" /> class.
/// </summary>
/// <param name="communicator">The communicator to use when initializing the stream.</param>
/// <param name="communicator">The communicator to use when unmarshaling classes, exceptions and proxies.</param>
/// <param name="encoding">The desired encoding version.</param>
/// <param name="data">The byte array containing encoded Slice types.</param>
public InputStream(Communicator communicator, EncodingVersion encoding, byte[] data)
: this(communicator.instance, encoding, new Internal.Buffer(data))
{
initialize(communicator, encoding);
_buf = new Ice.Internal.Buffer(data);
}

public InputStream(Ice.Internal.Instance instance, EncodingVersion encoding)
{
initialize(instance, encoding);
_buf = new Ice.Internal.Buffer();
}

public InputStream(Ice.Internal.Instance instance, EncodingVersion encoding, Ice.Internal.Buffer buf, bool adopt)
{
initialize(instance, encoding);
_buf = new Ice.Internal.Buffer(buf, adopt);
}

/// <summary>
/// Initializes the stream to use the communicator's default encoding version.
/// Initializes a new instance of the <see cref="InputStream" /> class with an empty buffer.
/// </summary>
/// <param name="communicator">The communicator to use when initializing the stream.</param>
public void initialize(Communicator communicator)
internal InputStream(Instance instance, EncodingVersion encoding)
: this(instance, encoding, new Internal.Buffer())
{
Debug.Assert(communicator != null);
Ice.Internal.Instance instance = communicator.instance;
initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
}

/// <summary>
/// Initializes the stream to use the given communicator and encoding version.
/// Initializes a new instance of the <see cref="InputStream" /> class while adopting or borrowing the underlying
/// buffer.
/// </summary>
/// <param name="communicator">The communicator to use when initializing the stream.</param>
/// <param name="encoding">The desired encoding version.</param>
public void initialize(Communicator communicator, EncodingVersion encoding)
internal InputStream(Instance instance, EncodingVersion encoding, Internal.Buffer buf, bool adopt)
: this(instance, encoding, new Internal.Buffer(buf, adopt))
{
Debug.Assert(communicator != null);
Ice.Internal.Instance instance = communicator.instance;
initialize(instance, encoding);
}

private void initialize(Ice.Internal.Instance instance, EncodingVersion encoding)
/// <summary>
/// Initializes a new instance of the <see cref="InputStream" /> class. All other constructors delegate to this
/// constructor.
/// </summary>
private InputStream(Instance instance, EncodingVersion encoding, Internal.Buffer buf)
{
initialize(encoding);

_encoding = encoding;
_instance = instance;
_traceSlicing = _instance.traceLevels().slicing > 0;
_buf = buf;
_classGraphDepthMax = _instance.classGraphDepthMax();
_valueFactoryManager = _instance.initializationData().valueFactoryManager;
_logger = _instance.initializationData().logger;
}

private void initialize(EncodingVersion encoding)
{
_instance = null;
_encoding = encoding;
_encapsStack = null;
_encapsCache = null;
_traceSlicing = false;
_classGraphDepthMax = 0x7fffffff;
_closure = null;
_startSeq = -1;
_minSeqSize = 0;
// The communicator initialization always sets a non-null ValueFactoryManager in its initialization data.
_valueFactoryManager = _instance.initializationData().valueFactoryManager!;
}

/// <summary>
/// Resets this stream. This method allows the stream to be reused, to avoid creating
/// unnecessary garbage.
/// Resets this stream. This method allows the stream to be reused, to avoid creating unnecessary garbage.
/// </summary>
public void reset()
{
Expand All @@ -133,75 +104,7 @@ public void clear()
_startSeq = -1;
}

/// <summary>
/// Sets the value factory manager to use when marshaling value instances. If the stream
/// was initialized with a communicator, the communicator's value factory manager will
/// be used by default.
/// </summary>
/// <param name="vfm">The value factory manager.</param>
public void setValueFactoryManager(ValueFactoryManager vfm)
{
_valueFactoryManager = vfm;
}

/// <summary>
/// Sets the logger to use when logging trace messages. If the stream
/// was initialized with a communicator, the communicator's logger will
/// be used by default.
/// </summary>
/// <param name="logger">The logger to use for logging trace messages.</param>
public void setLogger(Logger logger)
{
_logger = logger;
}

/// <summary>
/// Determines whether the stream logs messages about slicing instances of Slice values.
/// </summary>
/// <param name="b">True to enable logging, false to disable logging.</param>
public void setTraceSlicing(bool b)
{
_traceSlicing = b;
}

/// <summary>
/// Set the maximum depth allowed for graph of Slice class instances.
/// </summary>
/// <param name="classGraphDepthMax">The maximum depth.</param>
public void setClassGraphDepthMax(int classGraphDepthMax)
{
if (classGraphDepthMax < 1)
{
_classGraphDepthMax = 0x7fffffff;
}
else
{
_classGraphDepthMax = classGraphDepthMax;
}
}

/// <summary>
/// Retrieves the closure object associated with this stream.
/// </summary>
/// <returns>The closure object.</returns>
public object? getClosure()
{
return _closure;
}

/// <summary>
/// Associates a closure object with this stream.
/// </summary>
/// <param name="p">The new closure object.</param>
/// <returns>The previous closure object, or null.</returns>
public object? setClosure(object p)
{
object? prev = _closure;
_closure = p;
return prev;
}

internal Ice.Internal.Instance? instance() => _instance;
internal Instance instance() => _instance;

/// <summary>
/// Swaps the contents of one stream with another.
Expand All @@ -210,27 +113,18 @@ public void setClassGraphDepthMax(int classGraphDepthMax)
public void swap(InputStream other)
{
Debug.Assert(_instance == other._instance);
// _valueFactoryManager and _classGraphDepthMax come from _instance.
Debug.Assert(_valueFactoryManager == other._valueFactoryManager);
Debug.Assert(_classGraphDepthMax == other._classGraphDepthMax);

Ice.Internal.Buffer tmpBuf = other._buf;
Internal.Buffer tmpBuf = other._buf;
other._buf = _buf;
_buf = tmpBuf;

EncodingVersion tmpEncoding = other._encoding;
other._encoding = _encoding;
_encoding = tmpEncoding;

bool tmpTraceSlicing = other._traceSlicing;
other._traceSlicing = _traceSlicing;
_traceSlicing = tmpTraceSlicing;

object? tmpClosure = other._closure;
other._closure = _closure;
_closure = tmpClosure;

int tmpClassGraphDepthMax = other._classGraphDepthMax;
other._classGraphDepthMax = _classGraphDepthMax;
_classGraphDepthMax = tmpClassGraphDepthMax;

//
// Swap is never called for InputStreams that have encapsulations being read. However,
// encapsulations might still be set in case un-marshaling failed. We just
Expand All @@ -246,14 +140,6 @@ public void swap(InputStream other)
int tmpMinSeqSize = other._minSeqSize;
other._minSeqSize = _minSeqSize;
_minSeqSize = tmpMinSeqSize;

ValueFactoryManager? tmpVfm = other._valueFactoryManager;
other._valueFactoryManager = _valueFactoryManager;
_valueFactoryManager = tmpVfm;

Logger? tmpLogger = other._logger;
other._logger = _logger;
_logger = tmpLogger;
}

private void resetEncapsulation()
Expand All @@ -271,10 +157,7 @@ public void resize(int sz)
_buf.b.position(sz);
}

public Ice.Internal.Buffer getBuffer()
{
return _buf;
}
internal Internal.Buffer getBuffer() => _buf;

/// <summary>
/// Marks the start of a class instance.
Expand Down Expand Up @@ -2144,11 +2027,6 @@ public void readStringSeq(int tag, out bool isset, out string[]? v)
/// <returns>The extracted proxy.</returns>
public ObjectPrx? readProxy()
{
if (_instance is null)
{
throw new MarshalException("cannot unmarshal a proxy without a communicator");
}

var ident = new Identity(this);
if (ident.name.Length == 0)
{
Expand Down Expand Up @@ -2464,17 +2342,16 @@ private bool skipOptionals()
{
try
{
return (UserException?)_instance!.getActivator().CreateInstance(id);
return (UserException?)_instance.getActivator().CreateInstance(id);
}
catch (System.Exception ex)
{
throw new MarshalException($"Failed to create user exception with type ID '{id}'.", ex);
}
}

private Ice.Internal.Instance? _instance;
private Ice.Internal.Buffer _buf;
private object? _closure;
private readonly Instance _instance;
private Internal.Buffer _buf;
private byte[]? _stringBytes; // Reusable array for reading strings.

private enum SliceType
Expand All @@ -2498,7 +2375,7 @@ public PatchEntry(System.Action<Value> cb, int classGraphDepth)
public int classGraphDepth;
}

internal EncapsDecoder(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager? f)
internal EncapsDecoder(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager f)
{
_stream = stream;
_encaps = encaps;
Expand Down Expand Up @@ -2561,7 +2438,7 @@ protected string readTypeId(bool isIndex)
//
// Try to find a factory registered for the specific type.
//
var userFactory = _valueFactoryManager!.find(typeId);
var userFactory = _valueFactoryManager.find(typeId);
Value? v = null;
if (userFactory != null)
{
Expand All @@ -2574,7 +2451,7 @@ protected string readTypeId(bool isIndex)
//
if (v is null)
{
userFactory = _valueFactoryManager!.find("");
userFactory = _valueFactoryManager.find("");
if (userFactory != null)
{
v = userFactory(typeId);
Expand All @@ -2588,7 +2465,7 @@ protected string readTypeId(bool isIndex)
{
try
{
v = (Value?)_stream._instance!.getActivator().CreateInstance(typeId);
v = (Value?)_stream._instance.getActivator().CreateInstance(typeId);
}
catch (System.Exception ex)
{
Expand Down Expand Up @@ -2727,8 +2604,7 @@ protected void unmarshal(int index, Value v)
protected readonly int _classGraphDepthMax;
protected int _classGraphDepth;

// It's null when _instance is null. We can't decode classes/exceptions/proxies in this case.
protected ValueFactoryManager? _valueFactoryManager;
protected ValueFactoryManager _valueFactoryManager;

//
// Encapsulation attributes for object unmarshaling.
Expand All @@ -2742,7 +2618,7 @@ protected void unmarshal(int index, Value v)

private sealed class EncapsDecoder10 : EncapsDecoder
{
internal EncapsDecoder10(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager? f)
internal EncapsDecoder10(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager f)
: base(stream, encaps, classGraphDepthMax, f)
{
_sliceType = SliceType.NoSlice;
Expand Down Expand Up @@ -3047,7 +2923,7 @@ private void readInstance()

private sealed class EncapsDecoder11 : EncapsDecoder
{
internal EncapsDecoder11(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager? f)
internal EncapsDecoder11(InputStream stream, Encaps encaps, int classGraphDepthMax, ValueFactoryManager f)
: base(stream, encaps, classGraphDepthMax, f)
{
_current = null;
Expand Down Expand Up @@ -3656,14 +3532,12 @@ private void initEncaps()
}
}

private bool _traceSlicing;
private int _classGraphDepthMax;
private readonly int _classGraphDepthMax;

private int _startSeq;
private int _startSeq = -1;
private int _minSeqSize;

private ValueFactoryManager? _valueFactoryManager;
private Logger? _logger;
private readonly ValueFactoryManager _valueFactoryManager;

private const string endOfBufferMessage = "Attempting to unmarshal past the end of the buffer.";
}
Loading

0 comments on commit a2cbac1

Please sign in to comment.