Beispiel #1
0
        internal static T[] CopyArrayRank1 <T>(T[] originalArray, CopyContext context)
        {
            if (context.TryGetCopy(originalArray, out var existingCopy))
            {
                return((T[])existingCopy);
            }

            var length = originalArray.Length;
            var result = new T[length];

            context.RecordCopy(originalArray, result);
            for (var i = 0; i < length; i++)
            {
                var original = originalArray[i];
                if (original != null)
                {
                    if (context.TryGetCopy(original, out var existingElement))
                    {
                        result[i] = (T)existingElement;
                    }
                    else
                    {
                        var copy = CopierGenerator <T> .Copy(original, context);

                        context.RecordCopy(original, copy);
                        result[i] = copy;
                    }
                }
            }
            return(result);
        }
Beispiel #2
0
        /// <summary>
        /// Creates and returns a deep copy of the provided object.
        /// </summary>
        /// <typeparam name="T">The object type.</typeparam>
        /// <param name="original">The object to copy.</param>
        /// <param name="context">
        /// The copy context, providing referential integrity between multiple calls to this method.
        /// </param>
        /// <returns>A deep copy of the provided object.</returns>
        public static T Copy <T>(T original, CopyContext context)
        {
            if (original == null)
            {
                return(default(T));
            }

            // If this object has already been copied, return that copy.
            var existingCopy = context.TryGetCopy(original);

            if (existingCopy != null)
            {
                return((T)existingCopy);
            }

            var type = original.GetType();

            if (!type.IsValueType)
            {
                // Handle arrays specially.
                var originalArray = original as Array;
                if (originalArray != null)
                {
                    return((T)CopyArray(originalArray, context));
                }
            }

            var typedCopier = CopierGenerator.GetOrCreateCopier <T>(type);

            return(typedCopier(original, context));
        }
Beispiel #3
0
        internal static T[,] CopyArrayRank2 <T>(T[,] originalArray, CopyContext context)
        {
            if (context.TryGetCopy(originalArray, out var existingCopy))
            {
                return((T[, ])existingCopy);
            }

            var lenI   = originalArray.GetLength(0);
            var lenJ   = originalArray.GetLength(1);
            var result = new T[lenI, lenJ];

            context.RecordCopy(originalArray, result);
            for (var i = 0; i < lenI; i++)
            {
                for (var j = 0; j < lenJ; j++)
                {
                    var original = originalArray[i, j];
                    if (original != null)
                    {
                        if (context.TryGetCopy(original, out var existingElement))
                        {
                            result[i, j] = (T)existingElement;
                        }
                        else
                        {
                            var copy = CopierGenerator <T> .Copy(original, context);

                            context.RecordCopy(original, copy);
                            result[i, j] = copy;
                        }
                    }
                }
            }
            return(result);
        }
Beispiel #4
0
        internal static T CopyArray <T>(T original, CopyContext context)
        {
            if (context.TryGetCopy(original, out var existingCopy))
            {
                return((T)existingCopy);
            }

            var originalArray = original as Array;

            if (originalArray == null)
            {
                throw new InvalidCastException($"Cannot cast non-array type {original?.GetType()} to Array.");
            }
            var elementType = original.GetType().GetElementType();

            var rank    = originalArray.Rank;
            var lengths = new int[rank];

            for (var i = 0; i < rank; i++)
            {
                lengths[i] = originalArray.GetLength(i);
            }

            var copyArray = Array.CreateInstance(elementType, lengths);

            context.RecordCopy(originalArray, copyArray);

            if (DeepCopier.CopyPolicy.IsShallowCopyable(elementType))
            {
                Array.Copy(originalArray, copyArray, originalArray.Length);
            }

            var index = new int[rank];
            var sizes = new int[rank];

            sizes[rank - 1] = 1;
            for (var k = rank - 2; k >= 0; k--)
            {
                sizes[k] = sizes[k + 1] * lengths[k + 1];
            }

            for (var i = 0; i < originalArray.Length; i++)
            {
                var k = i;
                for (var n = 0; n < rank; n++)
                {
                    var offset = k / sizes[n];
                    k        = k - offset * sizes[n];
                    index[n] = offset;
                }

                copyArray.SetValue(DeepCopier.Copy(originalArray.GetValue(index), context), index);
            }

            return((T)(object)copyArray);
        }
Beispiel #5
0
        internal static T[] CopyArrayRank1Shallow <T>(T[] array, CopyContext context)
        {
            if (context.TryGetCopy(array, out var existingCopy))
            {
                return((T[])existingCopy);
            }

            var length = array.Length;
            var result = new T[length];

            context.RecordCopy(array, result);
            Array.Copy(array, result, length);
            return(result);
        }
Beispiel #6
0
        internal static T[,] CopyArrayRank2Shallow <T>(T[,] array, CopyContext context)
        {
            if (context.TryGetCopy(array, out var existingCopy))
            {
                return((T[, ])existingCopy);
            }

            var lenI   = array.GetLength(0);
            var lenJ   = array.GetLength(1);
            var result = new T[lenI, lenJ];

            context.RecordCopy(array, result);
            Array.Copy(array, result, array.Length);
            return(result);
        }
Beispiel #7
0
        internal static T[] CopyArrayRank1 <T>(T[] originalArray, CopyContext context)
        {
            if (context.TryGetCopy(originalArray, out var existingCopy))
            {
                return((T[])existingCopy);
            }

            var length = originalArray.Length;
            var result = new T[length];

            context.RecordCopy(originalArray, result);
            for (var i = 0; i < length; i++)
            {
                result[i] = CopierGenerator <T> .Copy(originalArray[i], context);
            }
            return(result);
        }
Beispiel #8
0
        public static T Copy(T original, CopyContext context)
        {
            // ReSharper disable once ExpressionIsAlwaysNull
            if (original is null)
            {
                return(original);
            }

            var type = original.GetType();

            if (type == GenericType)
            {
                return(MatchingTypeCopier(original, context));
            }

            var result = Copiers.GetOrAdd(type, GenerateCopier);

            return(result(original, context));
        }
Beispiel #9
0
        /// <summary>
        /// Returns a copy of the provided array.
        /// </summary>
        /// <param name="originalArray">The original array.</param>
        /// <param name="context">The copy context.</param>
        /// <returns>A copy of the original array.</returns>
        private static object CopyArray(Array originalArray, CopyContext context)
        {
            // Special-case for empty rank-1 arrays.
            if (originalArray.Rank == 1 && originalArray.GetLength(0) == 0)
            {
                return(originalArray);
            }

            // Special-case for arrays of immutable types.
            var elementType = originalArray.GetType().GetElementType();

            if (CopyPolicy.IsImmutable(elementType))
            {
                return(originalArray.Clone());
            }

            var rank    = originalArray.Rank;
            var lengths = new int[rank];

            for (var i = 0; i < rank; i++)
            {
                lengths[i] = originalArray.GetLength(i);
            }

            var copyArray = Array.CreateInstance(elementType, lengths);

            context.RecordCopy(originalArray, copyArray);

            switch (rank)
            {
            case 1:
                for (var i = 0; i < lengths[0]; i++)
                {
                    copyArray.SetValue(Copy(originalArray.GetValue(i), context), i);
                }
                break;

            case 2:
                for (var i = 0; i < lengths[0]; i++)
                {
                    for (var j = 0; j < lengths[1]; j++)
                    {
                        copyArray.SetValue(Copy(originalArray.GetValue(i, j), context), i, j);
                    }
                }
                break;

            default:
                var index = new int[rank];
                var sizes = new int[rank];
                sizes[rank - 1] = 1;
                for (var k = rank - 2; k >= 0; k--)
                {
                    sizes[k] = sizes[k + 1] * lengths[k + 1];
                }

                for (var i = 0; i < originalArray.Length; i++)
                {
                    var k = i;
                    for (var n = 0; n < rank; n++)
                    {
                        var offset = k / sizes[n];
                        k        = k - offset * sizes[n];
                        index[n] = offset;
                    }

                    copyArray.SetValue(Copy(originalArray.GetValue(index), context), index);
                }

                break;
            }

            return(copyArray);
        }
Beispiel #10
0
 /// <summary>
 /// Creates and returns a deep copy of the provided object.
 /// </summary>
 /// <typeparam name="T">The object type.</typeparam>
 /// <param name="original">The object to copy.</param>
 /// <param name="context">
 /// The copy context, providing referential integrity between multiple calls to this method.
 /// </param>
 /// <returns>A deep copy of the provided object.</returns>
 public static T Copy <T>(T original, CopyContext context)
 {
     return(CopierGenerator <T> .Copy(original, context));
 }