<commit_before>﻿// Copyright (c) MarinAtanasov. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the project root for license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace AppBrix.Cloning
{
    /// <summary>
    /// Default cloner used for shalow or deep copying.
    /// </summary>
    internal sealed class DefaultCloner : ICloner
    {
        #region ICloner implementation
        public T DeepCopy<T>(T obj)
        {
            return this.DeepCopy(obj, new Dictionary<object, object>());
        }

        public T ShalowCopy<T>(T obj)
        {
            if (this.IsPrimitiveType(typeof(T)))
                return obj;

            return (T)DefaultCloner.ShalowCopyMethod.Invoke(obj, null);
        }
        #endregion

        #region Private methods
        private T DeepCopy<T>(T original, IDictionary<object, object> visited)
        {
            if (original == null)
                return original;

            var type = original.GetType();

            if (this.IsPrimitiveType(type))
                return original;

            if (typeof(Delegate).IsAssignableFrom(type))
                return (T)(object)null;

            if (!visited.ContainsKey(original))
            {
                this.CloneReferenceType(original, type, visited);
            }

            return (T)visited[original];
        }

        private object CloneReferenceType(object original, Type type, IDictionary<object, object> visited)
        {
            var cloned = this.ShalowCopy(original);
            visited[original] = cloned;
            if (type.IsArray)
            {
                var clonedArray = (Array)cloned;
                ((Array)original).ForEach((array, indices) => clonedArray.SetValue(this.DeepCopy(array.GetValue(indices), visited), indices));
            }
            while (type != typeof(object))
            {
                foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public))
                {
                    field.SetValue(cloned, this.DeepCopy(field.GetValue(original), visited));
                }
                type = type.GetTypeInfo().BaseType;
            }
            return cloned;
        }

        private bool IsPrimitiveType(Type type)
        {
            var typeInfo = type.GetTypeInfo();
            return (typeInfo.IsValueType && typeInfo.IsPrimitive) || typeInfo.IsEnum || type == typeof(string);
        }
        #endregion

        #region Private fields and constants
        private static readonly MethodInfo ShalowCopyMethod = typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
        #endregion
    }
}<commit_msg>Improved the shallow cloning to skip all value types and string.<commit_after>﻿// Copyright (c) MarinAtanasov. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the project root for license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace AppBrix.Cloning
{
    /// <summary>
    /// Default cloner used for shalow or deep copying.
    /// </summary>
    internal sealed class DefaultCloner : ICloner
    {
        #region ICloner implementation
        public T DeepCopy<T>(T obj)
        {
            return this.DeepCopy(obj, new Dictionary<object, object>());
        }

        public T ShalowCopy<T>(T obj)
        {
            if (this.IsValueType(typeof(T)))
                return obj;

            return (T)DefaultCloner.ShalowCopyMethod.Invoke(obj, null);
        }
        #endregion

        #region Private methods
        private T DeepCopy<T>(T original, IDictionary<object, object> visited)
        {
            if (original == null)
                return original;

            var type = original.GetType();

            if (this.IsPrimitiveType(type))
                return original;

            if (typeof(Delegate).IsAssignableFrom(type))
                return (T)(object)null;

            if (!visited.ContainsKey(original))
            {
                this.CloneReferenceType(original, type, visited);
            }

            return (T)visited[original];
        }

        private object CloneReferenceType(object original, Type type, IDictionary<object, object> visited)
        {
            var cloned = this.ShalowCopy(original);
            visited[original] = cloned;
            if (type.IsArray)
            {
                var clonedArray = (Array)cloned;
                ((Array)original).ForEach((array, indices) => clonedArray.SetValue(this.DeepCopy(array.GetValue(indices), visited), indices));
            }
            while (type != typeof(object))
            {
                foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public))
                {
                    field.SetValue(cloned, this.DeepCopy(field.GetValue(original), visited));
                }
                type = type.GetTypeInfo().BaseType;
            }
            return cloned;
        }

        private bool IsPrimitiveType(Type type)
        {
            var typeInfo = type.GetTypeInfo();
            return (typeInfo.IsValueType && typeInfo.IsPrimitive) || typeInfo.IsEnum || type == typeof(string);
        }

        private bool IsValueType(Type type)
        {
            return type == typeof(string) || type.GetTypeInfo().IsValueType;
        }
        #endregion

        #region Private fields and constants
        private static readonly MethodInfo ShalowCopyMethod = typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
        #endregion
    }
}
{'fraction_non_alphanumeric': 0.09806936613702374, 'fraction_numerical': 0.0, 'mean_word_length': 1.9821701477330615, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2991709', 'n_tokens_mistral': 1537, 'n_tokens_neox': 1478, 'n_words': 366}