Skip to content

Commit 75fc3a9

Browse files
committed
Initial code commit, forked from: https://github.com/Konard/LinksPlatform
1 parent 04f4dcc commit 75fc3a9

14 files changed

+626
-0
lines changed

ArithmeticExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Platform.Numbers
2+
{
3+
public static class ArithmeticExtensions
4+
{
5+
public static T Decrement<T>(this ref T x) where T : struct => x = ArithmeticHelpers<T>.Decrement(x);
6+
public static T Increment<T>(this ref T x) where T : struct => x = ArithmeticHelpers<T>.Increment(x);
7+
}
8+
}

ArithmeticHelpers.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Platform.Numbers
2+
{
3+
public class ArithmeticHelpers
4+
{
5+
public static T Add<T>(T x, T y) => ArithmeticHelpers<T>.Add(x, y);
6+
public static T And<T>(T x, T y) => ArithmeticHelpers<T>.And(x, y);
7+
public static T Increment<T>(T x) => ArithmeticHelpers<T>.Increment(x);
8+
public static T Subtract<T>(T x, T y) => ArithmeticHelpers<T>.Subtract(x, y);
9+
public static T Subtract<T>(Integer<T> x, Integer<T> y) => ArithmeticHelpers<T>.Subtract(x, y);
10+
public static T Decrement<T>(T x) => ArithmeticHelpers<T>.Decrement(x);
11+
}
12+
}

ArithmeticHelpers[T].cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using Platform.Reflection;
3+
using Platform.Reflection.Sigil;
4+
5+
// ReSharper disable StaticFieldInGenericType
6+
7+
namespace Platform.Numbers
8+
{
9+
public class ArithmeticHelpers<T>
10+
{
11+
public static readonly Func<T, T, T> Add;
12+
public static readonly Func<T, T, T> And;
13+
public static readonly Func<T, T> Increment;
14+
public static readonly Func<T, T, T> Subtract;
15+
public static readonly Func<T, T> Decrement;
16+
17+
static ArithmeticHelpers()
18+
{
19+
DelegateHelpers.Compile(out Add, emiter =>
20+
{
21+
if (!CachedTypeInfo<T>.IsNumeric)
22+
throw new NotSupportedException();
23+
24+
emiter.LoadArguments(0, 1);
25+
emiter.Add();
26+
emiter.Return();
27+
});
28+
29+
DelegateHelpers.Compile(out And, emiter =>
30+
{
31+
if (!CachedTypeInfo<T>.IsNumeric)
32+
throw new NotSupportedException();
33+
34+
emiter.LoadArguments(0, 1);
35+
emiter.And();
36+
emiter.Return();
37+
});
38+
39+
DelegateHelpers.Compile(out Increment, emiter =>
40+
{
41+
if (!CachedTypeInfo<T>.IsNumeric)
42+
throw new NotSupportedException();
43+
44+
emiter.LoadArgument(0);
45+
emiter.Increment(typeof(T));
46+
emiter.Return();
47+
});
48+
49+
DelegateHelpers.Compile(out Subtract, emiter =>
50+
{
51+
if (!CachedTypeInfo<T>.IsNumeric)
52+
throw new NotSupportedException();
53+
54+
emiter.LoadArguments(0, 1);
55+
emiter.Subtract();
56+
emiter.Return();
57+
});
58+
59+
DelegateHelpers.Compile(out Decrement, emiter =>
60+
{
61+
if (!CachedTypeInfo<T>.IsNumeric)
62+
throw new NotSupportedException();
63+
64+
emiter.LoadArgument(0);
65+
emiter.Decrement(typeof(T));
66+
emiter.Return();
67+
});
68+
}
69+
}
70+
}

BitwiseExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Platform.Numbers
2+
{
3+
public static class BitwiseExtensions
4+
{
5+
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);
6+
public static T PartialRead<T>(this T target, int shift, int limit) => BitwiseHelpers<T>.PartialRead(target, shift, limit);
7+
}
8+
}

BitwiseHelpers.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
namespace Platform.Numbers
2+
{
3+
public static class BitwiseHelpers
4+
{
5+
public static long CountBits(long x)
6+
{
7+
long n = 0;
8+
while (x != 0)
9+
{
10+
n++;
11+
x = x & x - 1;
12+
}
13+
return n;
14+
}
15+
16+
public static int GetLowestBitPosition(ulong value)
17+
{
18+
if (value == 0)
19+
return -1;
20+
21+
var position = 0;
22+
while ((value & 1UL) == 0)
23+
{
24+
value >>= 1;
25+
++position;
26+
}
27+
return position;
28+
}
29+
30+
public static T PartialWrite<T>(T target, T source, int shift, int limit) => BitwiseHelpers<T>.PartialWrite(target, source, shift, limit);
31+
32+
public static T PartialRead<T>(T target, int shift, int limit) => BitwiseHelpers<T>.PartialRead(target, shift, limit);
33+
}
34+
}

BitwiseHelpers[T].cs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using System;
2+
using Platform.Reflection;
3+
using Platform.Reflection.Sigil;
4+
5+
// ReSharper disable StaticFieldInGenericType
6+
7+
namespace Platform.Numbers
8+
{
9+
public static class BitwiseHelpers<T>
10+
{
11+
public static readonly Func<T, T, int, int, T> PartialWrite;
12+
public static readonly Func<T, int, int, T> PartialRead;
13+
14+
static BitwiseHelpers()
15+
{
16+
DelegateHelpers.Compile(out PartialWrite, emiter =>
17+
{
18+
if (!CachedTypeInfo<T>.IsNumeric)
19+
throw new NotSupportedException();
20+
21+
var constants = GetConstants<T>();
22+
var bitsNumber = constants.Item1;
23+
var numberFilledWithOnes = constants.Item2;
24+
25+
ushort shiftArgument = 2;
26+
ushort limitArgument = 3;
27+
28+
var checkLimit = emiter.DefineLabel();
29+
var calculateSourceMask = emiter.DefineLabel();
30+
31+
// Check shift
32+
emiter.LoadArgument(shiftArgument);
33+
emiter.LoadConstant(0);
34+
emiter.BranchIfGreaterOrEqual(checkLimit); // Skip fix
35+
36+
// Fix shift
37+
emiter.LoadConstant(bitsNumber);
38+
emiter.LoadArgument(shiftArgument);
39+
emiter.Add();
40+
emiter.StoreArgument(shiftArgument);
41+
42+
emiter.MarkLabel(checkLimit);
43+
// Check limit
44+
emiter.LoadArgument(limitArgument);
45+
emiter.LoadConstant(0);
46+
emiter.BranchIfGreaterOrEqual(calculateSourceMask); // Skip fix
47+
48+
// Fix limit
49+
emiter.LoadConstant(bitsNumber);
50+
emiter.LoadArgument(limitArgument);
51+
emiter.Add();
52+
emiter.StoreArgument(limitArgument);
53+
54+
emiter.MarkLabel(calculateSourceMask);
55+
56+
using (var sourceMask = emiter.DeclareLocal<T>())
57+
using (var targetMask = emiter.DeclareLocal<T>())
58+
{
59+
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
60+
emiter.LoadArgument(limitArgument);
61+
emiter.ShiftLeft();
62+
emiter.Not();
63+
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
64+
emiter.And();
65+
emiter.StoreLocal(sourceMask);
66+
67+
emiter.LoadLocal(sourceMask);
68+
emiter.LoadArgument(shiftArgument);
69+
emiter.ShiftLeft();
70+
emiter.Not();
71+
emiter.StoreLocal(targetMask);
72+
73+
emiter.LoadArgument(0); // target
74+
emiter.LoadLocal(targetMask);
75+
emiter.And();
76+
emiter.LoadArgument(1); // source
77+
emiter.LoadLocal(sourceMask);
78+
emiter.And();
79+
emiter.LoadArgument(shiftArgument);
80+
emiter.ShiftLeft();
81+
emiter.Or();
82+
}
83+
84+
emiter.Return();
85+
});
86+
87+
DelegateHelpers.Compile(out PartialRead, emiter =>
88+
{
89+
if (!CachedTypeInfo<T>.IsNumeric)
90+
throw new NotSupportedException();
91+
92+
var constants = GetConstants<T>();
93+
var bitsNumber = constants.Item1;
94+
var numberFilledWithOnes = constants.Item2;
95+
96+
ushort shiftArgument = 1;
97+
ushort limitArgument = 2;
98+
99+
var checkLimit = emiter.DefineLabel();
100+
var calculateSourceMask = emiter.DefineLabel();
101+
102+
// Check shift
103+
emiter.LoadArgument(shiftArgument);
104+
emiter.LoadConstant(0);
105+
emiter.BranchIfGreaterOrEqual(checkLimit); // Skip fix
106+
107+
// Fix shift
108+
emiter.LoadConstant(bitsNumber);
109+
emiter.LoadArgument(shiftArgument);
110+
emiter.Add();
111+
emiter.StoreArgument(shiftArgument);
112+
113+
emiter.MarkLabel(checkLimit);
114+
// Check limit
115+
emiter.LoadArgument(limitArgument);
116+
emiter.LoadConstant(0);
117+
emiter.BranchIfGreaterOrEqual(calculateSourceMask); // Skip fix
118+
119+
// Fix limit
120+
emiter.LoadConstant(bitsNumber);
121+
emiter.LoadArgument(limitArgument);
122+
emiter.Add();
123+
emiter.StoreArgument(limitArgument);
124+
125+
emiter.MarkLabel(calculateSourceMask);
126+
127+
using (var sourceMask = emiter.DeclareLocal<T>())
128+
using (var targetMask = emiter.DeclareLocal<T>())
129+
{
130+
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
131+
emiter.LoadArgument(limitArgument); // limit
132+
emiter.ShiftLeft();
133+
emiter.Not();
134+
emiter.LoadConstant(typeof(T), numberFilledWithOnes);
135+
emiter.And();
136+
emiter.StoreLocal(sourceMask);
137+
138+
emiter.LoadLocal(sourceMask);
139+
emiter.LoadArgument(shiftArgument);
140+
emiter.ShiftLeft();
141+
emiter.StoreLocal(targetMask);
142+
143+
emiter.LoadArgument(0); // target
144+
emiter.LoadLocal(targetMask);
145+
emiter.And();
146+
emiter.LoadArgument(shiftArgument);
147+
emiter.ShiftRight();
148+
}
149+
150+
emiter.Return();
151+
});
152+
}
153+
154+
private static Tuple<int, TElement> GetConstants<TElement>()
155+
{
156+
var type = typeof(T);
157+
if (type == typeof(ulong))
158+
return new Tuple<int, TElement>(64, (TElement)(object)ulong.MaxValue);
159+
if (type == typeof(uint))
160+
return new Tuple<int, TElement>(32, (TElement)(object)uint.MaxValue);
161+
if (type == typeof(ushort))
162+
return new Tuple<int, TElement>(16, (TElement)(object)ushort.MaxValue);
163+
if (type == typeof(byte))
164+
return new Tuple<int, TElement>(8, (TElement)(object)byte.MaxValue);
165+
throw new NotSupportedException();
166+
}
167+
}
168+
}

Integer.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Platform.Converters;
2+
3+
namespace Platform.Numbers
4+
{
5+
public struct Integer
6+
{
7+
public readonly ulong Value;
8+
9+
public Integer(ulong value) => Value = value;
10+
11+
public static implicit operator Integer(ulong integer) => new Integer(integer);
12+
13+
public static implicit operator Integer(long integer) => To.UInt64(integer);
14+
15+
public static implicit operator Integer(uint integer) => new Integer(integer);
16+
17+
public static implicit operator Integer(int integer) => To.UInt64(integer);
18+
19+
public static implicit operator Integer(ushort integer) => new Integer(integer);
20+
21+
public static implicit operator Integer(short integer) => To.UInt64(integer);
22+
23+
public static implicit operator Integer(byte integer) => new Integer(integer);
24+
25+
public static implicit operator Integer(sbyte integer) => To.UInt64(integer);
26+
27+
public static implicit operator Integer(bool integer) => To.UInt64(integer);
28+
29+
public static implicit operator ulong(Integer integer) => integer.Value;
30+
31+
public static implicit operator long(Integer integer) => To.Int64(integer.Value);
32+
33+
public static implicit operator uint(Integer integer) => To.UInt32(integer.Value);
34+
35+
public static implicit operator int(Integer integer) => To.Int32(integer.Value);
36+
37+
public static implicit operator ushort(Integer integer) => To.UInt16(integer.Value);
38+
39+
public static implicit operator short(Integer integer) => To.Int16(integer.Value);
40+
41+
public static implicit operator byte(Integer integer) => To.Byte(integer.Value);
42+
43+
public static implicit operator sbyte(Integer integer) => To.SByte(integer.Value);
44+
45+
public static implicit operator bool(Integer integer) => To.Boolean(integer.Value);
46+
47+
public override string ToString() => Value.ToString();
48+
}
49+
}

0 commit comments

Comments
 (0)