// Copyright Christophe Bertrand.
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Collections;
using System.Linq.Expressions;
using System.Diagnostics;
using System.Text;
using System.Globalization;
using System.IO;
using System.Linq;
using UniversalSerializerLib2.NumberTools;
using UniversalSerializerLib2.DataTools;
namespace UniversalSerializerLib2
{
public static partial class Tools
{
// -------------------------------------------
// -------------------------------------------
/// <summary>
/// The default culture "en-US" is useful for number and date transcoding to and from string.
/// </summary>
internal static readonly CultureInfo EnUSCulture = new CultureInfo("en-us");
// -------------------------------------------
internal static object GenericMethodCall(object classInstance, MethodInfo method, Type[] types, object[] parameters = null)
{
var m =
method.IsGenericMethodDefinition ?
method
: method.GetGenericMethodDefinition();
MethodInfo generic = m.MakeGenericMethod(types);
return generic.Invoke(classInstance, parameters);
}
// -------------------------------------------
internal static Func<object, object> GenerateFieldGetter(Type classType, Type memberType, FieldInfo fieldInfo)
{
var classThis = Expression.Parameter(typeof(object)
#if DEBUG || PORTABLE
, "this"
#endif
);
var cast_classThis = Expression.Convert(classThis, classType);
var member = Expression.Field(cast_classThis, fieldInfo);
var lambda1 = Expression.Lambda(member, classThis);
var resultBody = Expression.Convert(lambda1.Body, typeof(object));
var lambda = Expression.Lambda<Func<object, object>>(resultBody, lambda1.Parameters);
return lambda.Compile();
}
// -------------------------------------------
internal static Func<object, object> GeneratePropertyGetter(Type classType, Type memberType, PropertyInfo propertyInfo)
{
var classThis = Expression.Parameter(typeof(object)
#if DEBUG || PORTABLE
, "this"
#endif
);
var cast_classThis = Expression.Convert(classThis, classType);
var member = Expression.Property(cast_classThis, propertyInfo);
var lambda1 = Expression.Lambda(member, classThis);
var resultBody = Expression.Convert(lambda1.Body, typeof(object));
var lambda = Expression.Lambda<Func<object, object>>(resultBody, lambda1.Parameters);
return lambda.Compile();
}
// -------------------------------------------
// Keep that code for reference.
static Func<object, object> GenerateMemberGetter(Type classType, Type memberType, string member_name)
{
var classThis = Expression.Parameter(typeof(object)
#if DEBUG || PORTABLE
, "this"
#endif
);
var cast_classThis = Expression.Convert(classThis, classType);
var member = Expression.PropertyOrField(cast_classThis, member_name);
var lambda1 = Expression.Lambda(member, classThis);
var resultBody = Expression.Convert(lambda1.Body, typeof(object));
var lambda = Expression.Lambda<Func<object, object>>(resultBody, lambda1.Parameters);
return lambda.Compile();
}
// -------------------------------------------
// Keep that code for reference.
/// <summary>
/// Creates a compiled method that set a class member.
/// Does not apply to structures (value references can not be cast in .NET).
/// </summary>
/// <param name="classType"></param>
/// <param name="memberType"></param>
/// <param name="member_name"></param>
/// <returns></returns>
static Action<object, object> GenerateReferenceTypeMemberSetterByTypesNoRef(
Type classType, Type memberType, string member_name)
{
#if DEBUG
if (classType.IsValueType)
throw new Exception();
#endif
var objectType = typeof(object);
var param_this = Expression.Parameter(objectType, "this");
var param_value = Expression.Parameter(typeof(object), "value");
var cast_this = Expression.Convert(param_this, classType);
var cast_param = Expression.Convert(param_value, memberType);
var member = Expression.PropertyOrField(cast_this, member_name);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(member, cast_param);
var lambda = Expression.Lambda<Action<object, object>>(assign, param_this, param_value);
return lambda.Compile();
}
// -------------------------------------------
/// <summary>
/// Creates a compiled method that set a class field.
/// Does not apply to structures (value references can not be cast in .NET).
/// </summary>
/// <param name="fi">FieldInfo</param>
/// <returns></returns>
internal static Action<object, object> GenerateReferenceTypeFieldSetter(
FieldInfo fi)
{
#if DEBUG
if (fi.DeclaringType.IsValueType)
throw new Exception();
#endif
if (fi.IsInitOnly)
return null; // Expression.Assign() can not set a readonly field.
var objectType = typeof(object);
var param_this = Expression.Parameter(objectType, "this");
var param_value = Expression.Parameter(typeof(object), "value");
var cast_this = Expression.Convert(param_this, fi.DeclaringType);
var cast_param = Expression.Convert(param_value, fi.FieldType);
var member = Expression.Field(cast_this, fi);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(member, cast_param);
var lambda = Expression.Lambda<Action<object, object>>(assign, param_this, param_value);
return lambda.Compile();
}
// -------------------------------------------
/// <summary>
/// Creates a compiled method that set a class property.
/// Does not apply to structures (value references can not be cast in .NET).
/// </summary>
/// <param name="pi">PropertyInfo</param>
/// <returns></returns>
internal static Action<object, object> GenerateReferenceTypePropertySetter(
PropertyInfo pi)
{
#if DEBUG
if (pi.DeclaringType.IsValueType)
throw new Exception();
#endif
if (!pi.CanWrite)
return null; // Expression.Assign() can not set a property with no set_().
var objectType = typeof(object);
var param_this = Expression.Parameter(objectType, "this");
var param_value = Expression.Parameter(typeof(object), "value");
var cast_this = Expression.Convert(param_this, pi.DeclaringType);
var cast_param = Expression.Convert(param_value, pi.PropertyType);
var member = Expression.Property(cast_this, pi);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(member, cast_param);
var lambda = Expression.Lambda<Action<object, object>>(assign, param_this, param_value);
return lambda.Compile();
}
// -------------------------------------------
// Keep that code for reference.
static ValueTypeMemberSetterDelegate<T, V> GenerateValueTypeMemberSetter<T, V>(string member_name)
where T : struct
{
var this_ref = typeof(T).MakeByRefType();
var param_this = Expression.Parameter(this_ref, "this");
var param_value = Expression.Parameter(typeof(V), "value");
var member = Expression.PropertyOrField(param_this, member_name);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(member, param_value);
var lambda = Expression.Lambda<ValueTypeMemberSetterDelegate<T, V>>(assign, param_this, param_value);
return lambda.Compile();
}
delegate void ValueTypeMemberSetterDelegate<T, V>(ref T @this, V value);
// -------------------------------------------
internal delegate void ValueTypeObjectMemberSetterDelegate<T>(ref T @this, object value);
// -------------------------------------------
internal static ValueTypeObjectMemberSetterDelegate<T> GenerateValueTypeFieldSetter<T>(FieldInfo fi)
{
var this_ref = typeof(T).MakeByRefType();
var param_struct = Expression.Parameter(this_ref
#if DEBUG || PORTABLE
, "this"
#endif
);
var param_value = Expression.Parameter(typeof(object)
#if DEBUG || PORTABLE
, "value"
#endif
);
#if WINDOWS_PHONE
//Debugger.Break(); // PB with Windows Phone 7.1: IsByRef does exist in ParameterExpression ! Therefore Expression.Field() can not take a ref type parameter.
#endif
var field = Expression.Field(param_struct, fi); // PB with Windows Phone 7.1: IsByRef does exist in ParameterExpression ! Therefore Expression.Field() can not take a ref type parameter.
var cast_param = Expression.Convert(param_value, fi.FieldType);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(field, cast_param);
var lambda = Expression.Lambda<ValueTypeObjectMemberSetterDelegate<T>>(assign, param_struct, param_value);
return lambda.Compile();
}
// -------------------------------------------
internal static ValueTypeObjectMemberSetterDelegate<T> GenerateValueTypePropertySetter<T>(PropertyInfo fi)
{
var this_ref = typeof(T).MakeByRefType();
var param_struct = Expression.Parameter(this_ref
#if DEBUG || PORTABLE
, "this"
#endif
);
var param_value = Expression.Parameter(typeof(object)
#if DEBUG || PORTABLE
, "value"
#endif
);
var Property = Expression.Property(param_struct, fi);
var cast_param = Expression.Convert(param_value, fi.PropertyType);
var assign =
#if !WINDOWS_PHONE && !PORTABLE
Expression.Assign
#else
ExpressionEx.Assign
#endif
(Property, cast_param);
var lambda = Expression.Lambda<ValueTypeObjectMemberSetterDelegate<T>>(assign, param_struct, param_value);
return lambda.Compile();
}
// -------------------------------------------
/// <summary>
/// Gets the MethodInfo of a not-static method.
/// No class instance is needed.
/// Usage: Tools.GetMethodInfo<TClass>(u => u.TheMethod(..))
/// We need parameters, but they will not be used by this function, so they can be null or default(T).
///
/// Note 1: you do not need this function to obtain the MethodInfo of a STATIC method:
/// <code>
/// Func<int> f = TClass.StaticMethod<int>;
/// MethodInfo mi = f.Method;
/// </code>
/// Or in shorter:
/// <code>
/// MethodInfo mf = (()Func<int> TClass.StaticMethod<int>).Method;
/// </code>
///
/// Note 2: alternative method for NOT-static methods, using a class instance:
/// <code>
/// Func<int> f = this.NotStaticMethod<int>; // or Action
/// MethodInfo mf = f.Method;
/// </code>
/// Or in shorter:
/// <code>
/// MethodInfo mf = (()Func<int> this.NotStaticMethod<int>).Method;
/// </code>
/// </summary>
internal static MethodInfo GetMethodInfo<TClass>(
Expression<Func<TClass, object>> expression)
{
{
UnaryExpression ubody = expression.Body as UnaryExpression;
if (ubody != null)
{
var operand = ubody.Operand as System.Linq.Expressions.MethodCallExpression;
if (operand.Method != null)
return operand.Method;
}
}
return null;
}
// -------------------------------------------
/// <summary>
/// Returns true for (List{int},List{}), but false for (MyList{int},List{}) because it is inherited twice.
/// </summary>
internal static bool IsADirectGenericOf(this Type objType, Type genericType)
{
if (!objType.IsGenericType)
return false;
Type t = objType.GetGenericTypeDefinition();
return t == genericType;
}
// -------------------------------------------
internal static bool Contains<T>(this IEnumerable<T> list, T value)
{
foreach (T item in list)
if (item.Equals(value))
return true;
return false;
}
// -------------------------------------------
internal static Func<object> GetNoParamConstructorWithoutCache2(Type type)
{
ConstructorInfo ci =
#if !PORTABLE
type.IsPublic ?
type.GetConstructor(
BindingFlags.Public | BindingFlags.Instance
,
null,
Type.EmptyTypes,
null
)
: type.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null,
Type.EmptyTypes,
null
);
#else
type.GetConstructor(EmptyTypes);
if (ci == null && !type.IsPublic)
{
var constrs = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
if (constrs.Length > 0)
ci = constrs.First((ci2) => ci2.GetParameters().Length == 0);
}
#endif
if (ci == null)
return null;
// Some constructors only contains a 'throw new Exception', so we test them.
try
{
var f = DefaultConstructorToDelegate(ci);
object o = f();
return o != null ? f : null;
}
catch
{
#if DEBUG
// Pauses on unknown types:
#if SILVERLIGHT
if (type != typeof(System.Windows.Input.InputScope))
#else
if (type.Name != "RuntimeType")
#endif
Debugger.Break();
#endif
return null;
}
}
private delegate object _CreateObject();
#if PORTABLE
static Type[] EmptyTypes = new Type[0];
#endif
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<object> DefaultConstructorToDelegate(System.Reflection.ConstructorInfo ci)
{
var lambda = System.Linq.Expressions.Expression.Lambda<Func<object>>(
System.Linq.Expressions.Expression.New(ci),
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_defaultConstructor",
#endif
new System.Linq.Expressions.ParameterExpression[0]);
var func = lambda.Compile();
return func;
}
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<P1, R> Param1ConstructorToDelegate<P1, R>(System.Reflection.ConstructorInfo ci)
{
var param1 = System.Linq.Expressions.Expression.Parameter(typeof(P1)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var pars = new System.Linq.Expressions.ParameterExpression[] { param1 };
var lambda = System.Linq.Expressions.Expression.Lambda<Func<P1, R>>(
System.Linq.Expressions.Expression.New(ci, pars),
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_defaultConstructor",
#endif
pars);
var func = lambda.Compile();
return func;
}
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<P1, P2, R> Param2ConstructorToDelegate<P1, P2, R>(System.Reflection.ConstructorInfo ci)
{
var param1 = System.Linq.Expressions.Expression.Parameter(typeof(P1)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param2 = System.Linq.Expressions.Expression.Parameter(typeof(P2)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var pars = new System.Linq.Expressions.ParameterExpression[] { param1, param2 };
var lambda = System.Linq.Expressions.Expression.Lambda<Func<P1, P2, R>>(
System.Linq.Expressions.Expression.New(ci, pars),
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_Constructor",
#endif
pars);
var func = lambda.Compile();
return func;
}
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<P1, P2, P3, P4, P5, P6, R> Param6ConstructorToDelegate<P1, P2, P3, P4, P5, P6, R>(System.Reflection.ConstructorInfo ci)
{
var param1 = System.Linq.Expressions.Expression.Parameter(typeof(P1)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param2 = System.Linq.Expressions.Expression.Parameter(typeof(P2)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param3 = System.Linq.Expressions.Expression.Parameter(typeof(P3)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param4 = System.Linq.Expressions.Expression.Parameter(typeof(P4)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param5 = System.Linq.Expressions.Expression.Parameter(typeof(P5)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param6 = System.Linq.Expressions.Expression.Parameter(typeof(P6)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var pars = new System.Linq.Expressions.ParameterExpression[] { param1, param2, param3, param4, param5, param6 };
var constr = System.Linq.Expressions.Expression.New(ci, pars);
var lambda = System.Linq.Expressions.Expression.Lambda<Func<P1, P2, P3, P4, P5, P6, R>>(
constr,
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_Constructor",
#endif
pars);
var func = lambda.Compile();
return func;
}
#if WINDOWS_PHONE || PORTABLE
// Windows Phone SDK (7.1) is really really incomplete ! ;)
/// <summary>
/// Func delegate with 6 parameters.
/// </summary>
/// <typeparam name="P1"></typeparam>
/// <typeparam name="P2"></typeparam>
/// <typeparam name="P3"></typeparam>
/// <typeparam name="P4"></typeparam>
/// <typeparam name="P5"></typeparam>
/// <typeparam name="P6"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <param name="p4"></param>
/// <param name="p5"></param>
/// <param name="p6"></param>
/// <returns></returns>
public delegate TResult Func<P1, P2, P3, P4, P5, P6, TResult>(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
#endif
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<P1, P2, P3, P4, P5, R> Param5ConstructorToDelegate<P1, P2, P3, P4, P5, R>(System.Reflection.ConstructorInfo ci)
{
var param1 = System.Linq.Expressions.Expression.Parameter(typeof(P1)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param2 = System.Linq.Expressions.Expression.Parameter(typeof(P2)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param3 = System.Linq.Expressions.Expression.Parameter(typeof(P3)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param4 = System.Linq.Expressions.Expression.Parameter(typeof(P4)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param5 = System.Linq.Expressions.Expression.Parameter(typeof(P5)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var pars = new System.Linq.Expressions.ParameterExpression[] { param1, param2, param3, param4, param5 };
var constr = System.Linq.Expressions.Expression.New(ci, pars);
var lambda = System.Linq.Expressions.Expression.Lambda<Func<P1, P2, P3, P4, P5, R>>(
constr,
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_Constructor",
#endif
pars);
var func = lambda.Compile();
return func;
}
#if WINDOWS_PHONE || PORTABLE
// Windows Phone SDK (7.1) is really really incomplete ! ;)
/// <summary>
/// Func delegate with 5 parameters.
/// </summary>
/// <typeparam name="P1"></typeparam>
/// <typeparam name="P2"></typeparam>
/// <typeparam name="P3"></typeparam>
/// <typeparam name="P4"></typeparam>
/// <typeparam name="P5"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <param name="p4"></param>
/// <param name="p5"></param>
/// <returns></returns>
public delegate TResult Func<P1, P2, P3, P4, P5, TResult>(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
#endif
// -------------------------------------------
/// <summary>
/// Create a Delegate from a ConstructorInfo.
/// Equivalent to a IL emission, but more portable.
/// Compatible with Silverlight 4.
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
internal static Func<P1, P2, P3, P4, R> Param4ConstructorToDelegate<P1, P2, P3, P4, R>(System.Reflection.ConstructorInfo ci)
{
var param1 = System.Linq.Expressions.Expression.Parameter(typeof(P1)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param2 = System.Linq.Expressions.Expression.Parameter(typeof(P2)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param3 = System.Linq.Expressions.Expression.Parameter(typeof(P3)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var param4 = System.Linq.Expressions.Expression.Parameter(typeof(P4)
#if WINDOWS_PHONE || PORTABLE
, string.Empty
#endif
);
var pars = new System.Linq.Expressions.ParameterExpression[] { param1, param2, param3, param4 };
var constr = System.Linq.Expressions.Expression.New(ci, pars);
var lambda = System.Linq.Expressions.Expression.Lambda<Func<P1, P2, P3, P4, R>>(
constr,
#if DEBUG && !WINDOWS_PHONE && !PORTABLE
ci.DeclaringType.Name + "_Constructor",
#endif
pars);
var func = lambda.Compile();
return func;
}
// -------------------------------------------
internal static bool IsEmpty(this IEnumerable collection)
{
{
var coll = collection as ICollection;
if (coll != null)
return coll.Count == 0;
}
var enumerator = collection.GetEnumerator();
return !enumerator.MoveNext();
}
// -------------------------------------------
internal static int GetCount(this IEnumerable collection)
{
{
var coll = collection as ICollection;
if (coll != null)
return coll.Count;
}
var enumerator = collection.GetEnumerator();
int i = 0;
while (enumerator.MoveNext()) // Very slow, but what else ?
i++;
return i;
}
// -------------------------------------------
/// <summary>
/// Get item type of an IEnumerable, if it is a generic IEnumerable as well.
/// </summary>
internal static Type GetCollectionItemType(Type collectionType)
{
if (collectionType.IsArray)
return collectionType.GetElementType();
Type genericIEnumerable = collectionType.FindDerivedOrEqualToThisType(typeof(IEnumerable<>));
return
(genericIEnumerable != null) ?
genericIEnumerable.GetGenericArguments()[0]
: null;
}
// -------------------------------------------
/// <summary>
/// Get key and value types of an IDictionary<,>.
/// </summary>
internal static void GetKeyAndValueTypes(Type collectionType, out Type KeyType, out Type ValueType)
{
Type genericIDictionary = collectionType.FindDerivedOrEqualToThisType(typeof(IDictionary<,>));
if (genericIDictionary != null)
{
KeyType = genericIDictionary.GetGenericArguments()[0];
ValueType = genericIDictionary.GetGenericArguments()[1];
}
KeyType = ValueType = null;
}
// -------------------------------------------
/// <summary>
/// Get generic type short name.
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
internal static string GetGenericTypeName(this Type t)
{
if (!t.IsGenericType)
return t.Name;
var pars = t.GetGenericArguments();
StringBuilder ret = new StringBuilder(t.Name.Substring(0, t.Name.IndexOf('`')));
ret.Append('<');
bool append = false;
foreach (var par in pars)
{
if (append)
ret.Append(',');
ret.Append(par.GetGenericTypeName());
append = true;
}
ret.Append('>');
return ret.ToString();
}
// -------------------------------------------
/// <summary>
/// Returns true if the object type inherits the searched type
/// Returns false if the type are the same.
/// </summary>
internal static bool Inherits(this Type ObjectType, Type SearchedType)
{
return FindDerivedToThisType(ObjectType, SearchedType) != null;
}
// -------------------------------------------
internal static Type FindDerivedToThisType(this Type TheObjectType, Type SearchedType)
{
if (SearchedType == TypeTools.Types.ObjectType)
return SearchedType; // optimisation: All types are objects.
Type ret;
KeyValuePair<Type, Type> searched = new KeyValuePair<Type, Type>(TheObjectType, SearchedType);
if (!_FindDerivedToThisTypeCache.TryGetValue(searched, out ret))
{
ret = _FindDerivedToThisType(TheObjectType, SearchedType);
_FindDerivedToThisTypeCache.Add(searched, ret);
}
return ret;
}
internal static Type _FindDerivedToThisType(Type ObjectType, Type SearchedType)
{
if (SearchedType.IsInterface)
{
if (ObjectType.IsGenericType && !ObjectType.IsGenericTypeDefinition && (ObjectType.GetGenericTypeDefinition() == SearchedType))
return SearchedType;
var ints = ObjectType.GetInterfaces();
return ContainsThisType(ints, SearchedType);
}
else // PAS une interface: --------------------------
{
bool lookForAPureGenericWithoutDefinedParameter =
SearchedType.IsGenericType && (SearchedType.ContainsGenericParameters);
if (!lookForAPureGenericWithoutDefinedParameter)
{
Type tparent = ObjectType.BaseType;
while (tparent != null)
{
if (tparent == SearchedType)
return tparent;
tparent = tparent.BaseType;
}
}
else
{
Type previous = ObjectType;
Type tparent = ObjectType.IsGenericType ? ObjectType.GetGenericTypeDefinition() : ObjectType;
while (tparent != null)
{
if (tparent == SearchedType)
return previous;// tparent;
// next:
previous = tparent;
tparent = tparent.BaseType;
if (tparent != null)
{
if (tparent.IsGenericType)
tparent = tparent.GetGenericTypeDefinition();
}
}
}
}
return null;
}
static Dictionary<KeyValuePair<Type, Type>, Type> _FindDerivedToThisTypeCache
= new Dictionary<KeyValuePair<Type, Type>, Type>();
// -------------------------------------------
/// <summary>
/// Set a value in the list, even if it is not defined yet.
/// Missing indexes are filled with default(T).
/// </summary>
/// <param name="index">Index of the value to be modified.</param>
/// <param name="list"></param>
/// <param name="Value">The value.</param>
/// <returns></returns>
internal static void SecurelySetIndex<T>(this IList<T> list, int index, T Value)
{
if (index < 0)
throw new ArgumentException();
if (index < list.Count)
list[index] = Value;
// Il manque des cases dans cette liste, on doit les créer pour pouvoir modifier celle-ci.
list.FillUntilIndex(index - 1);
list.Add(Value); // Maintenant, on peut modifier cette case, car elle existe.
}
// -------------------------------------------
internal static void FillUntilIndex<T>(
this IList<T> list, int index)
{
Type t = typeof(T);
for (int i = list.Count; i <= index; i++)
list.Add(default(T));
}
// -------------------------------------------
internal static void SetMinimalSize<T>(
this IList<T> list, int index)
{
list.FillUntilIndex(index - 1);
}
// -------------------------------------------
/// <summary>
/// Returns true if the types are equal or if the object type inherits the searched type.
/// This is equivalent to C# 'is', but for Type.
/// </summary>
public static bool TypeIs(Type ObjectType, Type SearchedType)
{
return ObjectType.FindDerivedOrEqualToThisType(SearchedType) != null;
}
// -------------------------------------------
/// <summary>
/// Returns true if the types are the equal or if the objetc type inherits the searched type
/// </summary>
internal static bool Is(this Type ObjectType, Type SearchedType)
{
return ObjectType.FindDerivedOrEqualToThisType(SearchedType) != null;
}
// -------------------------------------------
/// <summary>
/// Returns true if the types are the equal or if the object type inherits the searched type
/// From the AssemblyQualifiedName or the FullName.
/// </summary>
internal static bool Is(this Type ObjectType, string SearchedTypeFullName)
{
return ObjectType.FindDerivedOrEqualToThisType(GetTypeFromFullName(SearchedTypeFullName)) != null;
}
// -------------------------------------------
/// <summary>
/// From the AssemblyQualifiedName or the FullName.
/// </summary>
public static Type GetTypeFromFullName(string TypeFullName)
{
Type ret;
if (!_GetTypeFromFullNameCache.TryGetValue(TypeFullName, out ret))
{
ret = _GetTypeFromFullName(TypeFullName);
_GetTypeFromFullNameCache.Add(TypeFullName, ret);
}
return ret;
}
/// <summary>
/// From the AssemblyQualifiedName or the FullName.
/// </summary>
static Type _GetTypeFromFullName(string TypeFullName)
{
var searchedType = Type.GetType(TypeFullName);
if (searchedType == null)
{
foreach (var assem in FrameworkTools.Framework.Assemblies.Value)
{
searchedType =
assem.GetType(TypeFullName);
if (searchedType != null)
break;
}
}
return searchedType;
}
static Dictionary<string, Type> _GetTypeFromFullNameCache = new Dictionary<string, Type>(100);
// -------------------------------------------
/// <summary>
/// Returns the FieldInfo from the field name.
/// </summary>
/// <param name="t"></param>
/// <param name="name"></param>
/// <returns></returns>
static public FieldInfo FieldInfoFromName(Type t, string name)
{
return t.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
// -------------------------------------------
/// <summary>
/// Get type name including generic parameters.
/// </summary>
static public string GetName(this Type t)
{
return Tools.GetNameAsCSharpStyle(t);
}
/// <summary>
/// Get type name including generic parameters.
/// Uses C# style.
/// </summary>
static public string GetNameAsCSharpStyle(this Type t)
{
if (t == null)
return null;
return LanguageStyle("<", ">", t);
}
/// <summary>
/// Get type name including generic parameters.
/// Uses VB style.
/// </summary>
static public string GetNameAsVBStyle(this Type t)
{
if (t == null)
return null;
return LanguageStyle("(Of ", ")", t);
}
internal static string LanguageStyle(string prefix, string suffix, Type type)
{
var gts = type.GetGenericArguments();
if (gts.Length > 0)
{
int cut = type.Name.IndexOf('`');
string mainName =
(cut < 0) ?
type.Name :
type.Name.Substring(0, cut);
StringBuilder sb = new StringBuilder(mainName);
sb.Append(prefix);
bool pendingElement = false;
foreach (var param in gts)
{
if (pendingElement)
sb.Append(", ");
sb.Append(LanguageStyle(prefix, suffix, param));
pendingElement = true;
}
sb.Append(suffix);
return sb.ToString();
}
else
return type.Name;
}
// -------------------------------------------
/// <summary>
/// Returns the derived type of ObjectType that correspond to SearchType.
/// Also works with interfaces and generic types.
/// </summary>
/// <returns></returns>
public static Type DerivedType(Type ObjectType, Type SearchedType)
{
return ObjectType.FindDerivedOrEqualToThisType(SearchedType);
}
// -------------------------------------------
/// <summary>
/// Returns the meeting SearchedType in the inheritance path of ObjectType.
/// Returns null of none.
/// Example: FindDerivedOrEqualToThisType(typeof(List<int>),typeof(List<>)) returns typeof(List<int>).
/// </summary>
/// <param name="ObjectType">The type to be analysed.</param>
/// <param name="SearchedType">Searched type. Can be generic with a type (as List<int>) of nothing (as List<>).</param>
/// <returns></returns>
public static Type FindDerivedOrEqualToThisType(this Type ObjectType, Type SearchedType)
{
if (ObjectType == SearchedType)
return ObjectType;
return ObjectType.FindDerivedToThisType(SearchedType);
}
// -------------------------------------------
/// <summary>
/// From the AssemblyQualifiedName or the FullName.
/// </summary>
public static Type FindDerivedOrEqualToThisType(this Type ObjectType, String SearchedTypeFullName)
{
if (ObjectType.FullName == SearchedTypeFullName)
return ObjectType;
return ObjectType.FindDerivedToThisType(GetTypeFromFullName(SearchedTypeFullName));
}
// -------------------------------------------
static Type ContainsThisType(Type[] array, Type value)
{
int length = array.Length;
for(int i=0;i<length;i++)
{
Type item = array[i];
Type comparableItem =
(value.IsGenericTypeDefinition && item.IsGenericType && !item.IsGenericTypeDefinition) ?
item.GetGenericTypeDefinition()
: item;
if (
(comparableItem == value)
||
((comparableItem.FullName == value.FullName)
#if !PORTABLE
&& (comparableItem.GUID == value.GUID)
#endif
))
return item;
}
return null;
}
// -------------------------------------------
internal static string TranscodeToXmlCompatibleString(string s)
{
if (s == null)
return s;
if (s.Length <= 10)
{
s = s.Replace("&", "&");
s = s.Replace("\b", string.Empty);// "" is a illegal character in xml. We remove it.
s = s.Replace("\f", string.Empty);// "" is a illegal character in xml. We remove it.
s = s.Replace("<", "<");
s = s.Replace(">", ">");
s = s.Replace("\"", """);
s = s.Replace("'", "'");// "'");
return s;
}
StringBuilder sb = new StringBuilder(s);
sb.Replace("&", "&");
sb.Replace("\b", string.Empty);// "" is a illegal character in xml. We remove it.
sb.Replace("\f", string.Empty);// "" is a illegal character in xml. We remove it.
sb.Replace("<", "<");
sb.Replace(">", ">");
sb.Replace("\"", """);
sb.Replace("'", "'");//"'");
return sb.ToString();
}
// -------------------------------------------
internal static string TranscodeToJSONCompatibleString(string s)
{
if (s == null)
return s;
// Escape list generated from System.Runtime.Serialization.Json.JsonReaderWriterFactory .
if (s.Length <= 10)
{
s = s.Replace(@"\", @"\\"); // '\' -> '\\'
s = s.Replace("\b", @"\b"); // 8 (backspace) -> '\b'
s = s.Replace("\t", @"\t"); // 9 (tab) -> '\t'
s = s.Replace("\n", @"\n"); // (new line, string depends on O.S.) -> '\n'
s = s.Replace("\f", @"\f"); // 12 (formfeed) -> '\f'
s = s.Replace("\r", @"\r"); // 13 (Carriage return, code depends on O.S.) -> '\r'
s = s.Replace("\"", "\\\""); // '' -> '\"'
return s;
}
StringBuilder sb = new StringBuilder(s);
sb.Replace(@"\", @"\\"); // '\' -> '\\'
sb.Replace("\b", @"\b"); // 8 (backspace) -> '\b'
sb.Replace("\t", @"\t"); // 9 (tab) -> '\t'
sb.Replace("\n", @"\n"); // (new line, string depends on O.S.) -> '\n'
sb.Replace("\f", @"\f"); // 12 (formfeed) -> '\f'
sb.Replace("\r", @"\r"); // 13 (Carriage return, code depends on O.S.) -> '\r'
sb.Replace("\"", "\\\""); // '' -> '\"'
return sb.ToString();
}
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
}
// ###############################################################
// ###############################################################
#if WINDOWS_PHONE || PORTABLE
/// <summary>
/// A simplified version of System.Lazy, for Windows Phone and PCL.
/// </summary>
public class Lazy<T> : SimpleLazy<T>
{
/// <summary>
/// Lazy constructor taking a definition function.
/// </summary>
/// <param name="valueFactory">The definition function.</param>
public Lazy(Func<T> valueFactory)
: base(valueFactory)
{
}
}
#endif
/// <summary>
/// A simplified version of System.Lazy, for Windows Phone and PCL.
/// Based on Mono, but thread management has been removed.
/// </summary>
public class SimpleLazy<T>
{
T value;
Func<T> factory;
Exception exception;
bool inited;
/// <summary>
/// Builds from a function.
/// </summary>
/// <param name="valueFactory"></param>
public SimpleLazy(Func<T> valueFactory)
{
if (valueFactory == null)
throw new ArgumentNullException("valueFactory");
this.factory = valueFactory;
}
/// <summary>
/// Gets the evaluated value.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public T Value
{
get
{
if (inited)
return value;
if (exception != null)
throw exception;
return InitValue();
}
}
T InitValue()
{
Func<T> init_factory;
T v;
{
init_factory = factory;
if (init_factory == null)
throw exception = new InvalidOperationException("The initialization function tries to access Value on this instance");
{
factory = null;
v = init_factory();
value = v;
inited = true;
}
}
return value;
}
/// <summary>
/// Returns true if the function has already been evaluated.
/// </summary>
public bool IsValueCreated
{
get
{
return inited;
}
}
/// <summary>
/// Gets the value as a string, or "<Value is not evaluated>".
/// </summary>
/// <returns></returns>
public override string ToString()
{
if (inited)
return value.ToString();
else
return "<Value is not evaluated>";
}
}
// ###############################################################
// ###############################################################
#if WINDOWS_PHONE || PORTABLE
// May be useful for .NET 3.5 also..
/// <summary>
/// Tree Expression extensions.
/// </summary>
public static class ExpressionEx
{
/// <summary>
/// Assign copies a value of an Expression to another Expression.
/// Internally, we use Expression.Add().
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static BinaryExpression Assign(Expression left, Expression right)
{
var assign = typeof(Assigner<>).MakeGenericType(left.Type).GetMethod("Assign");
var assignExpr = Expression.Add(left, right, assign);
return assignExpr;
}
private static class Assigner<T>
{
public static T Assign(ref T left, T right)
{
return (left = right);
}
}
}
#endif
#if false // possible future use
//http://allwpf.blogspot.fr/2009/11/in-project-i-currently-working-on-which.html
public static class ExpressionExtenstions
{
private class AssignmentHelper<TPropType>
{
private static void SetValue(ref TPropType target, TPropType value)
{
target = value;
}
internal static MethodInfo MethodInfoSetValue =
typeof(AssignmentHelper<TPropType>).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Static);
}
public static Expression<Action<TOwner, TPropType>> ToFieldAssignExpression<TOwner, TPropType>
(this Expression<Func<TOwner, TPropType>> fieldGetter)
{
if (fieldGetter == null)
throw new ArgumentNullException("fieldGetter");
if(fieldGetter.Parameters.Count != 1 || !(fieldGetter.Body is MemberExpression))
throw new ArgumentException ("Input expression must be a single parameter field getter, e.g. g => g._fieldToSet or function(g) g._fieldToSet");
ParameterExpression[] parms = new ParameterExpression[] {
fieldGetter.Parameters[0],
Expression.Parameter(typeof(TPropType), "value")};
Expression body = Expression.Call(AssignmentHelper<TPropType>.MethodInfoSetValue, new Expression[] { fieldGetter.Body, parms[1] });
return Expression.Lambda<Action<TOwner, TPropType>>(body, parms);
}
public static Action<TOwner, TPropType> ToFieldAssignment<TOwner, TPropType>
(
this Expression<Func<TOwner, TPropType>> fieldGetter
)
{
return fieldGetter.ToFieldAssignExpression().Compile();
}
}
#endif
// ###############################################################
// ###############################################################
}
// ###############################################################
// ###############################################################
namespace UniversalSerializerLib2.TypeTools
{
// ------------------------------
internal static class Types
{
// ------------------------------
internal static Type[] PrimitiveTypes = new Type[] {
null, //Empty = 0,
typeof(Object), // = 1,
#if !PORTABLE
typeof(DBNull), // = 2,
#else
null, // = 2, // No DBNull in that framework.
#endif
typeof(Boolean), // = 3,
typeof(Char), // = 4,
typeof(SByte), // = 5,
typeof(Byte), // = 6,
typeof(Int16), // = 7,
typeof(UInt16), // = 8,
typeof(Int32), // = 9,
typeof(UInt32), // = 10,
typeof(Int64), // = 11,
typeof(UInt64), // = 12,
typeof(Single), // = 13,
typeof(Double), // = 14,
typeof(Decimal), // = 15,
typeof(DateTime), // = 16,
typeof(String), // = 18,
};
internal static Type ObjectType = typeof(object);
// ------------------------------
/// <summary>
/// Returns all private fields including the inherited fields.
/// The list is sorted by name.
/// The reason for this function is .NET's GetFields() returns inherited public types but not inherited private types.
/// </summary>
/// <param name="type"></param>
/// <returns>The fields, sorted by name.</returns>
internal static IEnumerable<FieldInfo> GetPrivateFieldsIncludingInherited(this Type type)
{
var list = new Dictionary<string, FieldInfo>();
Type t=type;
do
{
foreach (var fi in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
{
if (!list.ContainsKey(fi.Name))
list.Add(fi.Name, fi);
}
t = t.BaseType;
} while (t != null);
return list.Select((kvp) => kvp.Value).OrderBy(fi=>fi.Name);
}
// ------------------------------
internal static bool MemberIsDeclaredAsNotSerializable(MemberInfo m)
{
object[] att = m.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false);
return (att != null && att.Length > 0);
}
// ------------------------------
#if WINDOWS_PHONE || PORTABLE
/// <summary>
/// From Mono.
/// </summary>
/// <param name="EnumType"></param>
/// <returns></returns>
internal static string[] GetEnumNames(this Type EnumType)
{
if (!EnumType.IsEnum)
throw new ArgumentException("Type is not an enumeration", "enumType");
var fields = EnumType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
string[] names = new string[fields.Length];
if (0 != names.Length)
{
for (int i = 0; i < fields.Length; ++i)
names[i] = fields[i].Name;
var et = EnumType;//.GetEnumUnderlyingType();
var values = Array.CreateInstance(et, names.Length);
for (int i = 0; i < fields.Length; ++i)
values.SetValue(fields[i].GetValue(null), i);
return names.OrderBy(s => s).ToArray();
}
return names;
}
/// <summary>
/// From Mono.
/// </summary>
/// <returns></returns>
internal static Array GetEnumValues(this Type EnumType)
{
if (!EnumType.IsEnum)
throw new ArgumentException("Type is not an enumeration", "enumType");
var fields = EnumType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
string[] names = new string[fields.Length];
if (0 != names.Length)
{
for (int i = 0; i < fields.Length; ++i)
names[i] = fields[i].Name;
var et =
EnumType;//.GetEnumUnderlyingType();
var values = Array.CreateInstance(et, names.Length);
for (int i = 0; i < fields.Length; ++i)
//values.SetValue(fields[i].GetRawConstantValue()/*.GetValue(null)*/, i);
values.SetValue(fields[i].GetRawConstantValue()/*.GetValue(null)*/, i);
return names.OrderBy(s => s).ToArray();
}
return names;
}
#endif
#if PORTABLE
internal static object GetRawConstantValue(this FieldInfo fieldInfo)
{
// from http://code.google.com/p/protobuf-net/source/browse/trunk/protobuf-net/Meta/ValueMember.cs. License: Apache 2.
object value = fieldInfo.GetValue(null);
switch(Type.GetTypeCode(Enum.GetUnderlyingType(fieldInfo.FieldType)))
{
case TypeCode.SByte: return (sbyte)value;
case TypeCode.Byte: return (byte)value;
case TypeCode.Int16: return (short)value;
case TypeCode.UInt16: return (ushort)value;
case TypeCode.Int32: return (int)value;
case TypeCode.UInt32: return (uint)value;
case TypeCode.Int64: return (long)value;
case TypeCode.UInt64: return (ulong)value;
default:
#if DEBUG
throw new InvalidOperationException();
#else
return null; // only for compilation.
#endif
}
}
#endif
}
}
// ###############################################################
// ###############################################################
namespace UniversalSerializerLib2.FileTools
{
internal static class Files
{ }
/// <summary>
/// Allows use of protected Read7BitEncodedInt().
/// </summary>
internal class BinaryReader2 : BinaryReader
{
public BinaryReader2(Stream input)
: base(input)
{ }
public BinaryReader2(Stream input, Encoding encoding)
: base(input,encoding)
{ }
/// <summary>
/// Reads compressed short from stream.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal short Read7BitEncodedShort()
{
return unchecked((short)this.Read7BitEncodedUShort());
}
/// <summary>
/// Reads compressed short from stream using special encoding.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal short ReadSpecial7BitEncodedShort()
{
return unchecked(Numbers.Special16ToInt16((short)this.Read7BitEncodedUShort()));
}
/// <summary>
/// Reads compressed ushort from stream.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal ushort Read7BitEncodedUShort()
{
ushort retValue = 0;
int shifter = 0;
while (shifter != 21) // 21 because 7*3 > 16 (bits).
{
byte b = this.ReadByte();
retValue |= (ushort)((ushort)(b & 0x7f) << shifter);
shifter += 7;
if ((b & 0x80) == 0)
{
return retValue;
}
}
#if DEBUG
throw new FormatException();
#else
return 0;
#endif
}
/// <summary>
/// Reads a compressed integer from the stream.
/// </summary>
/// <returns></returns>
public new int Read7BitEncodedInt()
{
return base.Read7BitEncodedInt(); // go to the protected method.
}
/// <summary>
/// Reads a compressed integer from the stream using special encoding.
/// </summary>
/// <returns></returns>
public int ReadSpecial7BitEncodedInt()
{
return Numbers.Special32ToInt32(base.Read7BitEncodedInt()); // go to the protected method.
}
/// <summary>
/// Reads a compressed unsigned integer from the stream.
/// </summary>
/// <returns></returns>
public uint Read7BitEncodedUInt()
{
return unchecked((uint)base.Read7BitEncodedInt()); // go to the protected method.
}
/// <summary>
/// Reads compressed long from stream.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal long Read7BitEncodedLong()
{
return unchecked((long)this.Read7BitEncodedULong());
}
/// <summary>
/// Reads compressed long from stream special encoding.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal long ReadSpecial7BitEncodedLong()
{
return Numbers.Special64ToInt64( unchecked((long)this.Read7BitEncodedULong()));
}
/// <summary>
/// Reads compressed long from stream.
/// </summary>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal ulong Read7BitEncodedULong()
{
ulong retValue = 0;
int shifter = 0;
while (shifter != 70) // 70 because 7*10 > 64 (bits).
{
byte b = this.ReadByte();
retValue |= (ulong)(b & 0x7f) << shifter;
shifter += 7;
if ((b & 0x80) == 0)
{
return retValue;
}
}
#if DEBUG
throw new FormatException();
#else
return 0;
#endif
}
#if (SILVERLIGHT || PORTABLE) && !WINDOWS_PHONE8
public decimal ReadDecimal()
{
int[] buffer = new int[4];// d.lo, d.mid, d.hi, d.flags
buffer[0] = this.ReadInt32();
buffer[1] = this.ReadInt32();
buffer[2] = this.ReadInt32();
buffer[3] = this.ReadInt32();
return new decimal(buffer);
}
#endif
}
/// <summary>
/// Allows use of protected Write7BitEncodedInt().
/// </summary>
internal class BinaryWriter2 : BinaryWriter
{
public BinaryWriter2(Stream output)
: base(output)
{ }
public BinaryWriter2(Stream output, Encoding encoding)
: base(output, encoding)
{ }
/// <summary>
/// Writes compressed short to stream.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void Write7BitEncodedShort(short value)
{
this.Write7BitEncodedUShort(unchecked((ushort)value));
}
/// <summary>
/// Writes compressed short to stream using special encoding.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void WriteSpecial7BitEncodedShort(short value)
{
this.Write7BitEncodedUShort(unchecked((ushort) Numbers.Int16ToSpecial16(value)));
}
/// <summary>
/// Writes compressed ushort to stream.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void Write7BitEncodedUShort(ushort value)
{
ushort number;
for (number = value; number >= (ushort)128u; number >>= 7)
this.Write(unchecked((byte)(number | (ushort)128u)));
this.Write((byte)number); // remaining bits.
}
/// <summary>
/// Writes a compressed integer to the stream.
/// </summary>
/// <param name="value"></param>
public new void Write7BitEncodedInt(int value)
{
base.Write7BitEncodedInt(value); // go to the protected method.
}
/// <summary>
/// Writes a compressed integer to the stream using special encoding.
/// </summary>
/// <param name="value"></param>
public void WriteSpecial7BitEncodedInt(int value)
{
base.Write7BitEncodedInt(Numbers.Int32ToSpecial32(value)); // go to the protected method.
}
/// <summary>
/// Writes a compressed unsigned integer to the stream.
/// </summary>
/// <param name="value"></param>
public void Write7BitEncodedUInt(uint value)
{
base.Write7BitEncodedInt(unchecked((int)value)); // go to the protected method.
}
/// <summary>
/// Writes compressed long to stream.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void Write7BitEncodedLong(long value)
{
this.Write7BitEncodedULong(unchecked((ulong)value));
}
/// <summary>
/// Writes compressed long to stream using special encoding.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void WriteSpecial7BitEncodedLong(long value)
{
this.Write7BitEncodedULong(unchecked((ulong)Numbers.Int64ToSpecial64(value)));
}
/// <summary>
/// Writes compressed ulong to stream.
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl((System.Runtime.CompilerServices.MethodImplOptions)256)] // AggressiveInlining
internal void Write7BitEncodedULong(ulong value)
{
ulong number;
for (number = value; number >= 128ul; number >>= 7)
this.Write(unchecked((byte)(number | 128ul)));
this.Write((byte)number); // remaining bits.
}
#if (SILVERLIGHT || PORTABLE) && !WINDOWS_PHONE8
public void WriteDecimal(decimal value)
{
var ints = decimal.GetBits(value); // returns d.lo, d.mid, d.hi, d.flags.
foreach (int i in ints)
this.Write(i);
}
#endif
}
}
// ###############################################################
// ###############################################################
namespace UniversalSerializerLib2.DataTools
{
// ###############################################################
// ###############################################################
internal static class Data
{
// -------------------------------------------
public class ComparableKeyValuePair<TKey, TValue> : IEquatable<ComparableKeyValuePair<TKey, TValue>>, IEqualityComparer
where TKey : class//IEquatable<TKey>
where TValue : class//IEquatable<TValue>
{
public readonly TKey Key;
public readonly TValue Value;
public ComparableKeyValuePair(TKey Key, TValue Value)
{
this.Key = Key;
this.Value = Value;
}
public static bool operator ==(ComparableKeyValuePair<TKey, TValue> A, ComparableKeyValuePair<TKey, TValue> B)
{
//return A.Key.Equals(B.Key) && A.Value.Equals(B.Value);
return A.Key == B.Key && A.Value == B.Value;
}
public static bool operator !=(ComparableKeyValuePair<TKey, TValue> A, ComparableKeyValuePair<TKey, TValue> B)
{
//return !A.Key.Equals(B.Key) || !A.Value.Equals(B.Value);
return A.Key != B.Key || A.Value != B.Value;
}
public override bool Equals(object obj)
{
if (!(obj is ComparableKeyValuePair<TKey, TValue>))
return false;
return this == (ComparableKeyValuePair<TKey, TValue>)obj;
}
public override int GetHashCode()
{
return this.Key.GetHashCode() ^ this.Value.GetHashCode();
}
public bool Equals(ComparableKeyValuePair<TKey, TValue> other)
{
return this == other;
}
public new bool Equals(object x, object y)
{
ComparableKeyValuePair<TKey, TValue> X = (ComparableKeyValuePair<TKey, TValue>)x;
ComparableKeyValuePair<TKey, TValue> Y = (ComparableKeyValuePair<TKey, TValue>)y;
return x == y;
}
public int GetHashCode(object obj)
{
ComparableKeyValuePair<TKey, TValue> o = (ComparableKeyValuePair<TKey, TValue>)obj;
return o.Key.GetHashCode() ^ o.Value.GetHashCode();
}
}
// -------------------------------------------
internal static void AddRangeNoDuplicate<T>(this List<T> list, IEnumerable<T> collection)
{
foreach (T item in collection)
if (!list.Contains(item))
list.Add(item);
}
// -------------------------------------------
/// <summary>
/// Find the index of an item in the enumerable.
/// Please note that arrays already have a IndexOf method, but static.
/// </summary>
/// <param name="enumerable"></param>
/// <param name="o"></param>
/// <returns>The item index, or -1 if it has not been found.</returns>
internal static int IndexOf(this IEnumerable enumerable, object o)
{
Array array = enumerable as Array;
if (array != null)
return array.IndexOf(o);
int i = 0;
foreach (var item in enumerable)
{
if (item == o)
return i;
i++;
}
return -1;
}
// -------------------------------------------
/// <summary>
/// Find the index of an item in the enumerable.
/// Please note that arrays already have a IndexOf method, but static.
/// </summary>
/// <param name="enumerable"></param>
/// <param name="o"></param>
/// <returns>The item index, or -1 if it has not been found.</returns>
internal static int IndexOf2<T>(this IEnumerable<T> enumerable, T o)
where T : class
{
/*Array array = enumerable as Array;
if (array != null)
return array.IndexOf(o);*/
int i = 0;
foreach (var item in enumerable)
{
if (item==o)
return i;
i++;
}
return -1;
}
// -------------------------------------------
}
// ###############################################################
/// <summary>
/// A generic limited-size dictionary.
/// Maximum size is given by the constructor.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
internal class LimitedSizeDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
Queue<TKey> queue;
readonly int MaximumSize;
public LimitedSizeDictionary(int MaximumSize)
: base(MaximumSize + 1)
{
this.MaximumSize = MaximumSize;
queue = new Queue<TKey>(MaximumSize);
}
public new void Add(TKey key, TValue value)
{
this.Add(key, value);
if (queue.Count == MaximumSize)
this.Remove(queue.Dequeue());
queue.Enqueue(key);
}
public new bool Remove(TKey key)
{
if (this.Remove(key))
{
Queue<TKey> newQueue = new Queue<TKey>(MaximumSize);
foreach (TKey item in queue)
if (!this.Comparer.Equals(item, key))
newQueue.Enqueue(item);
queue = newQueue;
return true;
}
else
return false;
}
}
// ###############################################################
/// <summary>
/// A generic limited-size dictionary that will eliminate least used items on priority.
/// Maximum size is given by the constructor.
/// It is optimized for small size (10 items or less). Hash codes is not used.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
internal class FrequencyOrderedLimitedSizeDict<TKey, TValue>:IDictionary<TKey,TValue>
where TKey : class
{
readonly TKey[] Keys;
readonly TValue[] Values;
readonly int[] Counters;
readonly int MaximumSize;
int CurrentCount;
public FrequencyOrderedLimitedSizeDict(int MaximumSize)
{
this.MaximumSize = MaximumSize;
this.Counters=new int[MaximumSize];
this.Keys = new TKey[MaximumSize];
this.Values = new TValue[MaximumSize];
}
public void Add(TKey key, TValue value)
{
// 1. get a free index:
int index = this.CurrentCount;
if (index >= this.MaximumSize)
{ // replace the least-used item
int count = int.MaxValue;
for (int i = 0; i < this.CurrentCount; i++)
{
int counter = Counters[i];
if (counter < count)
{
index = i;
count = counter;
}
}
Counters[index] = 0;
}
else
this.CurrentCount++;
// 2. set the item in the free index:
this.Keys[index] = key;
this.Values[index] = value;
Counters[index]++;
}
public bool Remove(TKey key)
{
if (key.Equals(default(TKey)))
throw new ArgumentNullException(); // We need a set value.
int index = this.Keys.IndexOf2(key);
if (index < 0)
return false;
this.Keys[index] = default(TKey);
this.Counters[index] = 0;
return true;
}
public bool ContainsKey(TKey key)
{
throw new NotImplementedException();
}
ICollection<TKey> IDictionary<TKey, TValue>.Keys
{
get { throw new NotImplementedException(); }
}
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.Keys.IndexOf2(key);
if (index < 0)
{
value = default(TValue);
return false;
}
value = this.Values[index];
this.Counters[index]++;
return true;
}
ICollection<TValue> IDictionary<TKey, TValue>.Values
{
get { throw new NotImplementedException(); }
}
public TValue this[TKey key]
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
throw new NotImplementedException();
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public int Count
{
get { throw new NotImplementedException(); }
}
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
throw new NotImplementedException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
// ###############################################################
// ###############################################################
// ###############################################################
// ###############################################################
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
// -------------------------------------------
}
// ###############################################################
// ###############################################################
namespace UniversalSerializerLib2.FrameworkTools
{
internal static class Framework
{
internal static readonly Lazy<Assembly[]> Assemblies =
new Lazy<Assembly[]>(() =>
#if !PORTABLE
AppDomain.CurrentDomain.GetAssemblies());
#else
{
return AppDomain.Assemblies;
});
#endif
}
#if PORTABLE
/// <summary>
/// We try to obtain current AppDomain using reflection.
/// </summary>
internal static class AppDomain
{
/// <summary>
/// Can be null.
/// </summary>
internal static object CurrentDomain {get; private set;}
/// <summary>
/// Always defined, but can be empty if not found by reflexion in the framework.
/// </summary>
internal static Assembly[] Assemblies { get; private set; }
static AppDomain()
{
var tAppDomain = Type.GetType("System.AppDomain");
if (tAppDomain != null)
{
var pi=tAppDomain.GetProperty("CurrentDomain", BindingFlags.Static | BindingFlags.Public);
if (pi != null)
{
CurrentDomain = pi.GetValue(null, null);
if (CurrentDomain != null)
{
var mi=CurrentDomain.GetType().GetMethod("GetAssemblies", BindingFlags.Instance | BindingFlags.Public);
if (mi != null)
Assemblies = (Assembly[])mi.Invoke(CurrentDomain, null);
}
}
}
if (Assemblies == null)
Assemblies = new Assembly[0];
}
} // class AppDomain
#endif // PORTABLE
}
// ###############################################################
// ###############################################################
namespace UniversalSerializerLib2.NumberTools
{
internal static class Numbers
{
#region Special integers
/*
* 'Special' integers are signed integers where negative values have their bits reversed (except the higher bit),
* then value is rotated one bit left, the higher bit goes to the lower site.
* The objective is to reduce the number of set (1) bits for small negative numbers.
* The compresser considers small numbers (positive or negative) as more frequent and optimizes their storage size.
*
* The transcoding method is the same in the two directions, but I wrote one function for each direction for clarity reasons.
*/
internal static short Int16ToSpecial16(short i)
{
if (i >= 0)
return (short)(i << 1);
return unchecked((short)((i << 1) ^ -1));
}
internal static short Special16ToInt16(short i)
{
if ((i & 1) == 0)
return (short)((uint)(ushort)i >> 1);
return unchecked((short)((((uint)(ushort)i >> 1)) ^ -1));
}
internal static int Int32ToSpecial32(int i)
{
if (i >= 0)
return i << 1;
return (i << 1) ^ -1;
}
internal static int Special32ToInt32(int i)
{
if ((i & 1) == 0)
return (int)((uint)i >> 1);
return ((int)((uint)i >> 1)) ^ -1;
}
internal static long Int64ToSpecial64(long i)
{
if (i >= 0)
return i << 1;
return (i << 1) ^ -1L;
}
internal static long Special64ToInt64(long i)
{
if ((i & 1) == 0)
return (long)((ulong)i >> 1);
return ((long)((ulong)i >> 1)) ^ -1L;
}
#endregion Special integers
}
}
// ###############################################################
// ###############################################################
// ###############################################################