/Arrays.cs |
@@ -8,7 +8,7 @@ |
|
namespace wasSharp |
{ |
public class Arrays |
public static class Arrays |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
@@ -22,13 +22,7 @@ |
/// <return>an array element</return> |
public static T GetElementAt<T>(T[] data, int index) |
{ |
switch (index < 0) |
{ |
case true: |
return data[((index%data.Length) + data.Length)%data.Length]; |
default: |
return data[index%data.Length]; |
} |
return index < 0 ? data[(index%data.Length + data.Length)%data.Length] : data[index%data.Length]; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
@@ -46,7 +40,7 @@ |
{ |
if (stop.Equals(-1)) |
stop = data.Length - 1; |
T[] result = new T[stop - start + 1]; |
var result = new T[stop - start + 1]; |
Array.Copy(data, start, result, 0, stop - start + 1); |
return result; |
} |
@@ -66,7 +60,7 @@ |
{ |
if (stop.Equals(-1)) |
stop = data.Length - 1; |
T[] result = new T[data.Length - (stop - start) - 1]; |
var result = new T[data.Length - (stop - start) - 1]; |
Array.Copy(data, 0, result, 0, start); |
Array.Copy(data, stop + 1, result, start, data.Length - stop - 1); |
return result; |
@@ -83,14 +77,14 @@ |
/// <returns>a flat array with all arrays concatenated</returns> |
public static T[] ConcatenateArrays<T>(params T[][] arrays) |
{ |
int resultLength = 0; |
foreach (T[] o in arrays) |
var resultLength = 0; |
foreach (var o in arrays) |
{ |
resultLength += o.Length; |
} |
T[] result = new T[resultLength]; |
int offset = 0; |
for (int x = 0; x < arrays.Length; x++) |
var result = new T[resultLength]; |
var offset = 0; |
for (var x = 0; x < arrays.Length; x++) |
{ |
arrays[x].CopyTo(result, offset); |
offset += arrays[x].Length; |
@@ -111,7 +105,7 @@ |
public static T[] ReversePermuteArrayElements<T>(T[] input, int times) |
{ |
if (times.Equals(0)) return input; |
T[] slice = new T[input.Length]; |
var slice = new T[input.Length]; |
Array.Copy(input, 1, slice, 0, input.Length - 1); |
Array.Copy(input, 0, slice, input.Length - 1, 1); |
return ReversePermuteArrayElements(slice, --times); |
@@ -130,7 +124,7 @@ |
public static T[] ForwardPermuteArrayElements<T>(T[] input, int times) |
{ |
if (times.Equals(0)) return input; |
T[] slice = new T[input.Length]; |
var slice = new T[input.Length]; |
Array.Copy(input, input.Length - 1, slice, 0, 1); |
Array.Copy(input, 0, slice, 1, input.Length - 1); |
return ForwardPermuteArrayElements(slice, --times); |
/BitTwiddling.cs |
@@ -4,9 +4,12 @@ |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System.Collections.Generic; |
using System.Linq; |
|
namespace wasSharp |
{ |
public class BitTwiddling |
public static class BitTwiddling |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -22,5 +25,112 @@ |
p ^= q; |
q ^= p; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Checks whether a flag is set for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to check the flag for</param> |
/// <param name="flag">the flag to check</param> |
/// <returns>true in case the flag is set</returns> |
public static bool IsMaskFlagSet<T, U>(this T mask, U flag) where T : struct where U : struct |
{ |
return unchecked(mask as dynamic & flag as dynamic) != 0; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sets a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to set the flag on</param> |
/// <param name="flag">the flag to set</param> |
public static void SetMaskFlag<T, U>(ref T mask, U flag) where T : struct where U : struct |
{ |
mask = unchecked(mask as dynamic | flag as dynamic); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Create a bitmask from multiple flags. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <param name="flag">the flags to set</param> |
/// <returns>a bitmask</returns> |
public static T CreateMask<T>(this IEnumerable<T> flag) where T : struct |
{ |
return flag.Aggregate((o, p) => unchecked(o as dynamic | p as dynamic)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Unset a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to unset the flag on</param> |
/// <param name="flag">the flag to unset</param> |
public static void UnsetMaskFlag<T, U>(ref T mask, U flag) |
{ |
mask = unchecked(mask as dynamic & ~(flag as dynamic)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Toggle a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to toggle the flag on</param> |
/// <param name="flag">the flag to toggle</param> |
public static void ToggleMaskFlag<T, U>(ref T mask, U flag) |
{ |
mask = unchecked(mask as dynamic ^ flag as dynamic); |
} |
|
/// <summary> |
/// Computes the previous power of two. |
/// </summary> |
/// <param name="x">the integer</param> |
/// <returns>the previous power of two</returns> |
/// <remarks>Adapted from Hacker's Delight ISBN-10:0201914654</remarks> |
public static T PreviousPowerOfTwo<T>(this T x) |
{ |
var y = x as dynamic; |
unchecked |
{ |
y = y | (y >> 1); |
y = y | (y >> 2); |
y = y | (y >> 4); |
y = y | (y >> 8); |
y = y | (y >> 16); |
return y - (y >> 1); |
} |
} |
|
/// <summary> |
/// Determines if a number is a power of two. |
/// </summary> |
/// <typeparam name="T">the number type</typeparam> |
/// <param name="x">the number</param> |
/// <returns>true of the number is a power of two</returns> |
public static bool IsPowerOfTwo<T>(this T x) |
{ |
var y = x as dynamic; |
return (y != 0) && ((y & (y - 1)) == 0); |
} |
} |
} |
/CSV.cs |
@@ -4,15 +4,13 @@ |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Linq.Expressions; |
using System.Text; |
|
namespace wasSharp |
{ |
public class CSV |
public static class CSV |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -22,14 +20,36 @@ |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static Func<IEnumerable<string>, string> FromEnumerable = |
((Expression<Func<IEnumerable<string>, string>>) (data => string.Join(",", |
data |
public static string FromEnumerable(IEnumerable<string> input) |
{ |
return string.Join(",", |
input |
.Select(o => o.Replace("\"", "\"\"")) |
.Select(o => o.IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}).Equals(-1) ? o : "\"" + o + "\"")))) |
.Compile(); |
.Select(o => o.IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}).Equals(-1) ? o : "\"" + o + "\"")); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a dictionary of strings to a comma-separated values string. |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static string FromDictionary<K, V>(Dictionary<K, V> input) |
{ |
return string.Join(",", input.Keys.Select(o => o.ToString()).Zip(input.Values.Select(o => o.ToString()), |
(o, p) => |
string.Join(",", |
o.Replace("\"", "\"\"").IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}).Equals(-1) |
? o |
: "\"" + o + "\"", |
p.Replace("\"", "\"\"").IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}).Equals(-1) |
? p |
: "\"" + p + "\""))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
@@ -36,19 +56,44 @@ |
/// Converts successive comma-separated values to key-value pairs. |
/// </summary> |
/// <returns>key-value pairs of successive comma-separate values</returns> |
public static Func<string, IEnumerable<KeyValuePair<string, string>>> ToKeyValue = |
((Expression<Func<string, IEnumerable<KeyValuePair<string, string>>>>) |
(csv => ToEnumerable(csv).AsParallel().Select((o, p) => new {o, p}) |
.GroupBy(q => q.p/2, q => q.o) |
.Select(o => o.ToArray()) |
.TakeWhile(o => o.Length%2 == 0) |
.Where(o => !string.IsNullOrEmpty(o[0]) || !string.IsNullOrEmpty(o[1])) |
.ToDictionary(o => o[0], p => p[1]).Select(o => o))).Compile(); |
public static IEnumerable<KeyValuePair<string, string>> ToKeyValue(string input) |
{ |
return ToEnumerable(input).AsParallel().Select((o, p) => new {o, p}) |
.GroupBy(q => q.p/2, q => q.o) |
.Select(o => o.ToArray()) |
.TakeWhile(o => o.Length%2 == 0) |
.Where(o => !string.IsNullOrEmpty(o[0]) || !string.IsNullOrEmpty(o[1])) |
.ToDictionary(o => o[0], p => p[1]).Select(o => o); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a generic key value pair to a CSV. |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static string FromKeyValue<K, V>(KeyValuePair<K, V> input) |
{ |
var key = input.Key.ToString(); |
var value = input.Value.ToString(); |
|
return string.Join(",", key |
.Replace("\"", "\"\"").IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}).Equals(-1) |
? key |
: "\"" + key + "\"", value |
.Replace("\"", "\"\"") |
.IndexOfAny(new[] {'"', ' ', ',', '\r', '\n'}) |
.Equals(-1) |
? value |
: "\"" + value + "\""); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a comma-separated list of values to a list of strings. |
/// </summary> |
/// <param name="csv">a comma-separated list of values</param> |
@@ -56,9 +101,9 @@ |
/// <remarks>compliant with RFC 4180</remarks> |
public static IEnumerable<string> ToEnumerable(string csv) |
{ |
Stack<char> s = new Stack<char>(); |
StringBuilder m = new StringBuilder(); |
for (int i = 0; i < csv.Length; ++i) |
var s = new Stack<char>(); |
var m = new StringBuilder(); |
for (var i = 0; i < csv.Length; ++i) |
{ |
switch (csv[i]) |
{ |
/Collections.cs |
@@ -4,7 +4,13 @@ |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections; |
using System.Collections.Generic; |
using System.Collections.ObjectModel; |
using System.Collections.Specialized; |
using System.IO; |
using System.Linq; |
using System.Xml; |
using System.Xml.Schema; |
using System.Xml.Serialization; |
@@ -11,9 +17,478 @@ |
|
namespace wasSharp |
{ |
public class Collections |
public static class Collections |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// A circular queue implementation based on linked lists. |
/// </summary> |
/// <typeparam name="T">the type of value to store</typeparam> |
public class CircularQueue<T> |
{ |
private readonly LinkedList<T> Store = new LinkedList<T>(); |
private LinkedListNode<T> CurrentNode = null; |
|
object SyncRoot = new object(); |
|
public int Count |
{ |
get |
{ |
lock (SyncRoot) |
{ |
return Store.Count; |
} |
} |
} |
|
private T GetNext |
{ |
get |
{ |
lock (SyncRoot) |
{ |
|
if (CurrentNode == null) |
return default(T); |
|
T value = CurrentNode.Value; |
|
switch (CurrentNode.Next != null) |
{ |
case true: |
CurrentNode = CurrentNode.Next; |
break; |
default: |
CurrentNode = Store.First; |
break; |
} |
|
return value; |
} |
} |
} |
|
public IEnumerable<T> Items |
{ |
get |
{ |
lock (SyncRoot) |
{ |
|
if (CurrentNode == null) |
yield break; |
|
var node = CurrentNode; |
do |
{ |
yield return node.Value; |
node = node.Next; |
} while (node != null); |
} |
} |
} |
|
public CircularQueue() |
{ |
|
} |
|
public CircularQueue(IEnumerable<T> items) |
{ |
Enqueue(items); |
} |
|
public CircularQueue(CircularQueue<T> queue) |
{ |
lock (SyncRoot) |
{ |
lock (queue.SyncRoot) |
{ |
|
foreach (var item in queue.Items) |
{ |
Store.AddLast(item); |
} |
|
if (CurrentNode == null) |
CurrentNode = Store.First; |
} |
} |
} |
|
public void Enqueue(IEnumerable<T> items) |
{ |
lock (SyncRoot) |
{ |
foreach (var i in items) |
Store.AddLast(i); |
|
if (CurrentNode == null) |
CurrentNode = Store.First; |
} |
} |
|
public void Enqueue(T item) |
{ |
lock (SyncRoot) |
{ |
|
Store.AddLast(item); |
|
if (CurrentNode == null) |
CurrentNode = Store.First; |
} |
} |
|
public T Dequeue() |
{ |
lock (SyncRoot) |
{ |
return GetNext; |
} |
} |
|
public IEnumerable<T> Dequeue(int count = 1) |
{ |
if (count <= 0) |
yield break; |
|
lock (SyncRoot) |
{ |
if(CurrentNode == null) |
yield break; |
|
do |
{ |
yield return GetNext; |
} while (--count != 0); |
} |
} |
|
public void Clear() |
{ |
lock (SyncRoot) |
{ |
Store.Clear(); |
|
CurrentNode = null; |
} |
} |
|
public bool Contains(T item) |
{ |
lock (SyncRoot) |
{ |
return Store.Contains(item); |
} |
} |
|
public void CopyTo(T[] array, int arrayIndex) |
{ |
lock (SyncRoot) |
{ |
Store.CopyTo(array, arrayIndex); |
} |
} |
|
public bool Remove(T item) |
{ |
lock (SyncRoot) |
{ |
var node = Store.Find(item); |
if (node == null) |
return false; |
if (CurrentNode.Equals(node)) |
{ |
switch (node.Next != null) |
{ |
case true: |
CurrentNode = node.Next; |
break; |
default: |
CurrentNode = Store.First; |
break; |
} |
} |
Store.Remove(node); |
return true; |
} |
} |
|
public void RemoveAll(IEnumerable<T> items) |
{ |
var itemSet = new HashSet<T>(items); |
lock (SyncRoot) |
{ |
var node = CurrentNode; |
do |
{ |
var next = node.Next; |
if (itemSet.Contains(node.Value)) |
{ |
switch (next != null) |
{ |
case true: |
CurrentNode = next; |
break; |
default: |
CurrentNode = Store.First; |
break; |
} |
Store.Remove(node); |
} |
node = next; |
} while (node != null); |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// A collection that maps ranges to values with O(1) complexity |
/// lookups and O(n) insertions. |
/// </summary> |
/// <typeparam name="T">the type of value to store</typeparam> |
public class RangeCollection<T> : IEnumerable |
{ |
private Dictionary<int, T> map = null; |
|
public RangeCollection(int min, int max) |
{ |
map = new Dictionary<int, T>(max - min); |
} |
|
/// <summary> |
/// Map a value to a range. |
/// </summary> |
/// <param name="Value">the value for the range</param> |
/// <param name="min">the minimal range</param> |
/// <param name="max">the maximal range</param> |
public void Add(T Value, int min, int max) |
{ |
foreach (var i in Enumerable.Range(min, max - min + 1)) |
{ |
map.Add(i, Value); |
} |
} |
|
public IEnumerator GetEnumerator() |
{ |
return ((IEnumerable)map).GetEnumerator(); |
} |
|
public T this[int x] |
{ |
get |
{ |
T value; |
return map.TryGetValue(x, out value) ? value : default(T); |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns true of an enumerable contains more than one element. |
/// </summary> |
/// <typeparam name="T">the type of the enumeration</typeparam> |
/// <param name="e">the enumeration</param> |
/// <returns>true if enumeration contains more than one element</returns> |
/// <remarks>O(2) worst case</remarks> |
public static bool Some<T>(this IEnumerable<T> e) |
{ |
int i = 0; |
using (var iter = e.GetEnumerator()) |
{ |
while (iter.MoveNext()) |
{ |
if (++i > 1) |
return true; |
} |
return false; |
} |
} |
|
/// <summary> |
/// Compares two dictionaries for equality. |
/// </summary> |
/// <typeparam name="TKey">key type</typeparam> |
/// <typeparam name="TValue">value type</typeparam> |
/// <param name="dictionary">dictionary to compare</param> |
/// <param name="otherDictionary">dictionary to compare to</param> |
/// <returns>true if the dictionaries contain the same elements</returns> |
public static bool ContentEquals<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, |
IDictionary<TKey, TValue> otherDictionary) |
{ |
return |
(dictionary ?? new Dictionary<TKey, TValue>()).Count.Equals( |
(otherDictionary ?? new Dictionary<TKey, TValue>()).Count) && |
(otherDictionary ?? new Dictionary<TKey, TValue>()) |
.OrderBy(kvp => kvp.Key) |
.SequenceEqual((dictionary ?? new Dictionary<TKey, TValue>()) |
.OrderBy(kvp => kvp.Key)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// An implementation of an observable HashSet. |
/// </summary> |
/// <typeparam name="T">the object type</typeparam> |
public class ObservableHashSet<T> : ICollection<T>, INotifyCollectionChanged |
{ |
private readonly HashSet<T> store = new HashSet<T>(); |
|
public ObservableHashSet(HashSet<T> set) |
{ |
UnionWith(set); |
} |
|
public ObservableHashSet() |
{ |
} |
|
public ObservableHashSet(T item) |
{ |
Add(item); |
} |
|
public ObservableHashSet(ObservableHashSet<T> other) |
{ |
UnionWith(other); |
} |
|
public ObservableHashSet(IEnumerable<T> list) |
{ |
UnionWith(list); |
} |
|
public bool IsVirgin { get; private set; } = true; |
|
public IEnumerator<T> GetEnumerator() |
{ |
return store.GetEnumerator(); |
} |
|
IEnumerator IEnumerable.GetEnumerator() |
{ |
return GetEnumerator(); |
} |
|
public void Add(T item) |
{ |
store.Add(item); |
IsVirgin = false; |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); |
} |
|
public void Clear() |
{ |
store.Clear(); |
if (!IsVirgin) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
IsVirgin = false; |
} |
|
public bool Contains(T item) |
{ |
return store.Contains(item); |
} |
|
public void CopyTo(T[] array, int arrayIndex) |
{ |
store.CopyTo(array, arrayIndex); |
} |
|
public bool Remove(T item) |
{ |
var removed = store.Remove(item); |
IsVirgin = false; |
if (removed) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); |
return removed; |
} |
|
public int Count => store.Count; |
|
public bool IsReadOnly => false; |
|
public event NotifyCollectionChangedEventHandler CollectionChanged; |
|
public void UnionWith(IEnumerable<T> list) |
{ |
var added = new List<T>(list.Except(store)); |
store.UnionWith(added); |
if (!IsVirgin && added.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added)); |
IsVirgin = false; |
} |
|
private void OnCollectionChanged(NotifyCollectionChangedEventArgs args) |
{ |
CollectionChanged?.Invoke(this, args); |
} |
|
public void ExceptWith(IEnumerable<T> list) |
{ |
var removed = new List<T>(list.Intersect(store)); |
store.ExceptWith(removed); |
if (!IsVirgin && removed.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
removed)); |
IsVirgin = false; |
} |
|
public void RemoveWhere(Func<T, bool> func) |
{ |
var removed = new List<T>(store.Where(func)); |
store.ExceptWith(removed); |
if (!IsVirgin && removed.Any()) |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, |
removed)); |
IsVirgin = false; |
} |
} |
|
/// <summary> |
/// An observable collection allowing the add of a range of items. |
/// </summary> |
/// <typeparam name="T">the collection type</typeparam> |
public class ExtendedObservableCollection<T> : ObservableCollection<T> |
{ |
private bool _suppressNotification; |
|
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) |
{ |
if (!_suppressNotification) |
base.OnCollectionChanged(e); |
} |
|
public void AddRange(IEnumerable<T> list) |
{ |
if (list == null) |
throw new ArgumentNullException(nameof(list)); |
|
_suppressNotification = true; |
|
foreach (var item in list) |
{ |
Add(item); |
} |
_suppressNotification = false; |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); |
} |
} |
|
/// <summary> |
/// A serializable dictionary class. |
/// </summary> |
/// <typeparam name="TKey">the key</typeparam> |
@@ -24,6 +499,48 @@ |
{ |
#region IXmlSerializable Members |
|
public SerializableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> kvp) |
{ |
foreach (var i in kvp) |
{ |
Add(i.Key, i.Value); |
} |
} |
|
public SerializableDictionary() |
{ |
} |
|
/// <summary> |
/// Deep-clones the serializable dictionary. |
/// </summary> |
/// <returns>a deep clone of the original dictionary</returns> |
public SerializableDictionary<TKey, TValue> Clone() |
{ |
SerializableDictionary<TKey, TValue> clone; |
try |
{ |
using (var writer = new MemoryStream()) |
{ |
var serializer = |
new XmlSerializer( |
typeof (SerializableDictionary<TKey, TValue>)); |
serializer.Serialize(writer, this); |
writer.Seek(0, SeekOrigin.Begin); |
clone = (SerializableDictionary<TKey, TValue>) |
new XmlSerializer( |
typeof (SerializableDictionary<TKey, TValue>)) |
.Deserialize(writer); |
} |
} |
/* cloning failed so return an empty dictionary */ |
catch (Exception) |
{ |
clone = new SerializableDictionary<TKey, TValue>(); |
} |
return clone; |
} |
|
public XmlSchema GetSchema() |
{ |
return null; |
@@ -31,25 +548,25 @@ |
|
public void ReadXml(XmlReader reader) |
{ |
XmlSerializer keySerializer = new XmlSerializer(typeof (TKey)); |
XmlSerializer valueSerializer = new XmlSerializer(typeof (TValue)); |
var keySerializer = new XmlSerializer(typeof (TKey)); |
var valueSerializer = new XmlSerializer(typeof (TValue)); |
|
bool wasEmpty = reader.IsEmptyElement; |
var wasEmpty = reader.IsEmptyElement; |
reader.Read(); |
|
if (wasEmpty) |
return; |
|
while (reader.NodeType != XmlNodeType.EndElement) |
while (!reader.NodeType.Equals(XmlNodeType.EndElement)) |
{ |
reader.ReadStartElement("Item"); |
|
reader.ReadStartElement("Key"); |
TKey key = (TKey) keySerializer.Deserialize(reader); |
var key = (TKey) keySerializer.Deserialize(reader); |
reader.ReadEndElement(); |
|
reader.ReadStartElement("Value"); |
TValue value = (TValue) valueSerializer.Deserialize(reader); |
var value = (TValue) valueSerializer.Deserialize(reader); |
reader.ReadEndElement(); |
|
Add(key, value); |
@@ -62,10 +579,10 @@ |
|
public void WriteXml(XmlWriter writer) |
{ |
XmlSerializer keySerializer = new XmlSerializer(typeof (TKey)); |
XmlSerializer valueSerializer = new XmlSerializer(typeof (TValue)); |
var keySerializer = new XmlSerializer(typeof (TKey)); |
var valueSerializer = new XmlSerializer(typeof (TValue)); |
|
foreach (TKey key in Keys) |
foreach (var key in Keys) |
{ |
writer.WriteStartElement("Item"); |
|
@@ -74,7 +591,7 @@ |
writer.WriteEndElement(); |
|
writer.WriteStartElement("Value"); |
TValue value = this[key]; |
var value = this[key]; |
valueSerializer.Serialize(writer, value); |
writer.WriteEndElement(); |
|
@@ -84,5 +601,119 @@ |
|
#endregion |
} |
|
/// <summary> |
/// A serializable sorted dictionary class. |
/// </summary> |
/// <typeparam name="TKey">the key</typeparam> |
/// <typeparam name="TValue">the value</typeparam> |
[XmlRoot("SortedDictionary")] |
public class SerializableSortedDictionary<TKey, TValue> |
: SortedDictionary<TKey, TValue>, IXmlSerializable |
{ |
#region IXmlSerializable Members |
|
public SerializableSortedDictionary(IEnumerable<KeyValuePair<TKey, TValue>> kvp) |
{ |
foreach (var i in kvp) |
{ |
Add(i.Key, i.Value); |
} |
} |
|
public SerializableSortedDictionary() |
{ |
} |
|
/// <summary> |
/// Deep-clones the serializable dictionary. |
/// </summary> |
/// <returns>a deep clone of the original dictionary</returns> |
public SerializableSortedDictionary<TKey, TValue> Clone() |
{ |
SerializableSortedDictionary<TKey, TValue> clone; |
try |
{ |
using (var writer = new MemoryStream()) |
{ |
var serializer = |
new XmlSerializer( |
typeof(SerializableDictionary<TKey, TValue>)); |
serializer.Serialize(writer, this); |
writer.Seek(0, SeekOrigin.Begin); |
clone = (SerializableSortedDictionary<TKey, TValue>) |
new XmlSerializer( |
typeof(SerializableSortedDictionary<TKey, TValue>)) |
.Deserialize(writer); |
} |
} |
/* cloning failed so return an empty dictionary */ |
catch (Exception) |
{ |
clone = new SerializableSortedDictionary<TKey, TValue>(); |
} |
return clone; |
} |
|
public XmlSchema GetSchema() |
{ |
return null; |
} |
|
public void ReadXml(XmlReader reader) |
{ |
var keySerializer = new XmlSerializer(typeof(TKey)); |
var valueSerializer = new XmlSerializer(typeof(TValue)); |
|
var wasEmpty = reader.IsEmptyElement; |
reader.Read(); |
|
if (wasEmpty) |
return; |
|
while (!reader.NodeType.Equals(XmlNodeType.EndElement)) |
{ |
reader.ReadStartElement("Item"); |
|
reader.ReadStartElement("Key"); |
var key = (TKey)keySerializer.Deserialize(reader); |
reader.ReadEndElement(); |
|
reader.ReadStartElement("Value"); |
var value = (TValue)valueSerializer.Deserialize(reader); |
reader.ReadEndElement(); |
|
Add(key, value); |
|
reader.ReadEndElement(); |
reader.MoveToContent(); |
} |
reader.ReadEndElement(); |
} |
|
public void WriteXml(XmlWriter writer) |
{ |
var keySerializer = new XmlSerializer(typeof(TKey)); |
var valueSerializer = new XmlSerializer(typeof(TValue)); |
|
foreach (var key in Keys) |
{ |
writer.WriteStartElement("Item"); |
|
writer.WriteStartElement("Key"); |
keySerializer.Serialize(writer, key); |
writer.WriteEndElement(); |
|
writer.WriteStartElement("Value"); |
var value = this[key]; |
valueSerializer.Serialize(writer, value); |
writer.WriteEndElement(); |
|
writer.WriteEndElement(); |
} |
} |
|
#endregion |
} |
} |
} |
/Cryptography.cs |
@@ -12,7 +12,7 @@ |
|
namespace wasSharp |
{ |
public class Cryptography |
public static class Cryptography |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
@@ -27,7 +27,7 @@ |
/// <returns>either a decrypted or encrypted string</returns> |
public static string ENIGMA(string message, char[] rotors, char[] plugs, char reflector) |
{ |
Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]> |
var def_rotors = new Dictionary<char, char[]> |
{ |
{ |
'1', new[] |
@@ -141,7 +141,7 @@ |
} |
}; |
|
Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]> |
var def_reflectors = new Dictionary<char, char[]> |
{ |
{ |
'B', new[] |
@@ -182,10 +182,10 @@ |
}; |
|
// Setup rotors from plugs. |
foreach (char rotor in rotors) |
foreach (var rotor in rotors) |
{ |
char plug = plugs[Array.IndexOf(rotors, rotor)]; |
int i = Array.IndexOf(def_rotors[rotor], plug); |
var plug = plugs[Array.IndexOf(rotors, rotor)]; |
var i = Array.IndexOf(def_rotors[rotor], plug); |
if (i.Equals(0)) continue; |
def_rotors[rotor] = Arrays.ConcatenateArrays(new[] {plug}, |
Arrays.GetSubArray(Arrays.DeleteSubArray(def_rotors[rotor], i, i), i, -1), |
@@ -192,8 +192,8 @@ |
Arrays.GetSubArray(Arrays.DeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1)); |
} |
|
StringBuilder result = new StringBuilder(); |
foreach (char c in message) |
var result = new StringBuilder(); |
foreach (var c in message) |
{ |
if (!char.IsLetter(c)) |
{ |
@@ -202,11 +202,11 @@ |
} |
|
// Normalize to lower. |
char l = char.ToLower(c); |
var l = char.ToLower(c); |
|
Action<char[]> rotate = o => |
{ |
int i = o.Length - 1; |
var i = o.Length - 1; |
do |
{ |
def_rotors[o[0]] = Arrays.ForwardPermuteArrayElements(def_rotors[o[0]], 1); |
@@ -224,7 +224,7 @@ |
rotate.Invoke(rotors); |
|
// Reflect |
int x = Array.IndexOf(def_reflectors[reflector], l); |
var x = Array.IndexOf(def_reflectors[reflector], l); |
l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1]; |
|
// Reverse the order of the rotors. |
@@ -254,11 +254,11 @@ |
/// <returns>the expanded key</returns> |
public static string VIGENEREExpandKey(string input, string enc_key) |
{ |
string exp_key = string.Empty; |
var exp_key = string.Empty; |
int i = 0, j = 0; |
do |
{ |
char p = input[i]; |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
exp_key += p; |
@@ -265,7 +265,7 @@ |
++i; |
continue; |
} |
int m = j%enc_key.Length; |
var m = j%enc_key.Length; |
exp_key += enc_key[m]; |
++j; |
++i; |
@@ -291,11 +291,11 @@ |
}; |
|
enc_key = VIGENEREExpandKey(input, enc_key); |
string result = string.Empty; |
int i = 0; |
var result = string.Empty; |
var i = 0; |
do |
{ |
char p = input[i]; |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
result += p; |
@@ -302,7 +302,7 @@ |
++i; |
continue; |
} |
char q = |
var q = |
Arrays.ReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[ |
Array.IndexOf(a, char.ToLowerInvariant(p))]; |
if (char.IsUpper(p)) |
@@ -333,11 +333,11 @@ |
}; |
|
enc_key = VIGENEREExpandKey(input, enc_key); |
string result = string.Empty; |
int i = 0; |
var result = string.Empty; |
var i = 0; |
do |
{ |
char p = input[i]; |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
result += p; |
@@ -344,7 +344,7 @@ |
++i; |
continue; |
} |
char q = |
var q = |
a[ |
Array.IndexOf(Arrays.ReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])), |
char.ToLowerInvariant(p))]; |
@@ -374,13 +374,13 @@ |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' |
}; |
|
char[] input = data.ToCharArray(); |
var input = data.ToCharArray(); |
|
Parallel.ForEach(Enumerable.Range(0, data.Length), i => |
{ |
char e = input[i]; |
var e = input[i]; |
if (!char.IsLetter(e)) return; |
int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e)); |
var x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e)); |
if (!char.IsUpper(e)) |
{ |
input[i] = a[x]; |
/KeyValue.cs |
@@ -7,11 +7,10 @@ |
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Linq.Expressions; |
|
namespace wasSharp |
{ |
public class KeyValue |
public static class KeyValue |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -20,14 +19,15 @@ |
/// Returns the value of a key from a key-value data string. |
/// </summary> |
/// <returns>true if the key was found in data</returns> |
public static Func<string, string, string> Get = |
((Expression<Func<string, string, string>>) ((key, data) => data.Split('&') |
public static string Get(string key, string data) |
{ |
return data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2)) |
.Where(o => o[0].Equals(key)) |
.Where(o => o.Length.Equals(2) && Strings.StringEquals(o[0], key, StringComparison.Ordinal)) |
.Select(o => o[1]) |
.FirstOrDefault())).Compile(); |
.FirstOrDefault(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -39,14 +39,14 @@ |
/// a key-value data string or the empty string if either key or |
/// value are empty |
/// </returns> |
public static Func<string, string, string, string> Set = |
((Expression<Func<string, string, string, string>>) |
((key, value, data) => string.Join("&", string.Join("&", data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2)) |
.Where(o => !o[0].Equals(key)) |
.Select(o => string.Join("=", o[0], o[1]))), string.Join("=", key, value)))).Compile(); |
public static string Set(string key, string value, string data) |
{ |
return string.Join("&", string.Join("&", data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2) && !Strings.StringEquals(o[0], key, StringComparison.Ordinal)) |
.Select(o => string.Join("=", o[0], o[1]))), string.Join("=", key, value)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -55,14 +55,15 @@ |
/// Deletes a key-value pair from a string referenced by a key. |
/// </summary> |
/// <returns>a key-value pair string</returns> |
public static Func<string, string, string> Delete = |
((Expression<Func<string, string, string>>) ((key, data) => string.Join("&", data.Split('&') |
public static string Delete(string key, string data) |
{ |
return string.Join("&", data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2)) |
.Where(o => !o[0].Equals(key)) |
.Where(o => o.Length.Equals(2) && !Strings.StringEquals(o[0], key, StringComparison.Ordinal)) |
.Select(o => string.Join("=", o[0], o[1])) |
.ToArray()))).Compile(); |
.ToArray()); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -71,8 +72,9 @@ |
/// Decodes key-value pair data to a dictionary. |
/// </summary> |
/// <returns>a dictionary containing the keys and values</returns> |
public static Func<string, Dictionary<string, string>> Decode = |
((Expression<Func<string, Dictionary<string, string>>>) (data => data.Split('&') |
public static Dictionary<string, string> Decode(string data) |
{ |
return data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2)) |
@@ -82,7 +84,8 @@ |
v = o[1] |
}) |
.GroupBy(o => o.k) |
.ToDictionary(o => o.Key, p => p.First().v))).Compile(); |
.ToDictionary(o => o.Key, p => p.First().v); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -91,9 +94,10 @@ |
/// Serialises a dictionary to key-value data. |
/// </summary> |
/// <returns>a key-value data encoded string</returns> |
public static Func<Dictionary<string, string>, string> Encode = |
((Expression<Func<Dictionary<string, string>, string>>) |
(data => string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value))))).Compile(); |
public static string Encode(Dictionary<string, string> data) |
{ |
return string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -101,8 +105,9 @@ |
/// <summary> |
/// Escapes a dictionary's keys and values for sending as POST data. |
/// </summary> |
public static Func<Dictionary<string, string>, Func<string, string>, Dictionary<string, string>> Escape = |
((Expression<Func<Dictionary<string, string>, Func<string, string>, Dictionary<string, string>>>) |
((data, func) => data.AsParallel().ToDictionary(o => func(o.Key), p => func(p.Value)))).Compile(); |
public static Dictionary<string, string> Escape(Dictionary<string, string> data, Func<string, string> func) |
{ |
return data.AsParallel().ToDictionary(o => func(o.Key), p => func(p.Value)); |
} |
} |
} |
/Reflection.cs |
@@ -8,10 +8,11 @@ |
using System.Collections.Generic; |
using System.Linq; |
using System.Reflection; |
using wasSharp; |
|
namespace wasSharp |
{ |
public class Reflection |
public static class Reflection |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
@@ -38,7 +39,7 @@ |
/// <returns>a list of attributes</returns> |
public static IEnumerable<T> GetEnumAttributes<T>(Enum e) where T : Attribute |
{ |
return e.GetType().GetRuntimeFields() |
return e.GetType().GetRuntimeFields().ToArray() |
.AsParallel() |
.Select(o => GetAttributeFromEnumValue<T>((Enum) o.GetValue(Activator.CreateInstance<T>()))); |
} |
@@ -53,7 +54,7 @@ |
public static IEnumerable<string> GetEnumNames<T>() |
{ |
return |
typeof (T).GetRuntimeFields() |
typeof (T).GetRuntimeFields().ToArray() |
.AsParallel() |
.Select(o => o.GetCustomAttribute(typeof (NameAttribute), false)) |
.Select(o => (o as NameAttribute)?.Name) |
@@ -77,13 +78,13 @@ |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get the description from an enumeration value. |
/// Get the name from an enumeration value. |
/// </summary> |
/// <param name="value">an enumeration value</param> |
/// <returns>the description or the empty string</returns> |
public static string GetNameFromEnumValue(Enum value) |
{ |
NameAttribute attribute = value.GetType() |
var attribute = value.GetType() |
.GetRuntimeField(value.ToString()) |
.GetCustomAttributes(typeof (NameAttribute), false) |
.SingleOrDefault() as NameAttribute; |
@@ -100,7 +101,7 @@ |
/// <returns>the description or the empty string</returns> |
public static string GetDescriptionFromEnumValue(Enum value) |
{ |
DescriptionAttribute attribute = value.GetType() |
var attribute = value.GetType() |
.GetRuntimeField(value.ToString()) |
.GetCustomAttributes(typeof (DescriptionAttribute), false) |
.SingleOrDefault() as DescriptionAttribute; |
@@ -118,11 +119,11 @@ |
/// <returns>the value or the default of T if case no name attribute found</returns> |
public static T GetEnumValueFromName<T>(string name) |
{ |
var field = typeof (T).GetRuntimeFields() |
var field = typeof (T).GetRuntimeFields().ToArray() |
.AsParallel().SelectMany(f => f.GetCustomAttributes( |
typeof (NameAttribute), false), ( |
f, a) => new {Field = f, Att = a}).SingleOrDefault(a => ((NameAttribute) a.Att) |
.Name.Equals(name)); |
f, a) => new {Field = f, Att = a}).SingleOrDefault(a => Strings.StringEquals(((NameAttribute) a.Att) |
.Name, name, StringComparison.Ordinal)); |
return field != null ? (T) field.Field.GetValue(Activator.CreateInstance<T>()) : default(T); |
} |
|
@@ -130,7 +131,7 @@ |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get the description of structure member. |
/// Get the name of a structure member. |
/// </summary> |
/// <typeparam name="T">the type of the structure to search</typeparam> |
/// <param name="structure">the structure to search</param> |
@@ -138,13 +139,109 @@ |
/// <returns>the description or the empty string</returns> |
public static string GetStructureMemberName<T>(T structure, object item) where T : struct |
{ |
var field = typeof (T).GetRuntimeFields() |
var field = typeof (T).GetRuntimeFields().ToArray() |
.AsParallel().SelectMany(f => f.GetCustomAttributes(typeof (NameAttribute), false), |
(f, a) => new {Field = f, Att = a}).SingleOrDefault(f => f.Field.GetValue(structure).Equals(item)); |
return field != null ? ((NameAttribute) field.Att).Name : string.Empty; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get field or property from a class by supplying a path. |
/// </summary> |
/// <typeparam name="T">the type of the object</typeparam> |
/// <param name="o">the object</param> |
/// <param name="path">the fully qualified path to the field of property</param> |
/// <returns> |
/// the last object in the fully qualified path or null in case the field or property could not be found |
/// </returns> |
public static object GetFP<T>(this T o, string path) |
{ |
if (string.IsNullOrEmpty(path)) return null; |
if (o == null) return null; |
|
var memberType = o.GetType(); |
var components = path.Split('.'); |
|
var f = memberType.GetRuntimeField(components[0]); |
var p = memberType.GetRuntimeProperty(components[0]); |
|
if (f != null) |
return components.Length > 1 |
? GetFP(f.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeField(path).GetValue(o); |
|
if (p != null) |
return components.Length > 1 |
? GetFP(p.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeProperty(path).GetValue(o); |
|
return null; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get field or property info from a class by supplying a path. |
/// </summary> |
/// <typeparam name="T">the type of the object</typeparam> |
/// <param name="o">the object</param> |
/// <param name="path">the fully qualified path to the field of property</param> |
/// <returns> |
/// the field or property info of the last object in the path or null if the object cannot be found |
/// </returns> |
public static object GetFPInfo<T>(this T o, string path) |
{ |
if (string.IsNullOrEmpty(path)) return null; |
if (o == null) return null; |
|
var memberType = o.GetType(); |
var components = path.Split('.'); |
|
var f = memberType.GetRuntimeField(components[0]); |
var p = memberType.GetRuntimeProperty(components[0]); |
|
if (f != null) |
return components.Length > 1 |
? GetFPInfo(f.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeField(path); |
|
if (p != null) |
return components.Length > 1 |
? GetFPInfo(p.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeProperty(path); |
|
return null; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Enumerate all the base types recursively starting from a type. |
/// </summary> |
/// <param name="type">the type</param> |
/// <returns>an enumeration of all base types</returns> |
public static IEnumerable<Type> GetBaseTypes(this Type type) |
{ |
var baseType = type.GetTypeInfo().BaseType; |
if(baseType == null) |
yield break; |
yield return baseType; |
foreach (var t in GetBaseTypes(baseType)) |
{ |
yield return t; |
} |
} |
|
/// <summary> |
/// A generic name attribute. |
/// </summary> |
public class NameAttribute : Attribute |
/Time.cs |
@@ -14,7 +14,7 @@ |
|
namespace wasSharp |
{ |
public class Time |
public static class Time |
{ |
public delegate void TimerCallback(object state); |
|
@@ -63,6 +63,10 @@ |
{ |
} |
|
public Timer(TimerCallback callback) : this(callback, null, TimeSpan.Zero, TimeSpan.Zero) |
{ |
} |
|
public void Dispose() |
{ |
Dispose(true); |
@@ -87,6 +91,12 @@ |
Reset(dueTime); |
} |
|
public void Change(uint dueTime, int period) |
{ |
Period = period; |
Change((int) dueTime, period); |
} |
|
public void Change(TimeSpan dueTime, TimeSpan period) |
{ |
Change((int) dueTime.TotalMilliseconds, (int) period.TotalMilliseconds); |
@@ -95,30 +105,38 @@ |
private void Reset(int due) |
{ |
Cancel(); |
if (due >= 0) |
if (due <= 0) |
return; |
TokenSource = new CancellationTokenSource(); |
Action tick = null; |
tick = () => |
{ |
TokenSource = new CancellationTokenSource(); |
Action tick = null; |
tick = () => |
{ |
Task.Run(() => Callback(State)); |
if (Disposed || Period < 0) return; |
Delay = Period > 0 ? Task.Delay(Period, TokenSource.Token) : CompletedTask; |
Delay.ContinueWith(t => tick(), TokenSource.Token); |
}; |
Delay = due > 0 ? Task.Delay(due, TokenSource.Token) : CompletedTask; |
Task.Run(() => Callback(State)); |
if (Disposed) |
return; |
Delay = Period > 0 ? Task.Delay(Period, TokenSource.Token) : CompletedTask; |
if (Delay.IsCompleted) |
return; |
Delay.ContinueWith(t => tick(), TokenSource.Token); |
} |
}; |
Delay = due > 0 ? Task.Delay(due, TokenSource.Token) : CompletedTask; |
if (Delay.IsCompleted) |
return; |
Delay.ContinueWith(t => tick(), TokenSource.Token); |
} |
|
public void Stop() |
{ |
Change(0, 0); |
} |
|
private void Cancel() |
{ |
if (TokenSource != null) |
{ |
TokenSource.Cancel(); |
TokenSource.Dispose(); |
TokenSource = null; |
} |
if (TokenSource == null) |
return; |
TokenSource.Cancel(); |
TokenSource.Dispose(); |
TokenSource = null; |
} |
} |
|
@@ -131,12 +149,12 @@ |
/// another lined-up event. This is mostly used to check that throttles |
/// are being respected. |
/// </summary> |
public class TimedThrottle : IDisposable |
public sealed class TimedThrottle : IDisposable |
{ |
private readonly uint EventsAllowed; |
private readonly object LockObject = new object(); |
private Timer timer; |
private uint TriggeredEvents; |
public uint TriggeredEvents; |
|
public TimedThrottle(uint events, uint seconds) |
{ |
@@ -170,8 +188,13 @@ |
GC.SuppressFinalize(this); |
} |
|
protected virtual void Dispose(bool dispose) |
~TimedThrottle() |
{ |
Dispose(false); |
} |
|
private void Dispose(bool dispose) |
{ |
if (timer != null) |
{ |
timer.Dispose(); |
@@ -190,16 +213,16 @@ |
/// <remarks> |
/// (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 |
/// </remarks> |
public class DecayingAlarm : IDisposable |
public sealed class DecayingAlarm : IDisposable |
{ |
[Flags] |
public enum DECAY_TYPE |
{ |
[XmlEnum(Name = "none")] NONE = 0, |
[XmlEnum(Name = "arithmetic")] ARITHMETIC = 1, |
[XmlEnum(Name = "geometric")] GEOMETRIC = 2, |
[XmlEnum(Name = "harmonic")] HARMONIC = 4, |
[XmlEnum(Name = "weighted")] WEIGHTED = 5 |
[Reflection.NameAttribute("none")] [XmlEnum(Name = "none")] NONE = 0, |
[Reflection.NameAttribute("arithmetic")] [XmlEnum(Name = "arithmetic")] ARITHMETIC = 1, |
[Reflection.NameAttribute("geometric")] [XmlEnum(Name = "geometric")] GEOMETRIC = 2, |
[Reflection.NameAttribute("harmonic")] [XmlEnum(Name = "harmonic")] HARMONIC = 4, |
[Reflection.NameAttribute("weighted")] [XmlEnum(Name = "weighted")] WEIGHTED = 5 |
} |
|
private readonly DECAY_TYPE decay = DECAY_TYPE.NONE; |
@@ -234,6 +257,11 @@ |
GC.SuppressFinalize(this); |
} |
|
~DecayingAlarm() |
{ |
Dispose(false); |
} |
|
public void Alarm(double deadline) |
{ |
lock (LockObject) |
@@ -264,8 +292,8 @@ |
(int) ((deadline + times.Aggregate((a, b) => b + a))/(1f + times.Count)), 0); |
break; |
case DECAY_TYPE.GEOMETRIC: |
alarm?.Change((int) (Math.Pow(deadline*times.Aggregate((a, b) => b*a), |
1f/(1f + times.Count))), 0); |
alarm?.Change((int) Math.Pow(deadline*times.Aggregate((a, b) => b*a), |
1f/(1f + times.Count)), 0); |
break; |
case DECAY_TYPE.HARMONIC: |
alarm?.Change((int) ((1f + times.Count)/ |
@@ -272,10 +300,10 @@ |
(1f/deadline + times.Aggregate((a, b) => 1f/b + 1f/a))), 0); |
break; |
case DECAY_TYPE.WEIGHTED: |
HashSet<double> d = new HashSet<double>(times) {deadline}; |
double total = d.Aggregate((a, b) => b + a); |
var d = new HashSet<double>(times) {deadline}; |
var total = d.Aggregate((a, b) => b + a); |
alarm?.Change( |
(int) (d.Aggregate((a, b) => Math.Pow(a, 2)/total + Math.Pow(b, 2)/total)), 0); |
(int) d.Aggregate((a, b) => Math.Pow(a, 2)/total + Math.Pow(b, 2)/total), 0); |
break; |
default: |
alarm?.Change((int) deadline, 0); |
@@ -288,7 +316,7 @@ |
} |
} |
|
protected virtual void Dispose(bool dispose) |
private void Dispose(bool dispose) |
{ |
if (alarm != null) |
{ |
@@ -296,6 +324,11 @@ |
alarm = null; |
} |
} |
|
public DecayingAlarm Clone() |
{ |
return new DecayingAlarm(decay); |
} |
} |
} |
} |
/Web.cs |
@@ -5,14 +5,33 @@ |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Linq.Expressions; |
using System.Net; |
using System.Net.Http; |
using System.Net.Http.Headers; |
using System.Text; |
using System.Text.RegularExpressions; |
using System.Threading.Tasks; |
|
namespace wasSharp |
{ |
public class Web |
public static class Web |
{ |
private static readonly Func<string, string> directURIEscapeDataString = |
((Expression<Func<string, string>>) |
(data => string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766).AsParallel() |
.Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - o*32766)))) |
.ToArray()))).Compile(); |
|
private static readonly Func<string, string> directURIUnescapeDataString = |
((Expression<Func<string, string>>) |
(data => string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766).AsParallel() |
.Select( |
o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - o*32766)))) |
.ToArray()))).Compile(); |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
@@ -21,11 +40,10 @@ |
/// data - a string to escape |
/// </remarks> |
/// <returns>an RFC3986 escaped string</returns> |
public static Func<string, string> URIEscapeDataString = |
((Expression<Func<string, string>>) |
(data => string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) |
.Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766))))) |
.ToArray()))).Compile(); |
public static string URIEscapeDataString(string data) |
{ |
return directURIEscapeDataString(data); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
@@ -35,12 +53,10 @@ |
/// data - a string to unescape |
/// </remarks> |
/// <returns>the resulting string</returns> |
public static Func<string, string> URIUnescapeDataString = |
((Expression<Func<string, string>>) |
(data => string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) |
.Select( |
o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766))))) |
.ToArray()))).Compile(); |
public static string URIUnescapeDataString(string data) |
{ |
return directURIUnescapeDataString(data); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // |
@@ -63,5 +79,266 @@ |
{ |
return WebUtility.UrlDecode(data); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <param name="prefix">a HttpListener prefix</param> |
/// <returns>the port of the HttpListener</returns> |
public static long GetPortFromPrefix(string prefix) |
{ |
var split = Regex.Replace( |
prefix, |
@"^([a-zA-Z]+:\/\/)?([^\/]+)\/.*?$", |
"$2" |
).Split(':'); |
long port; |
return split.Length <= 1 || !long.TryParse(split[1], out port) ? 80 : port; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
// <summary>A portable HTTP client.</summar> |
public class wasHTTPClient |
{ |
private readonly HttpClient HTTPClient; |
private readonly string MediaType; |
|
public wasHTTPClient(ProductInfoHeaderValue userAgent, CookieContainer cookieContainer, string mediaType, |
AuthenticationHeaderValue authentication, Dictionary<string, string> headers, uint timeout) |
{ |
var HTTPClientHandler = new HttpClientHandler |
{ |
CookieContainer = cookieContainer, |
UseCookies = true |
}; |
if (HTTPClientHandler.SupportsRedirectConfiguration) |
{ |
HTTPClientHandler.AllowAutoRedirect = true; |
} |
if (HTTPClientHandler.SupportsProxy) |
{ |
HTTPClientHandler.Proxy = WebRequest.DefaultWebProxy; |
HTTPClientHandler.UseProxy = true; |
} |
if (HTTPClientHandler.SupportsAutomaticDecompression) |
{ |
HTTPClientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; |
} |
HTTPClientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic; |
|
HTTPClient = new HttpClient(HTTPClientHandler, false); |
HTTPClient.DefaultRequestHeaders.UserAgent.Add(userAgent); |
if (authentication != null) |
{ |
HTTPClient.DefaultRequestHeaders.Authorization = authentication; |
} |
if (headers != null) |
{ |
foreach (var header in headers) |
{ |
HTTPClient.DefaultRequestHeaders.Add(header.Key, header.Value); |
} |
} |
HTTPClient.Timeout = TimeSpan.FromMilliseconds(timeout); |
MediaType = mediaType; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a PUT request to an URL with binary data. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="data">key-value pairs to send</param> |
/// <param name="headers">headers to send with the request</param> |
public async Task<byte[]> PUT(string URL, byte[] data, Dictionary<string, string> headers) |
{ |
try |
{ |
using (var content = new ByteArrayContent(data)) |
{ |
using ( |
var request = new HttpRequestMessage |
{ |
RequestUri = new Uri(URL), |
Method = HttpMethod.Put, |
Content = content |
}) |
{ |
foreach (var header in headers) |
{ |
request.Headers.Add(header.Key, header.Value); |
} |
using (var response = await HTTPClient.SendAsync(request)) |
{ |
return response.IsSuccessStatusCode |
? await response.Content.ReadAsByteArrayAsync() |
: null; |
} |
} |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a PUT request to an URL with text. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="data">key-value pairs to send</param> |
/// <param name="headers">headers to send with the request</param> |
public async Task<byte[]> PUT(string URL, string data, Dictionary<string, string> headers) |
{ |
try |
{ |
using (var content = |
new StringContent(data, Encoding.UTF8, MediaType)) |
{ |
using ( |
var request = new HttpRequestMessage |
{ |
RequestUri = new Uri(URL), |
Method = HttpMethod.Put, |
Content = content |
}) |
{ |
foreach (var header in headers) |
{ |
request.Headers.Add(header.Key, header.Value); |
} |
using (var response = await HTTPClient.SendAsync(request)) |
{ |
return response.IsSuccessStatusCode |
? await response.Content.ReadAsByteArrayAsync() |
: null; |
} |
} |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a PUT request to an URL with binary data. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="data">key-value pairs to send</param> |
public async Task<byte[]> PUT(string URL, byte[] data) |
{ |
try |
{ |
using (var content = new ByteArrayContent(data)) |
{ |
using (var response = await HTTPClient.PutAsync(URL, content)) |
{ |
return response.IsSuccessStatusCode |
? await response.Content.ReadAsByteArrayAsync() |
: null; |
} |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a PUT request to an URL with text. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="data">key-value pairs to send</param> |
public async Task<byte[]> PUT(string URL, string data) |
{ |
try |
{ |
using (var content = |
new StringContent(data, Encoding.UTF8, MediaType)) |
{ |
using (var response = await HTTPClient.PutAsync(URL, content)) |
{ |
return response.IsSuccessStatusCode |
? await response.Content.ReadAsByteArrayAsync() |
: null; |
} |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a POST request to an URL with set key-value pairs. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="message">key-value pairs to send</param> |
public async Task<byte[]> POST(string URL, Dictionary<string, string> message) |
{ |
try |
{ |
using (var content = |
new StringContent(KeyValue.Encode(message), Encoding.UTF8, MediaType)) |
{ |
using (var response = await HTTPClient.PostAsync(URL, content)) |
{ |
return response.IsSuccessStatusCode |
? await response.Content.ReadAsByteArrayAsync() |
: null; |
} |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sends a GET request to an URL with set key-value pairs. |
/// </summary> |
/// <param name="URL">the url to send the message to</param> |
/// <param name="message">key-value pairs to send</param> |
public async Task<byte[]> GET(string URL, Dictionary<string, string> message) |
{ |
try |
{ |
using (var response = |
await HTTPClient.GetAsync(URL + "?" + KeyValue.Encode(message))) |
{ |
return response.IsSuccessStatusCode ? await response.Content.ReadAsByteArrayAsync() : null; |
} |
} |
catch (Exception) |
{ |
return null; |
} |
} |
} |
} |
} |
/XML.cs |
@@ -4,15 +4,28 @@ |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Linq.Expressions; |
using System.Text; |
using System.Text.RegularExpressions; |
using System.Threading.Tasks; |
using System.Xml.Linq; |
|
namespace wasSharp |
{ |
public class XML |
public static class XML |
{ |
private static readonly Func<string, bool> directIsSafeXML = |
((Expression<Func<string, bool>>) |
(data => |
Regex.Replace(data, |
@"(" + string.Join("|", @"&", @"<", @">", @""", @"'") + @")", |
@"", RegexOptions.IgnoreCase | RegexOptions.Multiline) |
.IndexOfAny(new[] {'&', '<', '>', '"', '\''}) |
.Equals(-1))).Compile(); |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
@@ -23,9 +36,9 @@ |
/// <returns>an XML unescaped string</returns> |
public static string UnescapeXML(string s) |
{ |
Queue<char> t = new Queue<char>(); |
StringBuilder m = new StringBuilder(); |
foreach (char c in s) |
var t = new Queue<char>(); |
var m = new StringBuilder(); |
foreach (var c in s) |
{ |
switch (c) |
{ |
@@ -41,7 +54,7 @@ |
if (!t.Count.Equals(0)) |
{ |
t.Enqueue(c); |
string special = string.Join("", t.ToArray()); |
var special = string.Join("", t.ToArray()); |
switch (special) |
{ |
case "'": |
@@ -98,7 +111,7 @@ |
{ |
if (string.IsNullOrEmpty(s)) return s; |
|
string[] result = new string[s.Length]; |
var result = new string[s.Length]; |
Parallel.ForEach(Enumerable.Range(0, s.Length), o => |
{ |
switch (s[o]) |
@@ -125,5 +138,40 @@ |
}); |
return string.Join("", result); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Determines whether a string is safe to use in XML |
/// </summary> |
/// <param name="data">the string to check</param> |
/// <returns>true in case the string is safe</returns> |
public static bool IsSafeXML(string data) |
{ |
return directIsSafeXML(data); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Recursively rename a node by name. |
/// </summary> |
/// <param name="root">the root from where to start</param> |
/// <param name="name">the name to replace</param> |
/// <param name="rename">the name to replace with</param> |
public static void RenameNodes(XElement root, string name, string rename) |
{ |
if (Strings.StringEquals(root.Name.LocalName, name, StringComparison.Ordinal)) |
{ |
root.Name = rename; |
} |
|
foreach (var xElement in root.Elements()) |
{ |
RenameNodes(xElement, name, rename); |
} |
} |
} |
} |