You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/09/21 16:27:32 UTC
[36/52] [partial] ignite git commit: IGNITE-1513: Moved .Net.
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
new file mode 100644
index 0000000..690f92c
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableHeapStream.cs
@@ -0,0 +1,447 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.IO
+{
+ using System;
+ using System.IO;
+ using System.Text;
+
+ /// <summary>
+ /// Portable onheap stream.
+ /// </summary>
+ internal unsafe class PortableHeapStream : PortableAbstractStream
+ {
+ /** Data array. */
+ protected byte[] Data;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="cap">Initial capacity.</param>
+ public PortableHeapStream(int cap)
+ {
+ Data = new byte[cap];
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="data">Data array.</param>
+ public PortableHeapStream(byte[] data)
+ {
+ Data = data;
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteByte(byte val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(1);
+
+ Data[pos0] = val;
+ }
+
+ /** <inheritdoc /> */
+ public override byte ReadByte()
+ {
+ int pos0 = EnsureReadCapacityAndShift(1);
+
+ return Data[pos0];
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteByteArray(byte[] val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(val.Length);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteByteArray0(val, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override byte[] ReadByteArray(int cnt)
+ {
+ int pos0 = EnsureReadCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadByteArray0(cnt, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteBoolArray(bool[] val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(val.Length);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteBoolArray0(val, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override bool[] ReadBoolArray(int cnt)
+ {
+ int pos0 = EnsureReadCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadBoolArray0(cnt, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteShort(short val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(2);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteShort0(val, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override short ReadShort()
+ {
+ int pos0 = EnsureReadCapacityAndShift(2);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadShort0(data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteShortArray(short[] val)
+ {
+ int cnt = val.Length << 1;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteShortArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override short[] ReadShortArray(int cnt)
+ {
+ int cnt0 = cnt << 1;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadShortArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteCharArray(char[] val)
+ {
+ int cnt = val.Length << 1;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteCharArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override char[] ReadCharArray(int cnt)
+ {
+ int cnt0 = cnt << 1;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadCharArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteInt(int val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(4);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteInt0(val, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteInt(int writePos, int val)
+ {
+ EnsureWriteCapacity(writePos + 4);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteInt0(val, data0 + writePos);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override int ReadInt()
+ {
+ int pos0 = EnsureReadCapacityAndShift(4);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadInt0(data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteIntArray(int[] val)
+ {
+ int cnt = val.Length << 2;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteIntArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override int[] ReadIntArray(int cnt)
+ {
+ int cnt0 = cnt << 2;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadIntArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteFloatArray(float[] val)
+ {
+ int cnt = val.Length << 2;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteFloatArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override float[] ReadFloatArray(int cnt)
+ {
+ int cnt0 = cnt << 2;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadFloatArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteLong(long val)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(8);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteLong0(val, data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override long ReadLong()
+ {
+ int pos0 = EnsureReadCapacityAndShift(8);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadLong0(data0 + pos0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteLongArray(long[] val)
+ {
+ int cnt = val.Length << 3;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteLongArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override long[] ReadLongArray(int cnt)
+ {
+ int cnt0 = cnt << 3;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadLongArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override void WriteDoubleArray(double[] val)
+ {
+ int cnt = val.Length << 3;
+
+ int pos0 = EnsureWriteCapacityAndShift(cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteDoubleArray0(val, data0 + pos0, cnt);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override double[] ReadDoubleArray(int cnt)
+ {
+ int cnt0 = cnt << 3;
+
+ int pos0 = EnsureReadCapacityAndShift(cnt0);
+
+ fixed (byte* data0 = Data)
+ {
+ return ReadDoubleArray0(cnt, data0 + pos0, cnt0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override int WriteString(char* chars, int charCnt, int byteCnt, Encoding encoding)
+ {
+ int pos0 = EnsureWriteCapacityAndShift(byteCnt);
+
+ int written;
+
+ fixed (byte* data0 = Data)
+ {
+ written = WriteString0(chars, charCnt, byteCnt, encoding, data0 + pos0);
+ }
+
+ return written;
+ }
+
+ /** <inheritdoc /> */
+ public override void Write(byte* src, int cnt)
+ {
+ EnsureWriteCapacity(Pos + cnt);
+
+ fixed (byte* data0 = Data)
+ {
+ WriteInternal(src, cnt, data0);
+ }
+
+ ShiftWrite(cnt);
+ }
+
+ /** <inheritdoc /> */
+ public override void Read(byte* dest, int cnt)
+ {
+ fixed (byte* data0 = Data)
+ {
+ ReadInternal(dest, cnt, data0);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override int Remaining()
+ {
+ return Data.Length - Pos;
+ }
+
+ /** <inheritdoc /> */
+ public override byte[] Array()
+ {
+ return Data;
+ }
+
+ /** <inheritdoc /> */
+ public override byte[] ArrayCopy()
+ {
+ byte[] copy = new byte[Pos];
+
+ Buffer.BlockCopy(Data, 0, copy, 0, Pos);
+
+ return copy;
+ }
+
+ /** <inheritdoc /> */
+ public override bool IsSameArray(byte[] arr)
+ {
+ return Data == arr;
+ }
+
+ /** <inheritdoc /> */
+ protected override void Dispose(bool disposing)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Internal array.
+ /// </summary>
+ internal byte[] InternalArray
+ {
+ get { return Data; }
+ }
+
+ /** <inheritdoc /> */
+ protected override void EnsureWriteCapacity(int cnt)
+ {
+ if (cnt > Data.Length)
+ {
+ int newCap = Capacity(Data.Length, cnt);
+
+ byte[] data0 = new byte[newCap];
+
+ // Copy the whole initial array length here because it can be changed
+ // from Java without position adjusting.
+ Buffer.BlockCopy(Data, 0, data0, 0, Data.Length);
+
+ Data = data0;
+ }
+ }
+
+ /** <inheritdoc /> */
+ protected override void EnsureReadCapacity(int cnt)
+ {
+ if (Data.Length - Pos < cnt)
+ throw new EndOfStreamException("Not enough data in stream [expected=" + cnt +
+ ", remaining=" + (Data.Length - Pos) + ']');
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
new file mode 100644
index 0000000..1d17f89
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Io/PortableStreamAdapter.cs
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.IO
+{
+ using System;
+ using System.IO;
+
+ /// <summary>
+ /// Adapter providing .Net streaming functionality over the portable stream.
+ /// </summary>
+ internal class PortableStreamAdapter : Stream
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ private readonly IPortableStream _stream;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="stream">Stream.</param>
+ public PortableStreamAdapter(IPortableStream stream)
+ {
+ _stream = stream;
+ }
+
+ /** <inheritDoc /> */
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ _stream.Write(buffer, offset, count);
+ }
+
+ /** <inheritDoc /> */
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ _stream.Read(buffer, offset, count);
+
+ return count;
+ }
+
+ /** <inheritDoc /> */
+ public override void Flush()
+ {
+ // No-op.
+ }
+
+ /** <inheritDoc /> */
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ /** <inheritDoc /> */
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ /** <inheritDoc /> */
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ /** <inheritDoc /> */
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("Stream is not seekable.");
+ }
+
+ /** <inheritDoc /> */
+ public override long Position
+ {
+ get
+ {
+ throw new NotSupportedException("Stream is not seekable.");
+ }
+ set
+ {
+ throw new NotSupportedException("Stream is not seekable.");
+ }
+ }
+
+ /** <inheritDoc /> */
+ public override long Length
+ {
+ get
+ {
+ throw new NotSupportedException("Stream is not seekable.");
+ }
+ }
+
+ /** <inheritDoc /> */
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException("Stream is not seekable.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
new file mode 100644
index 0000000..dc3090f
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/IPortableMetadataHandler.cs
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.Metadata
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Portable metadata handler.
+ /// </summary>
+ public interface IPortableMetadataHandler
+ {
+ /// <summary>
+ /// Callback invoked when named field is written.
+ /// </summary>
+ /// <param name="fieldId">Field ID.</param>
+ /// <param name="fieldName">Field name.</param>
+ /// <param name="typeId">Field type ID.</param>
+ void OnFieldWrite(int fieldId, string fieldName, int typeId);
+
+ /// <summary>
+ /// Callback invoked when object write is finished and it is time to collect missing metadata.
+ /// </summary>
+ /// <returns>Collected metadata.</returns>
+ IDictionary<string, int> OnObjectWriteFinished();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
new file mode 100644
index 0000000..8df5f36
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableHashsetMetadataHandler.cs
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.Metadata
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Metadata handler which uses hash set to determine whether field was already written or not.
+ /// </summary>
+ internal class PortableHashsetMetadataHandler : IPortableMetadataHandler
+ {
+ /** Empty fields collection. */
+ private static readonly IDictionary<string, int> EmptyFields = new Dictionary<string, int>();
+
+ /** IDs known when serialization starts. */
+ private readonly ICollection<int> _ids;
+
+ /** New fields. */
+ private IDictionary<string, int> _fieldMap;
+
+ /** */
+ private readonly bool _newType;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="ids">IDs.</param>
+ /// <param name="newType">True is metadata for type is not saved.</param>
+ public PortableHashsetMetadataHandler(ICollection<int> ids, bool newType)
+ {
+ _ids = ids;
+ _newType = newType;
+ }
+
+ /** <inheritdoc /> */
+ public void OnFieldWrite(int fieldId, string fieldName, int typeId)
+ {
+ if (!_ids.Contains(fieldId))
+ {
+ if (_fieldMap == null)
+ _fieldMap = new Dictionary<string, int>();
+
+ if (!_fieldMap.ContainsKey(fieldName))
+ _fieldMap[fieldName] = typeId;
+ }
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<string, int> OnObjectWriteFinished()
+ {
+ return _fieldMap ?? (_newType ? EmptyFields : null);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
new file mode 100644
index 0000000..a3fa90f
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataHolder.cs
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.Metadata
+{
+ using System;
+ using System.Collections.Generic;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Metadata for particular type.
+ /// </summary>
+ internal class PortableMetadataHolder
+ {
+ /** Type ID. */
+ private readonly int _typeId;
+
+ /** Type name. */
+ private readonly string _typeName;
+
+ /** Affinity key field name. */
+ private readonly string _affKeyFieldName;
+
+ /** Empty metadata when nothig is know about object fields yet. */
+ private readonly IPortableMetadata _emptyMeta;
+
+ /** Collection of know field IDs. */
+ private volatile ICollection<int> _ids;
+
+ /** Last known unmodifiable metadata which is given to the user. */
+ private volatile PortableMetadataImpl _meta;
+
+ /** Saved flag (set if type metadata was saved at least once). */
+ private volatile bool _saved;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="typeName">Type name.</param>
+ /// <param name="affKeyFieldName">Affinity key field name.</param>
+ public PortableMetadataHolder(int typeId, string typeName, string affKeyFieldName)
+ {
+ _typeId = typeId;
+ _typeName = typeName;
+ _affKeyFieldName = affKeyFieldName;
+
+ _emptyMeta = new PortableMetadataImpl(typeId, typeName, null, affKeyFieldName);
+ }
+
+ /// <summary>
+ /// Get saved flag.
+ /// </summary>
+ /// <returns>True if type metadata was saved at least once.</returns>
+ public bool Saved()
+ {
+ return _saved;
+ }
+
+ /// <summary>
+ /// Get current type metadata.
+ /// </summary>
+ /// <returns>Type metadata.</returns>
+ public IPortableMetadata Metadata()
+ {
+ PortableMetadataImpl meta0 = _meta;
+
+ return meta0 != null ? _meta : _emptyMeta;
+ }
+
+ /// <summary>
+ /// Currently cached field IDs.
+ /// </summary>
+ /// <returns>Cached field IDs.</returns>
+ public ICollection<int> FieldIds()
+ {
+ ICollection<int> ids0 = _ids;
+
+ if (_ids == null)
+ {
+ lock (this)
+ {
+ ids0 = _ids;
+
+ if (ids0 == null)
+ {
+ ids0 = new HashSet<int>();
+
+ _ids = ids0;
+ }
+ }
+ }
+
+ return ids0;
+ }
+
+ /// <summary>
+ /// Merge newly sent field metadatas into existing ones.
+ /// </summary>
+ /// <param name="newMap">New field metadatas map.</param>
+ public void Merge(IDictionary<int, Tuple<string, int>> newMap)
+ {
+ _saved = true;
+
+ if (newMap == null || newMap.Count == 0)
+ return;
+
+ lock (this)
+ {
+ // 1. Create copies of the old meta.
+ ICollection<int> ids0 = _ids;
+ PortableMetadataImpl meta0 = _meta;
+
+ ICollection<int> newIds = ids0 != null ? new HashSet<int>(ids0) : new HashSet<int>();
+
+ IDictionary<string, int> newFields = meta0 != null ?
+ new Dictionary<string, int>(meta0.FieldsMap()) : new Dictionary<string, int>(newMap.Count);
+
+ // 2. Add new fields.
+ foreach (KeyValuePair<int, Tuple<string, int>> newEntry in newMap)
+ {
+ if (!newIds.Contains(newEntry.Key))
+ newIds.Add(newEntry.Key);
+
+ if (!newFields.ContainsKey(newEntry.Value.Item1))
+ newFields[newEntry.Value.Item1] = newEntry.Value.Item2;
+ }
+
+ // 3. Assign new meta. Order is important here: meta must be assigned before field IDs.
+ _meta = new PortableMetadataImpl(_typeId, _typeName, newFields, _affKeyFieldName);
+ _ids = newIds;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
new file mode 100644
index 0000000..06578c0
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/Metadata/PortableMetadataImpl.cs
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable.Metadata
+{
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable metadata implementation.
+ /// </summary>
+ internal class PortableMetadataImpl : IPortableMetadata
+ {
+ /** Empty metadata. */
+ [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
+ public static readonly PortableMetadataImpl EmptyMeta =
+ new PortableMetadataImpl(PortableUtils.TypeObject, PortableTypeNames.TypeNameObject, null, null);
+
+ /** Empty dictionary. */
+ private static readonly IDictionary<string, int> EmptyDict = new Dictionary<string, int>();
+
+ /** Empty list. */
+ private static readonly ICollection<string> EmptyList = new List<string>().AsReadOnly();
+
+ /** Fields. */
+ private readonly IDictionary<string, int> _fields;
+
+ /// <summary>
+ /// Get type name by type ID.
+ /// </summary>
+ /// <param name="typeId">Type ID.</param>
+ /// <returns>Type name.</returns>
+ private static string ConvertTypeName(int typeId)
+ {
+ switch (typeId)
+ {
+ case PortableUtils.TypeBool:
+ return PortableTypeNames.TypeNameBool;
+ case PortableUtils.TypeByte:
+ return PortableTypeNames.TypeNameByte;
+ case PortableUtils.TypeShort:
+ return PortableTypeNames.TypeNameShort;
+ case PortableUtils.TypeChar:
+ return PortableTypeNames.TypeNameChar;
+ case PortableUtils.TypeInt:
+ return PortableTypeNames.TypeNameInt;
+ case PortableUtils.TypeLong:
+ return PortableTypeNames.TypeNameLong;
+ case PortableUtils.TypeFloat:
+ return PortableTypeNames.TypeNameFloat;
+ case PortableUtils.TypeDouble:
+ return PortableTypeNames.TypeNameDouble;
+ case PortableUtils.TypeDecimal:
+ return PortableTypeNames.TypeNameDecimal;
+ case PortableUtils.TypeString:
+ return PortableTypeNames.TypeNameString;
+ case PortableUtils.TypeGuid:
+ return PortableTypeNames.TypeNameGuid;
+ case PortableUtils.TypeDate:
+ return PortableTypeNames.TypeNameDate;
+ case PortableUtils.TypeEnum:
+ return PortableTypeNames.TypeNameEnum;
+ case PortableUtils.TypePortable:
+ case PortableUtils.TypeObject:
+ return PortableTypeNames.TypeNameObject;
+ case PortableUtils.TypeArrayBool:
+ return PortableTypeNames.TypeNameArrayBool;
+ case PortableUtils.TypeArrayByte:
+ return PortableTypeNames.TypeNameArrayByte;
+ case PortableUtils.TypeArrayShort:
+ return PortableTypeNames.TypeNameArrayShort;
+ case PortableUtils.TypeArrayChar:
+ return PortableTypeNames.TypeNameArrayChar;
+ case PortableUtils.TypeArrayInt:
+ return PortableTypeNames.TypeNameArrayInt;
+ case PortableUtils.TypeArrayLong:
+ return PortableTypeNames.TypeNameArrayLong;
+ case PortableUtils.TypeArrayFloat:
+ return PortableTypeNames.TypeNameArrayFloat;
+ case PortableUtils.TypeArrayDouble:
+ return PortableTypeNames.TypeNameArrayDouble;
+ case PortableUtils.TypeArrayDecimal:
+ return PortableTypeNames.TypeNameArrayDecimal;
+ case PortableUtils.TypeArrayString:
+ return PortableTypeNames.TypeNameArrayString;
+ case PortableUtils.TypeArrayGuid:
+ return PortableTypeNames.TypeNameArrayGuid;
+ case PortableUtils.TypeArrayDate:
+ return PortableTypeNames.TypeNameArrayDate;
+ case PortableUtils.TypeArrayEnum:
+ return PortableTypeNames.TypeNameArrayEnum;
+ case PortableUtils.TypeArray:
+ return PortableTypeNames.TypeNameArrayObject;
+ case PortableUtils.TypeCollection:
+ return PortableTypeNames.TypeNameCollection;
+ case PortableUtils.TypeDictionary:
+ return PortableTypeNames.TypeNameMap;
+ default:
+ throw new PortableException("Invalid type ID: " + typeId);
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PortableMetadataImpl" /> class.
+ /// </summary>
+ /// <param name="reader">The reader.</param>
+ public PortableMetadataImpl(IPortableRawReader reader)
+ {
+ TypeId = reader.ReadInt();
+ TypeName = reader.ReadString();
+ AffinityKeyFieldName = reader.ReadString();
+ _fields = reader.ReadGenericDictionary<string, int>();
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="typeName">Type name.</param>
+ /// <param name="fields">Fields.</param>
+ /// <param name="affKeyFieldName">Affinity key field name.</param>
+ public PortableMetadataImpl(int typeId, string typeName, IDictionary<string, int> fields,
+ string affKeyFieldName)
+ {
+ TypeId = typeId;
+ TypeName = typeName;
+ AffinityKeyFieldName = affKeyFieldName;
+ _fields = fields;
+ }
+
+ /// <summary>
+ /// Type ID.
+ /// </summary>
+ /// <returns></returns>
+ public int TypeId { get; private set; }
+
+ /// <summary>
+ /// Gets type name.
+ /// </summary>
+ public string TypeName { get; private set; }
+
+ /// <summary>
+ /// Gets field names for that type.
+ /// </summary>
+ public ICollection<string> Fields
+ {
+ get { return _fields != null ? _fields.Keys : EmptyList; }
+ }
+
+ /// <summary>
+ /// Gets field type for the given field name.
+ /// </summary>
+ /// <param name="fieldName">Field name.</param>
+ /// <returns>
+ /// Field type.
+ /// </returns>
+ public string GetFieldTypeName(string fieldName)
+ {
+ if (_fields != null)
+ {
+ int typeId;
+
+ _fields.TryGetValue(fieldName, out typeId);
+
+ return ConvertTypeName(typeId);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets optional affinity key field name.
+ /// </summary>
+ public string AffinityKeyFieldName { get; private set; }
+
+ /// <summary>
+ /// Gets fields map.
+ /// </summary>
+ /// <returns>Fields map.</returns>
+ public IDictionary<string, int> FieldsMap()
+ {
+ return _fields ?? EmptyDict;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
new file mode 100644
index 0000000..026d0d4
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderField.cs
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+
+ /// <summary>
+ /// Portable builder field.
+ /// </summary>
+ internal class PortableBuilderField
+ {
+ /** Remove marker object. */
+ public static readonly object RmvMarkerObj = new object();
+
+ /** Remove marker. */
+ public static readonly PortableBuilderField RmvMarker =
+ new PortableBuilderField(null, RmvMarkerObj);
+
+ /** Type. */
+ private readonly Type _typ;
+
+ /** Value. */
+ private readonly object _val;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="typ">Type.</param>
+ /// <param name="val">Value.</param>
+ public PortableBuilderField(Type typ, object val)
+ {
+ _typ = typ;
+ _val = val;
+ }
+
+ /// <summary>
+ /// Type.
+ /// </summary>
+ public Type Type
+ {
+ get
+ {
+ return _typ;
+ }
+ }
+
+ /// <summary>
+ /// Value.
+ /// </summary>
+ public object Value
+ {
+ get
+ {
+ return _val;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
new file mode 100644
index 0000000..dc0f570
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
@@ -0,0 +1,923 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Impl.Portable.Metadata;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable builder implementation.
+ /// </summary>
+ internal class PortableBuilderImpl : IPortableBuilder
+ {
+ /** Type IDs for metadata. */
+ private static readonly IDictionary<Type, int> TypeIds;
+
+ /** Cached dictionary with no values. */
+ private static readonly IDictionary<int, object> EmptyVals = new Dictionary<int, object>();
+
+ /** Offset: length. */
+ private const int OffsetLen = 10;
+
+ /** Portables. */
+ private readonly PortablesImpl _portables;
+
+ /** */
+ private readonly PortableBuilderImpl _parent;
+
+ /** Initial portable object. */
+ private readonly PortableUserObject _obj;
+
+ /** Type descriptor. */
+ private readonly IPortableTypeDescriptor _desc;
+
+ /** Values. */
+ private IDictionary<string, PortableBuilderField> _vals;
+
+ /** Contextual fields. */
+ private IDictionary<int, object> _cache;
+
+ /** Hash code. */
+ private int _hashCode;
+
+ /** Current context. */
+ private Context _ctx;
+
+ /// <summary>
+ /// Static initializer.
+ /// </summary>
+ static PortableBuilderImpl()
+ {
+ TypeIds = new Dictionary<Type, int>();
+
+ // 1. Primitives.
+ TypeIds[typeof(byte)] = PortableUtils.TypeByte;
+ TypeIds[typeof(bool)] = PortableUtils.TypeBool;
+ TypeIds[typeof(short)] = PortableUtils.TypeShort;
+ TypeIds[typeof(char)] = PortableUtils.TypeChar;
+ TypeIds[typeof(int)] = PortableUtils.TypeInt;
+ TypeIds[typeof(long)] = PortableUtils.TypeLong;
+ TypeIds[typeof(float)] = PortableUtils.TypeFloat;
+ TypeIds[typeof(double)] = PortableUtils.TypeDouble;
+ TypeIds[typeof(decimal)] = PortableUtils.TypeDecimal;
+
+ TypeIds[typeof(byte[])] = PortableUtils.TypeArrayByte;
+ TypeIds[typeof(bool[])] = PortableUtils.TypeArrayBool;
+ TypeIds[typeof(short[])] = PortableUtils.TypeArrayShort;
+ TypeIds[typeof(char[])] = PortableUtils.TypeArrayChar;
+ TypeIds[typeof(int[])] = PortableUtils.TypeArrayInt;
+ TypeIds[typeof(long[])] = PortableUtils.TypeArrayLong;
+ TypeIds[typeof(float[])] = PortableUtils.TypeArrayFloat;
+ TypeIds[typeof(double[])] = PortableUtils.TypeArrayDouble;
+ TypeIds[typeof(decimal[])] = PortableUtils.TypeArrayDecimal;
+
+ // 2. String.
+ TypeIds[typeof(string)] = PortableUtils.TypeString;
+ TypeIds[typeof(string[])] = PortableUtils.TypeArrayString;
+
+ // 3. Guid.
+ TypeIds[typeof(Guid)] = PortableUtils.TypeGuid;
+ TypeIds[typeof(Guid?)] = PortableUtils.TypeGuid;
+ TypeIds[typeof(Guid[])] = PortableUtils.TypeArrayGuid;
+ TypeIds[typeof(Guid?[])] = PortableUtils.TypeArrayGuid;
+
+ // 4. Date.
+ TypeIds[typeof(DateTime)] = PortableUtils.TypeDate;
+ TypeIds[typeof(DateTime?)] = PortableUtils.TypeDate;
+ TypeIds[typeof(DateTime[])] = PortableUtils.TypeArrayDate;
+ TypeIds[typeof(DateTime?[])] = PortableUtils.TypeArrayDate;
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="portables">Portables.</param>
+ /// <param name="obj">Initial portable object.</param>
+ /// <param name="desc">Type descriptor.</param>
+ public PortableBuilderImpl(PortablesImpl portables, PortableUserObject obj,
+ IPortableTypeDescriptor desc) : this(portables, null, obj, desc)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="portables">Portables.</param>
+ /// <param name="parent">Parent builder.</param>
+ /// <param name="obj">Initial portable object.</param>
+ /// <param name="desc">Type descriptor.</param>
+ public PortableBuilderImpl(PortablesImpl portables, PortableBuilderImpl parent,
+ PortableUserObject obj, IPortableTypeDescriptor desc)
+ {
+ _portables = portables;
+ _parent = parent ?? this;
+ _obj = obj;
+ _desc = desc;
+
+ _hashCode = obj.GetHashCode();
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder SetHashCode(int hashCode)
+ {
+ _hashCode = hashCode;
+
+ return this;
+ }
+
+ /** <inheritDoc /> */
+ public T GetField<T>(string name)
+ {
+ PortableBuilderField field;
+
+ if (_vals != null && _vals.TryGetValue(name, out field))
+ return field != PortableBuilderField.RmvMarker ? (T)field.Value : default(T);
+ T val = _obj.Field<T>(name, this);
+
+ if (_vals == null)
+ _vals = new Dictionary<string, PortableBuilderField>(2);
+
+ _vals[name] = new PortableBuilderField(typeof(T), val);
+
+ return val;
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder SetField<T>(string name, T val)
+ {
+ return SetField0(name, new PortableBuilderField(typeof(T), val));
+ }
+
+ /** <inheritDoc /> */
+ public IPortableBuilder RemoveField(string name)
+ {
+ return SetField0(name, PortableBuilderField.RmvMarker);
+ }
+
+ /** <inheritDoc /> */
+ public IPortableObject Build()
+ {
+ PortableHeapStream inStream = new PortableHeapStream(_obj.Data);
+
+ inStream.Seek(_obj.Offset, SeekOrigin.Begin);
+
+ // Assume that resulting length will be no less than header + [fields_cnt] * 12;
+ int len = PortableUtils.FullHdrLen + (_vals == null ? 0 : _vals.Count * 12);
+
+ PortableHeapStream outStream = new PortableHeapStream(len);
+
+ PortableWriterImpl writer = _portables.Marshaller.StartMarshal(outStream);
+
+ writer.Builder(this);
+
+ // All related builders will work in this context with this writer.
+ _parent._ctx = new Context(writer);
+
+ try
+ {
+ // Write.
+ writer.Write(this, null);
+
+ // Process metadata.
+ _portables.Marshaller.FinishMarshal(writer);
+
+ // Create portable object once metadata is processed.
+ return new PortableUserObject(_portables.Marshaller, outStream.InternalArray, 0,
+ _desc.TypeId, _hashCode);
+ }
+ finally
+ {
+ // Cleanup.
+ _parent._ctx.Closed = true;
+ }
+ }
+
+ /// <summary>
+ /// Create child builder.
+ /// </summary>
+ /// <param name="obj">Portable object.</param>
+ /// <returns>Child builder.</returns>
+ public PortableBuilderImpl Child(PortableUserObject obj)
+ {
+ return _portables.ChildBuilder(_parent, obj);
+ }
+
+ /// <summary>
+ /// Get cache field.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="val">Value.</param>
+ /// <returns><c>true</c> if value is found in cache.</returns>
+ public bool CachedField<T>(int pos, out T val)
+ {
+ if (_parent._cache != null)
+ {
+ object res;
+
+ if (_parent._cache.TryGetValue(pos, out res))
+ {
+ val = res != null ? (T)res : default(T);
+
+ return true;
+ }
+ }
+
+ val = default(T);
+
+ return false;
+ }
+
+ /// <summary>
+ /// Add field to cache test.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="val">Value.</param>
+ public void CacheField(int pos, object val)
+ {
+ if (_parent._cache == null)
+ _parent._cache = new Dictionary<int, object>(2);
+
+ _parent._cache[pos] = val;
+ }
+
+ /// <summary>
+ /// Internal set field routine.
+ /// </summary>
+ /// <param name="fieldName">Name.</param>
+ /// <param name="val">Value.</param>
+ /// <returns>This builder.</returns>
+ private IPortableBuilder SetField0(string fieldName, PortableBuilderField val)
+ {
+ if (_vals == null)
+ _vals = new Dictionary<string, PortableBuilderField>();
+
+ _vals[fieldName] = val;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Mutate portable object.
+ /// </summary>
+ /// <param name="inStream">Input stream with initial object.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="desc">Portable type descriptor.</param>
+ /// <param name="hashCode">Hash code.</param>
+ /// <param name="vals">Values.</param>
+ internal void Mutate(
+ PortableHeapStream inStream,
+ PortableHeapStream outStream,
+ IPortableTypeDescriptor desc,
+ int hashCode,
+ IDictionary<string, PortableBuilderField> vals)
+ {
+ // Set correct builder to writer frame.
+ PortableBuilderImpl oldBuilder = _parent._ctx.Writer.Builder(_parent);
+
+ int streamPos = inStream.Position;
+
+ try
+ {
+ // Prepare fields.
+ IPortableMetadataHandler metaHnd = _portables.Marshaller.MetadataHandler(desc);
+
+ IDictionary<int, object> vals0;
+
+ if (vals == null || vals.Count == 0)
+ vals0 = EmptyVals;
+ else
+ {
+ vals0 = new Dictionary<int, object>(vals.Count);
+
+ foreach (KeyValuePair<string, PortableBuilderField> valEntry in vals)
+ {
+ int fieldId = PortableUtils.FieldId(desc.TypeId, valEntry.Key, desc.NameConverter, desc.Mapper);
+
+ if (vals0.ContainsKey(fieldId))
+ throw new IgniteException("Collision in field ID detected (change field name or " +
+ "define custom ID mapper) [fieldName=" + valEntry.Key + ", fieldId=" + fieldId + ']');
+
+ vals0[fieldId] = valEntry.Value.Value;
+
+ // Write metadata if: 1) it is enabled for type; 2) type is not null (i.e. it is neither
+ // remove marker, nor a field read through "GetField" method.
+ if (metaHnd != null && valEntry.Value.Type != null)
+ metaHnd.OnFieldWrite(fieldId, valEntry.Key, TypeId(valEntry.Value.Type));
+ }
+ }
+
+ // Actual processing.
+ Mutate0(_parent._ctx, inStream, outStream, true, hashCode, vals0);
+
+ // 3. Handle metadata.
+ if (metaHnd != null)
+ {
+ IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
+
+ if (meta != null)
+ _parent._ctx.Writer.SaveMetadata(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+ }
+ }
+ finally
+ {
+ // Restore builder frame.
+ _parent._ctx.Writer.Builder(oldBuilder);
+
+ inStream.Seek(streamPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Internal mutation routine.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="ctx">Context.</param>
+ /// <param name="changeHash">WHether hash should be changed.</param>
+ /// <param name="hash">New hash.</param>
+ /// <param name="vals">Values to be replaced.</param>
+ /// <returns>Mutated object.</returns>
+ private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream,
+ bool changeHash, int hash, IDictionary<int, object> vals)
+ {
+ int inStartPos = inStream.Position;
+ int outStartPos = outStream.Position;
+
+ byte inHdr = inStream.ReadByte();
+
+ if (inHdr == PortableUtils.HdrNull)
+ outStream.WriteByte(PortableUtils.HdrNull);
+ else if (inHdr == PortableUtils.HdrHnd)
+ {
+ int inHnd = inStream.ReadInt();
+
+ int oldPos = inStartPos - inHnd;
+ int newPos;
+
+ if (ctx.OldToNew(oldPos, out newPos))
+ {
+ // Handle is still valid.
+ outStream.WriteByte(PortableUtils.HdrHnd);
+ outStream.WriteInt(outStartPos - newPos);
+ }
+ else
+ {
+ // Handle is invalid, write full object.
+ int inRetPos = inStream.Position;
+
+ inStream.Seek(oldPos, SeekOrigin.Begin);
+
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ inStream.Seek(inRetPos, SeekOrigin.Begin);
+ }
+ }
+ else if (inHdr == PortableUtils.HdrFull)
+ {
+ byte inUsrFlag = inStream.ReadByte();
+ int inTypeId = inStream.ReadInt();
+ int inHash = inStream.ReadInt();
+ int inLen = inStream.ReadInt();
+ int inRawOff = inStream.ReadInt();
+
+ int hndPos;
+
+ if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos))
+ {
+ // Object could be cached in parent builder.
+ object cachedVal;
+
+ if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) {
+ ctx.Writer.Write(cachedVal, null);
+ }
+ else
+ {
+ // New object, write in full form.
+ outStream.WriteByte(PortableUtils.HdrFull);
+ outStream.WriteByte(inUsrFlag);
+ outStream.WriteInt(inTypeId);
+ outStream.WriteInt(changeHash ? hash : inHash);
+
+ // Skip length and raw offset as they are not known at this point.
+ outStream.Seek(8, SeekOrigin.Current);
+
+ // Write regular fields.
+ while (inStream.Position < inStartPos + inRawOff)
+ {
+ int inFieldId = inStream.ReadInt();
+ int inFieldLen = inStream.ReadInt();
+ int inFieldDataPos = inStream.Position;
+
+ object fieldVal;
+
+ bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal);
+
+ if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj)
+ {
+ outStream.WriteInt(inFieldId);
+
+ int fieldLenPos = outStream.Position; // Here we will write length later.
+
+ outStream.Seek(4, SeekOrigin.Current);
+
+ if (fieldFound)
+ {
+ // Replace field with new value.
+ if (fieldVal != PortableBuilderField.RmvMarkerObj)
+ ctx.Writer.Write(fieldVal, null);
+
+ vals.Remove(inFieldId);
+ }
+ else
+ {
+ // If field was requested earlier, then we must write tracked value
+ if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal))
+ ctx.Writer.Write(fieldVal, null);
+ else
+ // Filed is not tracked, re-write as is.
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ }
+
+ int fieldEndPos = outStream.Position;
+
+ outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+ outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+ outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+ }
+
+ // Position intput stream pointer after the field.
+ inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin);
+ }
+
+ // Write remaining new fields.
+ foreach (KeyValuePair<int, object> valEntry in vals)
+ {
+ if (valEntry.Value != PortableBuilderField.RmvMarkerObj)
+ {
+ outStream.WriteInt(valEntry.Key);
+
+ int fieldLenPos = outStream.Position; // Here we will write length later.
+
+ outStream.Seek(4, SeekOrigin.Current);
+
+ ctx.Writer.Write(valEntry.Value, null);
+
+ int fieldEndPos = outStream.Position;
+
+ outStream.Seek(fieldLenPos, SeekOrigin.Begin);
+ outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
+ outStream.Seek(fieldEndPos, SeekOrigin.Begin);
+ }
+ }
+
+ // Write raw data.
+ int rawPos = outStream.Position;
+
+ outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff);
+
+ // Write length and raw data offset.
+ int outResPos = outStream.Position;
+
+ outStream.Seek(outStartPos + OffsetLen, SeekOrigin.Begin);
+
+ outStream.WriteInt(outResPos - outStartPos); // Length.
+ outStream.WriteInt(rawPos - outStartPos); // Raw offset.
+
+ outStream.Seek(outResPos, SeekOrigin.Begin);
+ }
+ }
+ else
+ {
+ // Object has already been written, write as handle.
+ outStream.WriteByte(PortableUtils.HdrHnd);
+ outStream.WriteInt(outStartPos - hndPos);
+ }
+
+ // Synchronize input stream position.
+ inStream.Seek(inStartPos + inLen, SeekOrigin.Begin);
+ }
+ else
+ {
+ // Try writing as well-known type with fixed size.
+ outStream.WriteByte(inHdr);
+
+ if (!WriteAsPredefined(inHdr, inStream, outStream, ctx))
+ throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) +
+ ", header=" + inHdr + ']');
+ }
+ }
+
+ /// <summary>
+ /// Process portable object inverting handles if needed.
+ /// </summary>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="port">Portable.</param>
+ internal void ProcessPortable(IPortableStream outStream, PortableUserObject port)
+ {
+ // Special case: writing portable object with correct inversions.
+ PortableHeapStream inStream = new PortableHeapStream(port.Data);
+
+ inStream.Seek(port.Offset, SeekOrigin.Begin);
+
+ // Use fresh context to ensure correct portable inversion.
+ Mutate0(new Context(), inStream, outStream, false, 0, EmptyVals);
+ }
+
+ /// <summary>
+ /// Process child builder.
+ /// </summary>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="builder">Builder.</param>
+ internal void ProcessBuilder(IPortableStream outStream, PortableBuilderImpl builder)
+ {
+ PortableHeapStream inStream = new PortableHeapStream(builder._obj.Data);
+
+ inStream.Seek(builder._obj.Offset, SeekOrigin.Begin);
+
+ // Builder parent context might be null only in one case: if we never met this group of
+ // builders before. In this case we set context to their parent and track it. Context
+ // cleanup will be performed at the very end of build process.
+ if (builder._parent._ctx == null || builder._parent._ctx.Closed)
+ builder._parent._ctx = new Context(_parent._ctx);
+
+ builder.Mutate(inStream, outStream as PortableHeapStream, builder._desc,
+ builder._hashCode, builder._vals);
+ }
+
+ /// <summary>
+ /// Write object as a predefined type if possible.
+ /// </summary>
+ /// <param name="hdr">Header.</param>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="ctx">Context.</param>
+ /// <returns><c>True</c> if was written.</returns>
+ private bool WriteAsPredefined(byte hdr, PortableHeapStream inStream, IPortableStream outStream,
+ Context ctx)
+ {
+ switch (hdr)
+ {
+ case PortableUtils.TypeByte:
+ TransferBytes(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeShort:
+ TransferBytes(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeInt:
+ TransferBytes(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeLong:
+ TransferBytes(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeFloat:
+ TransferBytes(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeDouble:
+ TransferBytes(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeChar:
+ TransferBytes(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeBool:
+ TransferBytes(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeDecimal:
+ TransferBytes(inStream, outStream, 4); // Transfer scale
+
+ int magLen = inStream.ReadInt(); // Transfer magnitude length.
+
+ outStream.WriteInt(magLen);
+
+ TransferBytes(inStream, outStream, magLen); // Transfer magnitude.
+
+ break;
+
+ case PortableUtils.TypeString:
+ PortableUtils.WriteString(PortableUtils.ReadString(inStream), outStream);
+
+ break;
+
+ case PortableUtils.TypeGuid:
+ TransferBytes(inStream, outStream, 16);
+
+ break;
+
+ case PortableUtils.TypeDate:
+ TransferBytes(inStream, outStream, 12);
+
+ break;
+
+ case PortableUtils.TypeArrayByte:
+ TransferArray(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeArrayShort:
+ TransferArray(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeArrayInt:
+ TransferArray(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeArrayLong:
+ TransferArray(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeArrayFloat:
+ TransferArray(inStream, outStream, 4);
+
+ break;
+
+ case PortableUtils.TypeArrayDouble:
+ TransferArray(inStream, outStream, 8);
+
+ break;
+
+ case PortableUtils.TypeArrayChar:
+ TransferArray(inStream, outStream, 2);
+
+ break;
+
+ case PortableUtils.TypeArrayBool:
+ TransferArray(inStream, outStream, 1);
+
+ break;
+
+ case PortableUtils.TypeArrayDecimal:
+ case PortableUtils.TypeArrayString:
+ case PortableUtils.TypeArrayGuid:
+ case PortableUtils.TypeArrayDate:
+ case PortableUtils.TypeArrayEnum:
+ case PortableUtils.TypeArray:
+ int arrLen = inStream.ReadInt();
+
+ outStream.WriteInt(arrLen);
+
+ for (int i = 0; i < arrLen; i++)
+ Mutate0(ctx, inStream, outStream, false, 0, null);
+
+ break;
+
+ case PortableUtils.TypeCollection:
+ int colLen = inStream.ReadInt();
+
+ outStream.WriteInt(colLen);
+
+ outStream.WriteByte(inStream.ReadByte());
+
+ for (int i = 0; i < colLen; i++)
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ break;
+
+ case PortableUtils.TypeDictionary:
+ int dictLen = inStream.ReadInt();
+
+ outStream.WriteInt(dictLen);
+
+ outStream.WriteByte(inStream.ReadByte());
+
+ for (int i = 0; i < dictLen; i++)
+ {
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ }
+
+ break;
+
+ case PortableUtils.TypeMapEntry:
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+ Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
+
+ break;
+
+ case PortableUtils.TypePortable:
+ TransferArray(inStream, outStream, 1); // Data array.
+ TransferBytes(inStream, outStream, 4); // Offset in array.
+
+ break;
+
+ case PortableUtils.TypeEnum:
+ TransferBytes(inStream, outStream, 4); // Integer ordinal.
+
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Get's metadata field type ID for the given type.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <returns>Type ID.</returns>
+ private static int TypeId(Type type)
+ {
+ int typeId;
+
+ if (TypeIds.TryGetValue(type, out typeId))
+ return typeId;
+ if (type.IsEnum)
+ return PortableUtils.TypeEnum;
+ if (type.IsArray)
+ return type.GetElementType().IsEnum ? PortableUtils.TypeArrayEnum : PortableUtils.TypeArray;
+ PortableCollectionInfo colInfo = PortableCollectionInfo.Info(type);
+
+ return colInfo.IsAny ? colInfo.IsCollection || colInfo.IsGenericCollection ?
+ PortableUtils.TypeCollection : PortableUtils.TypeDictionary : PortableUtils.TypeObject;
+ }
+
+ /// <summary>
+ /// Transfer bytes from one stream to another.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="cnt">Bytes count.</param>
+ private static void TransferBytes(PortableHeapStream inStream, IPortableStream outStream, int cnt)
+ {
+ outStream.Write(inStream.InternalArray, inStream.Position, cnt);
+
+ inStream.Seek(cnt, SeekOrigin.Current);
+ }
+
+ /// <summary>
+ /// Transfer array of fixed-size elements from one stream to another.
+ /// </summary>
+ /// <param name="inStream">Input stream.</param>
+ /// <param name="outStream">Output stream.</param>
+ /// <param name="elemSize">Element size.</param>
+ private static void TransferArray(PortableHeapStream inStream, IPortableStream outStream,
+ int elemSize)
+ {
+ int len = inStream.ReadInt();
+
+ outStream.WriteInt(len);
+
+ TransferBytes(inStream, outStream, elemSize * len);
+ }
+
+ /// <summary>
+ /// Mutation ocntext.
+ /// </summary>
+ private class Context
+ {
+ /** Map from object position in old portable to position in new portable. */
+ private IDictionary<int, int> _oldToNew;
+
+ /** Parent context. */
+ private readonly Context _parent;
+
+ /** Portable writer. */
+ private readonly PortableWriterImpl _writer;
+
+ /** Children contexts. */
+ private ICollection<Context> _children;
+
+ /** Closed flag; if context is closed, it can no longer be used. */
+ private bool _closed;
+
+ /// <summary>
+ /// Constructor for parent context where writer invocation is not expected.
+ /// </summary>
+ public Context()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Constructor for parent context.
+ /// </summary>
+ /// <param name="writer">Writer</param>
+ public Context(PortableWriterImpl writer)
+ {
+ _writer = writer;
+ }
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="parent">Parent context.</param>
+ public Context(Context parent)
+ {
+ _parent = parent;
+
+ _writer = parent._writer;
+
+ if (parent._children == null)
+ parent._children = new List<Context>();
+
+ parent._children.Add(this);
+ }
+
+ /// <summary>
+ /// Add another old-to-new position mapping.
+ /// </summary>
+ /// <param name="oldPos">Old position.</param>
+ /// <param name="newPos">New position.</param>
+ /// <param name="hndPos">Handle position.</param>
+ /// <returns><c>True</c> if ampping was added, <c>false</c> if mapping already existed and handle
+ /// position in the new object is returned.</returns>
+ public bool AddOldToNew(int oldPos, int newPos, out int hndPos)
+ {
+ if (_oldToNew == null)
+ _oldToNew = new Dictionary<int, int>();
+
+ if (_oldToNew.TryGetValue(oldPos, out hndPos))
+ return false;
+ _oldToNew[oldPos] = newPos;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Get mapping of old position to the new one.
+ /// </summary>
+ /// <param name="oldPos">Old position.</param>
+ /// <param name="newPos">New position.</param>
+ /// <returns><c>True</c> if mapping exists.</returns>
+ public bool OldToNew(int oldPos, out int newPos)
+ {
+ return _oldToNew.TryGetValue(oldPos, out newPos);
+ }
+
+ /// <summary>
+ /// Writer.
+ /// </summary>
+ public PortableWriterImpl Writer
+ {
+ get { return _writer; }
+ }
+
+ /// <summary>
+ /// Closed flag.
+ /// </summary>
+ public bool Closed
+ {
+ get
+ {
+ return _closed;
+ }
+ set
+ {
+ Context ctx = this;
+
+ while (ctx != null)
+ {
+ ctx._closed = value;
+
+ if (_children != null) {
+ foreach (Context child in _children)
+ child.Closed = value;
+ }
+
+ ctx = ctx._parent;
+ }
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
new file mode 100644
index 0000000..fc61833
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableCollectionInfo.cs
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Reflection;
+ using Apache.Ignite.Core.Impl.Common;
+
+ /**
+ * <summary>Collection info helper.</summary>
+ */
+ internal class PortableCollectionInfo
+ {
+ /** Flag: none. */
+ private const byte FlagNone = 0;
+
+ /** Flag: generic dictionary. */
+ private const byte FlagGenericDictionary = 1;
+
+ /** Flag: generic collection. */
+ private const byte FlagGenericCollection = 2;
+
+ /** Flag: dictionary. */
+ private const byte FlagDictionary = 3;
+
+ /** Flag: collection. */
+ private const byte FlagCollection = 4;
+
+ /** Cache "none" value. */
+ private static readonly PortableCollectionInfo None =
+ new PortableCollectionInfo(FlagNone, null, null, null);
+
+ /** Cache "dictionary" value. */
+ private static readonly PortableCollectionInfo Dictionary =
+ new PortableCollectionInfo(FlagDictionary, PortableSystemHandlers.WriteHndDictionary, null, null);
+
+ /** Cache "collection" value. */
+ private static readonly PortableCollectionInfo Collection =
+ new PortableCollectionInfo(FlagCollection, PortableSystemHandlers.WriteHndCollection, null, null);
+
+ /** Cached infos. */
+ private static readonly IDictionary<Type, PortableCollectionInfo> Infos =
+ new ConcurrentDictionary<Type, PortableCollectionInfo>(64, 32);
+
+ /**
+ * <summary>Get collection info for type.</summary>
+ * <param name="type">Type.</param>
+ * <returns>Collection info.</returns>
+ */
+ public static PortableCollectionInfo Info(Type type)
+ {
+ PortableCollectionInfo info;
+
+ if (!Infos.TryGetValue(type, out info))
+ {
+ info = Info0(type);
+
+ Infos[type] = info;
+ }
+
+ return info;
+ }
+
+ /**
+ * <summary>Internal routine to get collection info for type.</summary>
+ * <param name="type">Type.</param>
+ * <returns>Collection info.</returns>
+ */
+ private static PortableCollectionInfo Info0(Type type)
+ {
+ if (type.IsGenericType)
+ {
+ if (type.GetGenericTypeDefinition() == PortableUtils.TypGenericDictionary)
+ {
+ MethodInfo writeMthd =
+ PortableUtils.MtdhWriteGenericDictionary.MakeGenericMethod(type.GetGenericArguments());
+ MethodInfo readMthd =
+ PortableUtils.MtdhReadGenericDictionary.MakeGenericMethod(type.GetGenericArguments());
+
+ return new PortableCollectionInfo(FlagGenericDictionary,
+ PortableSystemHandlers.WriteHndGenericDictionary, writeMthd, readMthd);
+ }
+
+ Type genTyp = type.GetInterface(PortableUtils.TypGenericDictionary.FullName);
+
+ if (genTyp != null)
+ {
+ MethodInfo writeMthd =
+ PortableUtils.MtdhWriteGenericDictionary.MakeGenericMethod(genTyp.GetGenericArguments());
+ MethodInfo readMthd =
+ PortableUtils.MtdhReadGenericDictionary.MakeGenericMethod(genTyp.GetGenericArguments());
+
+ return new PortableCollectionInfo(FlagGenericDictionary,
+ PortableSystemHandlers.WriteHndGenericDictionary, writeMthd, readMthd);
+ }
+
+ if (type.GetGenericTypeDefinition() == PortableUtils.TypGenericCollection)
+ {
+ MethodInfo writeMthd =
+ PortableUtils.MtdhWriteGenericCollection.MakeGenericMethod(type.GetGenericArguments());
+ MethodInfo readMthd =
+ PortableUtils.MtdhReadGenericCollection.MakeGenericMethod(type.GetGenericArguments());
+
+ return new PortableCollectionInfo(FlagGenericCollection,
+ PortableSystemHandlers.WriteHndGenericCollection, writeMthd, readMthd);
+ }
+
+ genTyp = type.GetInterface(PortableUtils.TypGenericCollection.FullName);
+
+ if (genTyp != null)
+ {
+ MethodInfo writeMthd =
+ PortableUtils.MtdhWriteGenericCollection.MakeGenericMethod(genTyp.GetGenericArguments());
+ MethodInfo readMthd =
+ PortableUtils.MtdhReadGenericCollection.MakeGenericMethod(genTyp.GetGenericArguments());
+
+ return new PortableCollectionInfo(FlagGenericCollection,
+ PortableSystemHandlers.WriteHndGenericCollection, writeMthd, readMthd);
+ }
+ }
+
+ if (type == PortableUtils.TypDictionary || type.GetInterface(PortableUtils.TypDictionary.FullName) != null)
+ return Dictionary;
+ if (type == PortableUtils.TypCollection || type.GetInterface(PortableUtils.TypCollection.FullName) != null)
+ return Collection;
+ return None;
+ }
+
+ /** Flag. */
+ private readonly byte _flag;
+
+ /** Write handler. */
+ private readonly PortableSystemWriteDelegate _writeHnd;
+
+ /** Generic write func. */
+ private readonly Action<object, PortableWriterImpl> _writeFunc;
+
+ /** Generic read func. */
+ private readonly Func<PortableReaderImpl, object, object> _readFunc;
+
+ /**
+ * <summary>Constructor.</summary>
+ * <param name="flag0">Flag.</param>
+ * <param name="writeHnd0">Write handler.</param>
+ * <param name="writeMthd0">Generic write method.</param>
+ * <param name="readMthd0">Generic read method.</param>
+ */
+ private PortableCollectionInfo(byte flag0, PortableSystemWriteDelegate writeHnd0,
+ MethodInfo writeMthd0, MethodInfo readMthd0)
+ {
+ _flag = flag0;
+ _writeHnd = writeHnd0;
+
+ if (writeMthd0 != null)
+ _writeFunc = DelegateConverter.CompileFunc<Action<object, PortableWriterImpl>>(null, writeMthd0, null,
+ new[] {true, false, false});
+
+ if (readMthd0 != null)
+ _readFunc = DelegateConverter.CompileFunc<Func<PortableReaderImpl, object, object>>(null, readMthd0,
+ null, new[] {false, true, false});
+ }
+
+ /**
+ * <summary>Generic dictionary flag.</summary>
+ */
+ public bool IsGenericDictionary
+ {
+ get { return _flag == FlagGenericDictionary; }
+ }
+
+ /**
+ * <summary>Generic collection flag.</summary>
+ */
+ public bool IsGenericCollection
+ {
+ get { return _flag == FlagGenericCollection; }
+ }
+
+ /**
+ * <summary>Dictionary flag.</summary>
+ */
+ public bool IsDictionary
+ {
+ get { return _flag == FlagDictionary; }
+ }
+
+ /**
+ * <summary>Collection flag.</summary>
+ */
+ public bool IsCollection
+ {
+ get { return _flag == FlagCollection; }
+ }
+
+ /**
+ * <summary>Whether at least one flag is set..</summary>
+ */
+ public bool IsAny
+ {
+ get { return _flag != FlagNone; }
+ }
+
+ /**
+ * <summary>Write handler.</summary>
+ */
+ public PortableSystemWriteDelegate WriteHandler
+ {
+ get { return _writeHnd; }
+ }
+
+ /// <summary>
+ /// Reads the generic collection.
+ /// </summary>
+ public object ReadGeneric(PortableReaderImpl reader)
+ {
+ Debug.Assert(reader != null);
+ Debug.Assert(_readFunc != null);
+
+ return _readFunc(reader, null);
+ }
+
+ /// <summary>
+ /// Writes the generic collection.
+ /// </summary>
+ public void WriteGeneric(PortableWriterImpl writer, object value)
+ {
+ Debug.Assert(writer != null);
+ Debug.Assert(_writeFunc != null);
+
+ _writeFunc(value, writer);
+ }
+ }
+}