/// <summary> /// Add handle to handles map. /// </summary> /// <param name="pos">Position in stream.</param> /// <param name="obj">Object.</param> /// <returns><c>true</c> if object was written as handle.</returns> private bool WriteHandle(long pos, object obj) { if (_hnds == null) { // Cache absolute handle position. _hnds = new PortableHandleDictionary <object, long>(obj, pos); return(false); } long hndPos; if (!_hnds.TryGetValue(obj, out hndPos)) { // Cache absolute handle position. _hnds.Add(obj, pos); return(false); } _stream.WriteByte(PortableUtils.HdrHnd); // Handle is written as difference between position before header and handle position. _stream.WriteInt((int)(pos - hndPos)); return(true); }
/// <summary> /// Merge data from another dictionary without overwrite. /// </summary> /// <param name="that">Other dictionary.</param> public void Merge(PortableHandleDictionary <TK, TV> that) { Debug.Assert(that != null, "that == null"); AddIfAbsent(that._key1, that._val1); AddIfAbsent(that._key2, that._val2); AddIfAbsent(that._key3, that._val3); if (that._dict == null) { return; } foreach (var pair in that._dict) { AddIfAbsent(pair.Key, pair.Value); } }
internal void Write <T>(T obj, object handler) { // Apply detach mode if needed. PortableHandleDictionary <object, long> oldHnds = null; bool resetDetach = false; if (_detach) { _detach = false; _detachMode = true; resetDetach = true; oldHnds = _hnds; _hnds = null; } try { // Write null. if (obj == null) { _stream.WriteByte(PortableUtils.HdrNull); return; } if (_builder != null) { // Special case for portable object during build. PortableUserObject portObj = obj as PortableUserObject; if (portObj != null) { if (!WriteHandle(_stream.Position, portObj)) { _builder.ProcessPortable(_stream, portObj); } return; } // Special case for builder during build. PortableBuilderImpl portBuilder = obj as PortableBuilderImpl; if (portBuilder != null) { if (!WriteHandle(_stream.Position, portBuilder)) { _builder.ProcessBuilder(_stream, portBuilder); } return; } } // Try writting as well-known type. if (InvokeHandler(handler, handler as PortableSystemWriteDelegate, obj)) { return; } Type type = obj.GetType(); IPortableTypeDescriptor desc = _marsh.Descriptor(type); object typedHandler; PortableSystemWriteDelegate untypedHandler; if (desc == null) { typedHandler = null; untypedHandler = PortableSystemHandlers.WriteHandler(type); } else { typedHandler = desc.TypedHandler; untypedHandler = desc.UntypedHandler; } if (InvokeHandler(typedHandler, untypedHandler, obj)) { return; } if (desc == null) { if (!type.IsSerializable) { // If neither handler, nor descriptor exist, and not serializable, this is an exception. throw new PortableException("Unsupported object type [type=" + type + ", object=" + obj + ']'); } Write(new SerializableObjectHolder(obj)); return; } int pos = _stream.Position; // Dealing with handles. if (!(desc.Serializer is IPortableSystemTypeSerializer) && WriteHandle(pos, obj)) { return; } // Write header. _stream.WriteByte(PortableUtils.HdrFull); _stream.WriteBool(desc.UserType); _stream.WriteInt(desc.TypeId); _stream.WriteInt(obj.GetHashCode()); // Skip length as it is not known in the first place. _stream.Seek(8, SeekOrigin.Current); // Preserve old frame. int oldTypeId = _curTypeId; IPortableNameMapper oldConverter = _curConverter; IPortableIdMapper oldMapper = _curMapper; IPortableMetadataHandler oldMetaHnd = _curMetaHnd; bool oldRaw = _curRaw; long oldRawPos = _curRawPos; // Push new frame. _curTypeId = desc.TypeId; _curConverter = desc.NameConverter; _curMapper = desc.Mapper; _curMetaHnd = desc.MetadataEnabled ? _marsh.MetadataHandler(desc) : null; _curRaw = false; _curRawPos = 0; // Write object fields. desc.Serializer.WritePortable(obj, this); // Calculate and write length. int retPos = _stream.Position; _stream.Seek(pos + 10, SeekOrigin.Begin); int len = retPos - pos; _stream.WriteInt(len); if (_curRawPos != 0) { // When set, it is difference between object head and raw position. _stream.WriteInt((int)(_curRawPos - pos)); } else { // When no set, it is equal to object length. _stream.WriteInt(len); } _stream.Seek(retPos, SeekOrigin.Begin); // 13. Collect metadata. if (_curMetaHnd != null) { IDictionary <string, int> meta = _curMetaHnd.OnObjectWriteFinished(); if (meta != null) { SaveMetadata(_curTypeId, desc.TypeName, desc.AffinityKeyFieldName, meta); } } // Restore old frame. _curTypeId = oldTypeId; _curConverter = oldConverter; _curMapper = oldMapper; _curMetaHnd = oldMetaHnd; _curRaw = oldRaw; _curRawPos = oldRawPos; } finally { // Restore handles if needed. if (resetDetach) { // Add newly recorded handles without overriding already existing ones. if (_hnds != null) { if (oldHnds == null) { oldHnds = _hnds; } else { oldHnds.Merge(_hnds); } } _hnds = oldHnds; _detachMode = false; } } }