From 5508c749cedd4cf75a8a6abd312ddd19c7a3ab1c Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Tue, 27 Dec 2016 10:08:22 +0200 Subject: [PATCH] Updates to Utilities --- Utilities/ByteUtils/BigEndianReader.cs | 1 - Utilities/ByteUtils/BigEndianWriter.cs | 1 - Utilities/ByteUtils/ByteReader.cs | 1 - Utilities/ByteUtils/ByteUtils.cs | 32 ++++- Utilities/ByteUtils/ByteWriter.cs | 1 - Utilities/ByteUtils/LittleEndianReader.cs | 69 ++++++++- Utilities/ByteUtils/LittleEndianWriter.cs | 1 - Utilities/Generics/BlockingQueue.cs | 85 +++++++++++ Utilities/Generics/KeyValuePairList.cs | 4 +- Utilities/Generics/SortedList.cs | 163 ++++++++++++++++++++++ Utilities/Strings/QuotedStringUtils.cs | 18 ++- Utilities/Threading/CountdownLatch.cs | 51 +++++++ Utilities/Utilities.csproj | 3 + 13 files changed, 417 insertions(+), 13 deletions(-) create mode 100644 Utilities/Generics/BlockingQueue.cs create mode 100644 Utilities/Generics/SortedList.cs create mode 100644 Utilities/Threading/CountdownLatch.cs diff --git a/Utilities/ByteUtils/BigEndianReader.cs b/Utilities/ByteUtils/BigEndianReader.cs index 6eb767d..833ed7a 100644 --- a/Utilities/ByteUtils/BigEndianReader.cs +++ b/Utilities/ByteUtils/BigEndianReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Utilities/ByteUtils/BigEndianWriter.cs b/Utilities/ByteUtils/BigEndianWriter.cs index 8c01ca7..e7ef51a 100644 --- a/Utilities/ByteUtils/BigEndianWriter.cs +++ b/Utilities/ByteUtils/BigEndianWriter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Utilities/ByteUtils/ByteReader.cs b/Utilities/ByteUtils/ByteReader.cs index f1580ae..57ad5ed 100644 --- a/Utilities/ByteUtils/ByteReader.cs +++ b/Utilities/ByteUtils/ByteReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Utilities/ByteUtils/ByteUtils.cs b/Utilities/ByteUtils/ByteUtils.cs index d1eb83f..2f396da 100644 --- a/Utilities/ByteUtils/ByteUtils.cs +++ b/Utilities/ByteUtils/ByteUtils.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; @@ -33,6 +32,35 @@ namespace Utilities return true; } + public static byte[] XOR(byte[] array1, byte[] array2) + { + if (array1.Length == array2.Length) + { + return XOR(array1, 0, array2, 0, array1.Length); + } + else + { + throw new ArgumentException("Arrays must be of equal length"); + } + } + + public static byte[] XOR(byte[] array1, int offset1, byte[] array2, int offset2, int length) + { + if (offset1 + length <= array1.Length && offset2 + length <= array2.Length) + { + byte[] result = new byte[length]; + for (int index = 0; index < length; index++) + { + result[index] = (byte)(array1[offset1 + index] ^ array2[offset2 + index]); + } + return result; + } + else + { + throw new ArgumentOutOfRangeException(); + } + } + public static long CopyStream(Stream input, Stream output) { // input may not support seeking, so don't use input.Position @@ -41,7 +69,7 @@ namespace Utilities public static long CopyStream(Stream input, Stream output, long count) { - const int MaxBufferSize = 4194304; // 4 MB + const int MaxBufferSize = 1048576; // 1 MB int bufferSize = (int)Math.Min(MaxBufferSize, count); byte[] buffer = new byte[bufferSize]; long totalBytesRead = 0; diff --git a/Utilities/ByteUtils/ByteWriter.cs b/Utilities/ByteUtils/ByteWriter.cs index aba1657..0de2a41 100644 --- a/Utilities/ByteUtils/ByteWriter.cs +++ b/Utilities/ByteUtils/ByteWriter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Utilities/ByteUtils/LittleEndianReader.cs b/Utilities/ByteUtils/LittleEndianReader.cs index 6d05e74..db6b35c 100644 --- a/Utilities/ByteUtils/LittleEndianReader.cs +++ b/Utilities/ByteUtils/LittleEndianReader.cs @@ -1,23 +1,41 @@ using System; -using System.Collections.Generic; +using System.IO; using System.Text; namespace Utilities { public class LittleEndianReader { + public static short ReadInt16(byte[] buffer, ref int offset) + { + offset += 2; + return LittleEndianConverter.ToInt16(buffer, offset - 2); + } + public static ushort ReadUInt16(byte[] buffer, ref int offset) { offset += 2; return LittleEndianConverter.ToUInt16(buffer, offset - 2); } + public static int ReadInt32(byte[] buffer, ref int offset) + { + offset += 4; + return LittleEndianConverter.ToInt32(buffer, offset - 4); + } + public static uint ReadUInt32(byte[] buffer, ref int offset) { offset += 4; return LittleEndianConverter.ToUInt32(buffer, offset - 4); } + public static long ReadInt64(byte[] buffer, ref int offset) + { + offset += 8; + return LittleEndianConverter.ToInt64(buffer, offset - 8); + } + public static ulong ReadUInt64(byte[] buffer, ref int offset) { offset += 8; @@ -29,5 +47,54 @@ namespace Utilities offset += 16; return LittleEndianConverter.ToGuid(buffer, offset - 16); } + + public static short ReadInt16(Stream stream) + { + byte[] buffer = new byte[2]; + stream.Read(buffer, 0, 2); + return LittleEndianConverter.ToInt16(buffer, 0); + } + + public static ushort ReadUInt16(Stream stream) + { + byte[] buffer = new byte[2]; + stream.Read(buffer, 0, 2); + return LittleEndianConverter.ToUInt16(buffer, 0); + } + + public static int ReadInt32(Stream stream) + { + byte[] buffer = new byte[4]; + stream.Read(buffer, 0, 4); + return LittleEndianConverter.ToInt32(buffer, 0); + } + + public static uint ReadUInt32(Stream stream) + { + byte[] buffer = new byte[4]; + stream.Read(buffer, 0, 4); + return LittleEndianConverter.ToUInt32(buffer, 0); + } + + public static long ReadInt64(Stream stream) + { + byte[] buffer = new byte[8]; + stream.Read(buffer, 0, 8); + return LittleEndianConverter.ToInt64(buffer, 0); + } + + public static ulong ReadUInt64(Stream stream) + { + byte[] buffer = new byte[8]; + stream.Read(buffer, 0, 8); + return LittleEndianConverter.ToUInt64(buffer, 0); + } + + public static Guid ReadGuidBytes(Stream stream) + { + byte[] buffer = new byte[16]; + stream.Read(buffer, 0, 16); + return LittleEndianConverter.ToGuid(buffer, 0); + } } } diff --git a/Utilities/ByteUtils/LittleEndianWriter.cs b/Utilities/ByteUtils/LittleEndianWriter.cs index 30462ef..c40a71d 100644 --- a/Utilities/ByteUtils/LittleEndianWriter.cs +++ b/Utilities/ByteUtils/LittleEndianWriter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; diff --git a/Utilities/Generics/BlockingQueue.cs b/Utilities/Generics/BlockingQueue.cs new file mode 100644 index 0000000..13873d8 --- /dev/null +++ b/Utilities/Generics/BlockingQueue.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Text; + +namespace Utilities +{ + public class BlockingQueue + { + private Queue m_queue = new Queue(); + private int m_count = 0; + private bool m_stopping; + + public void Enqueue(T item) + { + lock (m_queue) + { + m_queue.Enqueue(item); + m_count++; + if (m_queue.Count == 1) + { + Monitor.Pulse(m_queue); + } + } + } + + public void Enqueue(List items) + { + if (items.Count == 0) + { + return; + } + lock (m_queue) + { + foreach (T item in items) + { + m_queue.Enqueue(item); + m_count++; + } + if (m_queue.Count == items.Count) + { + Monitor.Pulse(m_queue); + } + } + } + + /// Will return false if the BlockingQueue is stopped + public bool TryDequeue(out T item) + { + lock (m_queue) + { + while (m_queue.Count == 0) + { + Monitor.Wait(m_queue); + if (m_stopping) + { + item = default(T); + return false; + } + } + + item = m_queue.Dequeue(); + m_count--; + return true; + } + } + + public void Stop() + { + lock (m_queue) + { + m_stopping = true; + Monitor.PulseAll(m_queue); + } + } + + public int Count + { + get + { + return m_count; + } + } + } +} diff --git a/Utilities/Generics/KeyValuePairList.cs b/Utilities/Generics/KeyValuePairList.cs index 57fc465..b91be25 100644 --- a/Utilities/Generics/KeyValuePairList.cs +++ b/Utilities/Generics/KeyValuePairList.cs @@ -7,10 +7,10 @@ namespace Utilities { public bool ContainsKey(TKey key) { - return (this.IndexOf(key) != -1); + return (this.IndexOfKey(key) != -1); } - public int IndexOf(TKey key) + public int IndexOfKey(TKey key) { for (int index = 0; index < this.Count; index++) { diff --git a/Utilities/Generics/SortedList.cs b/Utilities/Generics/SortedList.cs new file mode 100644 index 0000000..ffc2160 --- /dev/null +++ b/Utilities/Generics/SortedList.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Utilities +{ + public class SortedList : ICollection + { + private List m_innerList; + private Comparer m_comparer; + + public SortedList() : this(Comparer.Default) + { + } + + public SortedList(Comparer comparer) + { + m_innerList = new List(); + m_comparer = comparer; + } + + public void Add(T item) + { + int insertIndex = FindIndexForSortedInsert(m_innerList, m_comparer, item); + m_innerList.Insert(insertIndex, item); + } + + public bool Contains(T item) + { + return IndexOf(item) != -1; + } + + /// + /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire SortedList + /// + public int IndexOf(T item) + { + int insertIndex = FindIndexForSortedInsert(m_innerList, m_comparer, item); + if (insertIndex == m_innerList.Count) + { + return -1; + } + if (m_comparer.Compare(item, m_innerList[insertIndex]) == 0) + { + int index = insertIndex; + while (index > 0 && m_comparer.Compare(item, m_innerList[index - 1]) == 0) + { + index--; + } + return index; + } + return -1; + } + + public bool Remove(T item) + { + int index = IndexOf(item); + if (index >= 0) + { + m_innerList.RemoveAt(index); + return true; + } + return false; + } + + public void RemoveAt(int index) + { + m_innerList.RemoveAt(index); + } + + public void CopyTo(T[] array) + { + m_innerList.CopyTo(array); + } + + public void CopyTo(T[] array, int arrayIndex) + { + m_innerList.CopyTo(array, arrayIndex); + } + + public void Clear() + { + m_innerList.Clear(); + } + + public T this[int index] + { + get + { + return m_innerList[index]; + } + } + + public IEnumerator GetEnumerator() + { + return m_innerList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_innerList.GetEnumerator(); + } + + public int Count + { + get + { + return m_innerList.Count; + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public static int FindIndexForSortedInsert(List list, Comparer comparer, T item) + { + if (list.Count == 0) + { + return 0; + } + + int lowerIndex = 0; + int upperIndex = list.Count - 1; + int comparisonResult; + while (lowerIndex < upperIndex) + { + int middleIndex = (lowerIndex + upperIndex) / 2; + T middle = list[middleIndex]; + comparisonResult = comparer.Compare(middle, item); + if (comparisonResult == 0) + { + return middleIndex; + } + else if (comparisonResult > 0) // middle > item + { + upperIndex = middleIndex - 1; + } + else // middle < item + { + lowerIndex = middleIndex + 1; + } + } + + // At this point any entry following 'middle' is greater than 'item', + // and any entry preceding 'middle' is lesser than 'item'. + // So we either put 'item' before or after 'middle'. + comparisonResult = comparer.Compare(list[lowerIndex], item); + if (comparisonResult < 0) // middle < item + { + return lowerIndex + 1; + } + else + { + return lowerIndex; + } + } + } +} diff --git a/Utilities/Strings/QuotedStringUtils.cs b/Utilities/Strings/QuotedStringUtils.cs index c597c7a..f9663f7 100644 --- a/Utilities/Strings/QuotedStringUtils.cs +++ b/Utilities/Strings/QuotedStringUtils.cs @@ -96,18 +96,30 @@ namespace Utilities } public static List SplitIgnoreQuotedSeparators(string str, char separator) + { + return SplitIgnoreQuotedSeparators(str, separator, StringSplitOptions.None); + } + + public static List SplitIgnoreQuotedSeparators(string str, char separator, StringSplitOptions options) { List result = new List(); int nextEntryIndex = 0; int separatorIndex = IndexOfUnquotedChar(str, separator); while (separatorIndex >= nextEntryIndex) { - result.Add(str.Substring(nextEntryIndex, separatorIndex - nextEntryIndex)); - + string entry = str.Substring(nextEntryIndex, separatorIndex - nextEntryIndex); + if (options != StringSplitOptions.RemoveEmptyEntries || entry != String.Empty) + { + result.Add(entry); + } nextEntryIndex = separatorIndex + 1; separatorIndex = IndexOfUnquotedChar(str, separator, nextEntryIndex); } - result.Add(str.Substring(nextEntryIndex)); + string lastEntry = str.Substring(nextEntryIndex); + if (options != StringSplitOptions.RemoveEmptyEntries || lastEntry != String.Empty) + { + result.Add(lastEntry); + } return result; } } diff --git a/Utilities/Threading/CountdownLatch.cs b/Utilities/Threading/CountdownLatch.cs new file mode 100644 index 0000000..de6b9a7 --- /dev/null +++ b/Utilities/Threading/CountdownLatch.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading; + +namespace Utilities +{ + public class CountdownLatch + { + private int m_count; + private EventWaitHandle m_waitHandle = new EventWaitHandle(true, EventResetMode.ManualReset); + + public CountdownLatch() + { + } + + public void Increment() + { + int count = Interlocked.Increment(ref m_count); + if (count == 1) + { + m_waitHandle.Reset(); + } + } + + public void Add(int value) + { + int count = Interlocked.Add(ref m_count, value); + if (count == value) + { + m_waitHandle.Reset(); + } + } + + public void Decrement() + { + int count = Interlocked.Decrement(ref m_count); + if (m_count == 0) + { + m_waitHandle.Set(); + } + else if (count < 0) + { + throw new InvalidOperationException("Count must be greater than or equal to 0"); + } + } + + public void WaitUntilZero() + { + m_waitHandle.WaitOne(); + } + } +} diff --git a/Utilities/Utilities.csproj b/Utilities/Utilities.csproj index 1545d91..cbd997a 100644 --- a/Utilities/Utilities.csproj +++ b/Utilities/Utilities.csproj @@ -42,13 +42,16 @@ + + +