wasSharp

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 6  →  ?path2? @ 7
/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];
/IO.cs
@@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
 
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
 
namespace wasSharp
{
public static class IO
{
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Combine multiple paths.
/// </summary>
/// <param name="paths">an array of paths</param>
/// <returns>a combined path</returns>
public static string PathCombine(params string[] paths)
{
return paths.Aggregate((x, y) => Path.Combine(x, y));
}
 
/// <summary>
/// Strip characters that are incompatible with file names.
/// </summary>
/// <param name="fileName">the name of the file</param>
/// <returns>a clean string</returns>
private static string CleanFileName(string fileName)
{
return Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Splits a path using a separator and an escape character.
/// </summary>
/// <param name="path">the path to split</param>
/// <param name="separator">the separator character</param>
/// <param name="escape">the escape character</param>
/// <returns>path parts</returns>
public static IEnumerable<string> PathSplit(this string path, char separator, char? escape)
{
Stack<char> s = new Stack<char>();
StringBuilder p = new StringBuilder();
foreach (char c in path)
{
if (c == escape)
{
s.Push(c);
continue;
}
if (c == separator)
{
if (s.Count.Equals(0) || !s.Peek().Equals(escape))
{
yield return p.ToString();
p = new StringBuilder();
continue;
}
s.Pop();
while (!s.Count.Equals(0))
{
p.Append(s.Pop());
}
p.Append(c);
continue;
}
p.Append(c);
}
while (!s.Count.Equals(0))
{
p.Append(s.Pop());
}
yield return p.ToString();
}
}
}
/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));
}
}
}
/Numerics.cs
@@ -4,12 +4,9 @@
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
 
using System;
using System.Linq.Expressions;
 
namespace wasSharp
{
public class Numerics
public static class Numerics
{
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
@@ -26,20 +23,9 @@
/// yMax - the upper bound of the target range
/// </remarks>
/// <returns>a value in x mapped in the range of y</returns>
public static Func<double, double, double, double, double, double> MapValueToRange =
((Expression<Func<double, double, double, double, double, double>>)
((value, xMin, xMax, yMin, yMax) => yMin + (
(
yMax - yMin
)
*
(
value - xMin
)
/
(
xMax - xMin
)
))).Compile();
public static double MapValueToRange(double value, double xMin, double xMax, double yMin, double yMax)
{
return yMin + (yMax - yMin)*(value - xMin)/(xMax - xMin);
}
}
}
/Properties/AssemblyInfo.cs
@@ -6,7 +6,7 @@
// associated with an assembly.
 
[assembly: AssemblyTitle("wasSharp")]
[assembly: AssemblyDescription("Collections of C# Tools Created by Wizardry and Steamworks")]
[assembly: AssemblyDescription("Collection of C# Portable Tools Created by Wizardry and Steamworks")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Wizardry and Steamworks")]
[assembly: AssemblyProduct("wasSharp")]
@@ -26,4 +26,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
 
[assembly: AssemblyVersion("1.4.*")]
[assembly: AssemblyVersion("1.29.*")]
/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
/Strings.cs
@@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
 
using System;
using System.IO;
using System.Linq;
 
namespace wasSharp
{
public static class Strings
{
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Combine multiple paths.
/// </summary>
/// <param name="paths">an array of paths</param>
/// <returns>a combined path</returns>
public static string PathCombine(params string[] paths)
{
return paths.Aggregate((x, y) => Path.Combine(x, y));
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Determines if two strings are equal.
/// </summary>
/// <param name="a">first string</param>
/// <param name="b">second string</param>
/// <param name="comparison">string comparison to use</param>
/// <returns>true if the strings are equal</returns>
public static bool StringEquals(string a, string b, StringComparison comparison)
{
return (a == null && b == null) || (a.Length == b.Length && string.Equals(a, b, comparison));
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Determines if two strings are equal.
/// </summary>
/// <param name="a">first string</param>
/// <param name="b">second string</param>
/// <returns>true if the strings are equal</returns>
public static bool StringEquals(string a, string b)
{
return (a == null && b == null) || (a != null && b != null && a.Length == b.Length && string.Equals(a, b));
}
}
}
/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("|", @"&amp;", @"&lt;", @"&gt;", @"&quot;", @"&apos;") + @")",
@"", 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 "&apos;":
@@ -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);
}
}
}
}
/wasSharp.cs
@@ -6,7 +6,7 @@
 
namespace wasSharp
{
public class wasSharp
public static class wasSharp
{
}
}
/wasSharp.csproj
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
@@ -34,17 +34,16 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Arrays.cs" />
<Compile Include="BitTwiddling.cs" />
<Compile Include="Collections.cs" />
<Compile Include="Cryptography.cs" />
<Compile Include="CSV.cs" />
<Compile Include="IO.cs" />
<Compile Include="KeyValue.cs" />
<Compile Include="Numerics.cs" />
<Compile Include="Reflection.cs" />
<Compile Include="Strings.cs" />
<Compile Include="Time.cs" />
<Compile Include="wasSharp.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />