Skip to content

Commit

Permalink
Initial code commit, forked from: https://github.com/Konard/LinksPlat…
Browse files Browse the repository at this point in the history
  • Loading branch information
Konard committed Jul 20, 2019
1 parent 04f4dcc commit 75fc3a9
Show file tree
Hide file tree
Showing 14 changed files with 626 additions and 0 deletions.
8 changes: 8 additions & 0 deletions ArithmeticExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Platform.Numbers
{
public static class ArithmeticExtensions
{
public static T Decrement<T>(this ref T x) where T : struct => x = ArithmeticHelpers<T>.Decrement(x);
public static T Increment<T>(this ref T x) where T : struct => x = ArithmeticHelpers<T>.Increment(x);
}
}
12 changes: 12 additions & 0 deletions ArithmeticHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Platform.Numbers
{
public class ArithmeticHelpers
{
public static T Add<T>(T x, T y) => ArithmeticHelpers<T>.Add(x, y);
public static T And<T>(T x, T y) => ArithmeticHelpers<T>.And(x, y);
public static T Increment<T>(T x) => ArithmeticHelpers<T>.Increment(x);
public static T Subtract<T>(T x, T y) => ArithmeticHelpers<T>.Subtract(x, y);
public static T Subtract<T>(Integer<T> x, Integer<T> y) => ArithmeticHelpers<T>.Subtract(x, y);
public static T Decrement<T>(T x) => ArithmeticHelpers<T>.Decrement(x);
}
}
70 changes: 70 additions & 0 deletions ArithmeticHelpers[T].cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using Platform.Reflection;
using Platform.Reflection.Sigil;

// ReSharper disable StaticFieldInGenericType

namespace Platform.Numbers
{
public class ArithmeticHelpers<T>
{
public static readonly Func<T, T, T> Add;
public static readonly Func<T, T, T> And;
public static readonly Func<T, T> Increment;
public static readonly Func<T, T, T> Subtract;
public static readonly Func<T, T> Decrement;

static ArithmeticHelpers()
{
DelegateHelpers.Compile(out Add, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

emiter.LoadArguments(0, 1);
emiter.Add();
emiter.Return();
});

DelegateHelpers.Compile(out And, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

emiter.LoadArguments(0, 1);
emiter.And();
emiter.Return();
});

DelegateHelpers.Compile(out Increment, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

emiter.LoadArgument(0);
emiter.Increment(typeof(T));
emiter.Return();
});

DelegateHelpers.Compile(out Subtract, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

emiter.LoadArguments(0, 1);
emiter.Subtract();
emiter.Return();
});

DelegateHelpers.Compile(out Decrement, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

emiter.LoadArgument(0);
emiter.Decrement(typeof(T));
emiter.Return();
});
}
}
}
8 changes: 8 additions & 0 deletions BitwiseExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Platform.Numbers
{
public static class BitwiseExtensions
{
public static T PartialWrite<T>(this ref T target, T source, int shift, int limit) where T : struct => target = BitwiseHelpers<T>.PartialWrite(target, source, shift, limit);
public static T PartialRead<T>(this T target, int shift, int limit) => BitwiseHelpers<T>.PartialRead(target, shift, limit);
}
}
34 changes: 34 additions & 0 deletions BitwiseHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Platform.Numbers
{
public static class BitwiseHelpers
{
public static long CountBits(long x)
{
long n = 0;
while (x != 0)
{
n++;
x = x & x - 1;
}
return n;
}

public static int GetLowestBitPosition(ulong value)
{
if (value == 0)
return -1;

var position = 0;
while ((value & 1UL) == 0)
{
value >>= 1;
++position;
}
return position;
}

public static T PartialWrite<T>(T target, T source, int shift, int limit) => BitwiseHelpers<T>.PartialWrite(target, source, shift, limit);

public static T PartialRead<T>(T target, int shift, int limit) => BitwiseHelpers<T>.PartialRead(target, shift, limit);
}
}
168 changes: 168 additions & 0 deletions BitwiseHelpers[T].cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System;
using Platform.Reflection;
using Platform.Reflection.Sigil;

// ReSharper disable StaticFieldInGenericType

namespace Platform.Numbers
{
public static class BitwiseHelpers<T>
{
public static readonly Func<T, T, int, int, T> PartialWrite;
public static readonly Func<T, int, int, T> PartialRead;

static BitwiseHelpers()
{
DelegateHelpers.Compile(out PartialWrite, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

var constants = GetConstants<T>();
var bitsNumber = constants.Item1;
var numberFilledWithOnes = constants.Item2;

ushort shiftArgument = 2;
ushort limitArgument = 3;

var checkLimit = emiter.DefineLabel();
var calculateSourceMask = emiter.DefineLabel();

// Check shift
emiter.LoadArgument(shiftArgument);
emiter.LoadConstant(0);
emiter.BranchIfGreaterOrEqual(checkLimit); // Skip fix

// Fix shift
emiter.LoadConstant(bitsNumber);
emiter.LoadArgument(shiftArgument);
emiter.Add();
emiter.StoreArgument(shiftArgument);

emiter.MarkLabel(checkLimit);
// Check limit
emiter.LoadArgument(limitArgument);
emiter.LoadConstant(0);
emiter.BranchIfGreaterOrEqual(calculateSourceMask); // Skip fix

// Fix limit
emiter.LoadConstant(bitsNumber);
emiter.LoadArgument(limitArgument);
emiter.Add();
emiter.StoreArgument(limitArgument);

emiter.MarkLabel(calculateSourceMask);

using (var sourceMask = emiter.DeclareLocal<T>())
using (var targetMask = emiter.DeclareLocal<T>())
{
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
emiter.LoadArgument(limitArgument);
emiter.ShiftLeft();
emiter.Not();
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
emiter.And();
emiter.StoreLocal(sourceMask);

emiter.LoadLocal(sourceMask);
emiter.LoadArgument(shiftArgument);
emiter.ShiftLeft();
emiter.Not();
emiter.StoreLocal(targetMask);

emiter.LoadArgument(0); // target
emiter.LoadLocal(targetMask);
emiter.And();
emiter.LoadArgument(1); // source
emiter.LoadLocal(sourceMask);
emiter.And();
emiter.LoadArgument(shiftArgument);
emiter.ShiftLeft();
emiter.Or();
}

emiter.Return();
});

DelegateHelpers.Compile(out PartialRead, emiter =>
{
if (!CachedTypeInfo<T>.IsNumeric)
throw new NotSupportedException();

var constants = GetConstants<T>();
var bitsNumber = constants.Item1;
var numberFilledWithOnes = constants.Item2;

ushort shiftArgument = 1;
ushort limitArgument = 2;

var checkLimit = emiter.DefineLabel();
var calculateSourceMask = emiter.DefineLabel();

// Check shift
emiter.LoadArgument(shiftArgument);
emiter.LoadConstant(0);
emiter.BranchIfGreaterOrEqual(checkLimit); // Skip fix

// Fix shift
emiter.LoadConstant(bitsNumber);
emiter.LoadArgument(shiftArgument);
emiter.Add();
emiter.StoreArgument(shiftArgument);

emiter.MarkLabel(checkLimit);
// Check limit
emiter.LoadArgument(limitArgument);
emiter.LoadConstant(0);
emiter.BranchIfGreaterOrEqual(calculateSourceMask); // Skip fix

// Fix limit
emiter.LoadConstant(bitsNumber);
emiter.LoadArgument(limitArgument);
emiter.Add();
emiter.StoreArgument(limitArgument);

emiter.MarkLabel(calculateSourceMask);

using (var sourceMask = emiter.DeclareLocal<T>())
using (var targetMask = emiter.DeclareLocal<T>())
{
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
emiter.LoadArgument(limitArgument); // limit
emiter.ShiftLeft();
emiter.Not();
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
emiter.And();
emiter.StoreLocal(sourceMask);

emiter.LoadLocal(sourceMask);
emiter.LoadArgument(shiftArgument);
emiter.ShiftLeft();
emiter.StoreLocal(targetMask);

emiter.LoadArgument(0); // target
emiter.LoadLocal(targetMask);
emiter.And();
emiter.LoadArgument(shiftArgument);
emiter.ShiftRight();
}

emiter.Return();
});
}

private static Tuple<int, TElement> GetConstants<TElement>()
{
var type = typeof(T);
if (type == typeof(ulong))
return new Tuple<int, TElement>(64, (TElement)(object)ulong.MaxValue);
if (type == typeof(uint))
return new Tuple<int, TElement>(32, (TElement)(object)uint.MaxValue);
if (type == typeof(ushort))
return new Tuple<int, TElement>(16, (TElement)(object)ushort.MaxValue);
if (type == typeof(byte))
return new Tuple<int, TElement>(8, (TElement)(object)byte.MaxValue);
throw new NotSupportedException();
}
}
}
49 changes: 49 additions & 0 deletions Integer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Platform.Converters;

namespace Platform.Numbers
{
public struct Integer
{
public readonly ulong Value;

public Integer(ulong value) => Value = value;

public static implicit operator Integer(ulong integer) => new Integer(integer);

public static implicit operator Integer(long integer) => To.UInt64(integer);

public static implicit operator Integer(uint integer) => new Integer(integer);

public static implicit operator Integer(int integer) => To.UInt64(integer);

public static implicit operator Integer(ushort integer) => new Integer(integer);

public static implicit operator Integer(short integer) => To.UInt64(integer);

public static implicit operator Integer(byte integer) => new Integer(integer);

public static implicit operator Integer(sbyte integer) => To.UInt64(integer);

public static implicit operator Integer(bool integer) => To.UInt64(integer);

public static implicit operator ulong(Integer integer) => integer.Value;

public static implicit operator long(Integer integer) => To.Int64(integer.Value);

public static implicit operator uint(Integer integer) => To.UInt32(integer.Value);

public static implicit operator int(Integer integer) => To.Int32(integer.Value);

public static implicit operator ushort(Integer integer) => To.UInt16(integer.Value);

public static implicit operator short(Integer integer) => To.Int16(integer.Value);

public static implicit operator byte(Integer integer) => To.Byte(integer.Value);

public static implicit operator sbyte(Integer integer) => To.SByte(integer.Value);

public static implicit operator bool(Integer integer) => To.Boolean(integer.Value);

public override string ToString() => Value.ToString();
}
}
Loading

1 comment on commit 75fc3a9

@Konard
Copy link
Member Author

@Konard Konard commented on 75fc3a9 Aug 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.