├── README.md
├── Compression
└── Vcdiff
│ ├── InstructionType.cs
│ ├── VcdiffFormatException.cs
│ ├── Instruction.cs
│ ├── IOHelper.cs
│ ├── AddressCache.cs
│ └── CodeTable.cs
├── Linq
├── Extensions
│ ├── DataProducerExt.cs
│ ├── ListExt.cs
│ ├── TypeExt.cs
│ └── DataProducerExt.Conversion.cs
├── IFuture.cs
├── IProducerGrouping.cs
├── IOrderedDataProducer.cs
├── IDataProducer.cs
├── FutureProxy.cs
├── EditableLookup.LookupGrouping.cs
├── Future.cs
├── ProducerGrouping.cs
├── OrderedDataProducer.cs
├── ExpressionUtil.cs
├── DataProducer.cs
├── KeyValueTuple.cs
└── EditableLookup.cs
├── Conversion
├── Endianness.cs
├── LittleEndianBitConverter.cs
├── BigEndianBitConverter.cs
└── DoubleConverter.cs
├── DotNet20
├── ExtensionAttribute.cs
├── IGrouping.cs
├── ILookup.cs
└── Delegates.cs
├── .gitattributes
├── BufferAcquisitionException.cs
├── .gitignore
├── EventArgs.cs
├── IBufferManager.cs
├── Collections
├── Extensions
│ ├── SmartEnumerableExt.cs
│ ├── RangeBasedExt.cs
│ ├── ComparerExt.cs
│ └── DictionaryExt.cs
├── LinkedComparer.cs
├── ReverseComparer.cs
├── ComparisonComparer.cs
├── DictionaryByType.cs
├── RangeIterator.cs
├── SmartEnumerable.cs
├── ProjectionComparer.cs
└── ProjectionEqualityComparer.cs
├── Threading
├── LockOrderException.cs
├── LockTimeoutException.cs
├── LockToken.cs
├── Delegates.cs
├── ThreadPoolWorkItem.cs
├── OrderedLock.cs
├── SyncLock.cs
└── ThreadController.cs
├── CachedBuffer.cs
├── IBuffer.cs
├── Extensions
├── ReferenceExt.cs
└── TimeRelated
│ ├── TimeSpanBasedExt.cs
│ └── DateTimeBasedExt.cs
├── Xml
└── Linq
│ └── Extensions
│ └── ObjectExt.cs
├── NullOp.cs
├── GenericMath.cs
├── Properties
└── AssemblyInfo.cs
├── StaticRandom.cs
├── IO
├── StringWriterWithEncoding.cs
└── LineReader.cs
├── Checksum
└── Adler32.cs
├── PartialComparer.cs
├── Reflection
└── PropertyCopy.cs
├── NonNullable.cs
├── ApplicationChooser.cs
└── MiscUtil.csproj
/README.md:
--------------------------------------------------------------------------------
1 | # MiscUtil
2 | From Jon Skeet http://www.yoda.arachsys.com/csharp/miscutil/
3 |
--------------------------------------------------------------------------------
/Compression/Vcdiff/InstructionType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Compression.Vcdiff
3 | {
4 | ///
5 | /// Enumeration of the different instruction types.
6 | ///
7 | internal enum InstructionType : byte
8 | {
9 | NoOp=0,
10 | Add=1,
11 | Run=2,
12 | Copy=3
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Linq/Extensions/DataProducerExt.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Linq.Extensions
3 | {
4 | ///
5 | /// Extensions on IDataProducer
6 | ///
7 | public static partial class DataProducerExt
8 | {
9 | // note: contents are in partial classes broken
10 | // down by function - i.e. DataProducerExt.Grouping.cs
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Conversion/Endianness.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Conversion
3 | {
4 | ///
5 | /// Endianness of a converter
6 | ///
7 | public enum Endianness
8 | {
9 | ///
10 | /// Little endian - least significant byte first
11 | ///
12 | LittleEndian,
13 | ///
14 | /// Big endian - most significant byte first
15 | ///
16 | BigEndian
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Linq/IFuture.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Linq
3 | {
4 | ///
5 | /// Class representing a value which will be available some time in the future.
6 | ///
7 | public interface IFuture
8 | {
9 | ///
10 | /// Retrieves the value, if available, and throws InvalidOperationException
11 | /// otherwise.
12 | ///
13 | T Value { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DotNet20/ExtensionAttribute.cs:
--------------------------------------------------------------------------------
1 | #if !DOTNET35
2 | using System;
3 |
4 | namespace System.Runtime.CompilerServices
5 | {
6 | ///
7 | /// Attribute used by the compiler to create extension methods under .NET 2.0.
8 | ///
9 | [AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
10 | public class ExtensionAttribute : Attribute
11 | {
12 | }
13 | }
14 | #endif
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/Compression/Vcdiff/VcdiffFormatException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Compression.Vcdiff
4 | {
5 | ///
6 | /// Summary description for VcdiffFormatException.
7 | ///
8 | [Serializable()]
9 | public class VcdiffFormatException : Exception
10 | {
11 | internal VcdiffFormatException(string message) : base (message)
12 | {
13 | }
14 |
15 | internal VcdiffFormatException(string message, Exception inner) : base(message, inner)
16 | {
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Linq/IProducerGrouping.cs:
--------------------------------------------------------------------------------
1 | namespace MiscUtil.Linq
2 | {
3 | ///
4 | /// IProducerGrouping is to IDataProducer as IGrouping is to IEnumerable:
5 | /// it's basically a data producer with a key. It's used by the GroupBy
6 | /// operator.
7 | ///
8 | public interface IProducerGrouping : IDataProducer
9 | {
10 | ///
11 | /// The key for this grouping.
12 | ///
13 | TKey Key { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DotNet20/IGrouping.cs:
--------------------------------------------------------------------------------
1 | #if !DOTNET35
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace System.Linq
6 | {
7 | ///
8 | /// LINQ interface used to represent groupings - each grouping has a key,
9 | /// and represents a sequence of elements.
10 | ///
11 | public interface IGrouping : IEnumerable, IEnumerable
12 | {
13 | ///
14 | /// Key for this group
15 | ///
16 | TKey Key { get; }
17 | }
18 | }
19 | #endif
--------------------------------------------------------------------------------
/BufferAcquisitionException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Exception thrown to indicate that a buffer of the
7 | /// desired size cannot be acquired.
8 | ///
9 | public class BufferAcquisitionException : Exception
10 | {
11 | ///
12 | /// Creates an instance of this class with the given message.
13 | ///
14 | public BufferAcquisitionException(string message)
15 | : base(message)
16 | {
17 | // No-op
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Compression/Vcdiff/Instruction.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Compression.Vcdiff
3 | {
4 | ///
5 | /// Contains the information for a single instruction
6 | ///
7 | internal struct Instruction
8 | {
9 | readonly InstructionType type;
10 | internal InstructionType Type
11 | {
12 | get { return type; }
13 | }
14 |
15 | readonly byte size;
16 | internal byte Size
17 | {
18 | get { return size; }
19 | }
20 |
21 | readonly byte mode;
22 | internal byte Mode
23 | {
24 | get { return mode; }
25 | }
26 |
27 | internal Instruction(InstructionType type, byte size, byte mode)
28 | {
29 | this.type = type;
30 | this.size = size;
31 | this.mode = mode;
32 | }
33 |
34 |
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear on external disk
35 | .Spotlight-V100
36 | .Trashes
37 |
38 | # Directories potentially created on remote AFP share
39 | .AppleDB
40 | .AppleDesktop
41 | Network Trash Folder
42 | Temporary Items
43 | .apdisk
44 |
--------------------------------------------------------------------------------
/EventArgs.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil
3 | {
4 | ///
5 | /// Generic event argument taking a single value
6 | ///
7 | public class EventArgs : System.EventArgs
8 | {
9 | readonly T value;
10 |
11 | ///
12 | /// The typed value of the EventArgs<T>
13 | ///
14 | public T Value
15 | {
16 | get { return value; }
17 | }
18 | ///
19 | /// Creates a new EventArgs<T> with the specified value.
20 | ///
21 | /// The Value of the EventArgs<T> instance.
22 | public EventArgs(T value)
23 | {
24 | this.value = value;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/IBufferManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Interface for classes which manage instances of
7 | /// IBuffer.
8 | ///
9 | public interface IBufferManager
10 | {
11 | ///
12 | /// Returns a buffer of the given size or greater.
13 | ///
14 | /// The minimum size of buffer to return
15 | /// This manager is unable
16 | /// to return a buffer of the appropriate size
17 | /// minimumSize is less than
18 | /// or equal to 0
19 | IBuffer GetBuffer(int minimumSize);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Linq/IOrderedDataProducer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace MiscUtil.Linq
4 | {
5 | ///
6 | /// Ordered variant of IDataProducer; note that generally
7 | /// this will force data to be buffered until the sequence
8 | /// is complete.
9 | ///
10 | ///
11 | public interface IOrderedDataProducer : IDataProducer
12 | {
13 | ///
14 | /// The unlerlying producer that can push data
15 | ///
16 | IDataProducer BaseProducer { get; }
17 | ///
18 | /// The comparer used to order the sequence (once complete)
19 | ///
20 | IComparer Comparer { get; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Collections/Extensions/SmartEnumerableExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MiscUtil.Collections.Extensions
7 | {
8 | ///
9 | /// Wrapper methods for SmartEnumerable[T].
10 | ///
11 | public static class SmartEnumerableExt
12 | {
13 | ///
14 | /// Extension method to make life easier.
15 | ///
16 | /// Type of enumerable
17 | /// Source enumerable
18 | /// A new SmartEnumerable of the appropriate type
19 | public static SmartEnumerable AsSmartEnumerable(this IEnumerable source)
20 | {
21 | return new SmartEnumerable(source);
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/DotNet20/ILookup.cs:
--------------------------------------------------------------------------------
1 | #if !DOTNET35
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace System.Linq
6 | {
7 | ///
8 | /// LINQ interface representing a lookup. This is like a dictionary, but
9 | /// each key maps to a sequence of values.
10 | ///
11 | public interface ILookup : IEnumerable>,
12 | IEnumerable
13 | {
14 | ///
15 | /// Returns whether or not the lookup contains the specified key
16 | ///
17 | bool Contains(TKey key);
18 | ///
19 | /// Returns the number of keys in this lookup
20 | ///
21 | int Count { get; }
22 | ///
23 | /// Returns the sequence of elements associated with the given key
24 | ///
25 | IEnumerable this[TKey key] { get; }
26 | }
27 | }
28 | #endif
--------------------------------------------------------------------------------
/Threading/LockOrderException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Threading
4 | {
5 | ///
6 | /// Exception thrown when a Lock method on the SyncLock class times out.
7 | ///
8 | public class LockOrderException : Exception
9 | {
10 | ///
11 | /// Constructs an instance with the specified message.
12 | ///
13 | /// The message for the exception
14 | internal LockOrderException (string message) : base (message)
15 | {
16 | }
17 |
18 | ///
19 | /// Constructs an instance by formatting the specified message with
20 | /// the given parameters.
21 | ///
22 | /// The message, which will be formatted with the parameters.
23 | /// The parameters to use for formatting.
24 | internal LockOrderException (string format, params object[] args)
25 | : this (string.Format(format, args))
26 | {
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Threading/LockTimeoutException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Threading
4 | {
5 | ///
6 | /// Exception thrown when a Lock method on the SyncLock class times out.
7 | ///
8 | public class LockTimeoutException : Exception
9 | {
10 | ///
11 | /// Constructs an instance with the specified message.
12 | ///
13 | /// The message for the exception
14 | internal LockTimeoutException (string message) : base (message)
15 | {
16 | }
17 |
18 | ///
19 | /// Constructs an instance by formatting the specified message with
20 | /// the given parameters.
21 | ///
22 | /// The message, which will be formatted with the parameters.
23 | /// The parameters to use for formatting.
24 | internal LockTimeoutException (string format, params object[] args)
25 | : this (string.Format(format, args))
26 | {
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CachedBuffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Type of buffer returned by CachingBufferManager.
7 | ///
8 | class CachedBuffer : IBuffer
9 | {
10 | readonly byte[] data;
11 | volatile bool available;
12 | readonly bool clearOnDispose;
13 |
14 | internal CachedBuffer(int size, bool clearOnDispose)
15 | {
16 | data = new byte[size];
17 | this.clearOnDispose = clearOnDispose;
18 | }
19 |
20 | internal bool Available
21 | {
22 | get { return available; }
23 | set { available = value; }
24 | }
25 |
26 | public byte[] Bytes
27 | {
28 | get { return data; }
29 | }
30 |
31 | public void Dispose()
32 | {
33 | if (clearOnDispose)
34 | {
35 | Array.Clear(data, 0, data.Length);
36 | }
37 | available = true;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/IBuffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Interface encapsulating a byte array which may be managed
7 | /// by an IBufferManager implementation. When the buffer is
8 | /// disposed, some implementations of this interface may
9 | /// return the buffer to the IBufferManager which created
10 | /// it. Note that an IBuffer *must* always be disposed after use,
11 | /// or some implementations may leak memory. The buffer must
12 | /// not be used after being disposed, likewise the byte array must
13 | /// not be used after the buffer is disposed.
14 | ///
15 | public interface IBuffer : IDisposable
16 | {
17 | ///
18 | /// Returns the byte array encapsulated by this buffer.
19 | /// Note that depending on the buffer manager providing
20 | /// the buffer, the array may or may not be cleared (i.e.
21 | /// with every byte 0) to start with.
22 | ///
23 | byte[] Bytes { get; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Threading/LockToken.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Threading
4 | {
5 | ///
6 | /// A lock token returned by a Lock method call on a SyncLock.
7 | /// This effectively holds the lock until it is disposed - a
8 | /// slight violation of the IDisposable contract, but it makes
9 | /// for easy use of the SyncLock system. This type itself
10 | /// is not thread-safe - LockTokens should not be shared between
11 | /// threads.
12 | ///
13 | public struct LockToken : IDisposable
14 | {
15 | ///
16 | /// The lock this token has been created by.
17 | ///
18 | SyncLock parent;
19 |
20 | ///
21 | /// Constructs a new lock token for the specified lock.
22 | ///
23 | /// The internal monitor used for locking.
24 | internal LockToken (SyncLock parent)
25 | {
26 | this.parent = parent;
27 | }
28 |
29 | ///
30 | /// Releases the lock. Subsequent calls to this method do nothing.
31 | ///
32 | public void Dispose()
33 | {
34 | if (parent==null)
35 | {
36 | return;
37 | }
38 | parent.Unlock();
39 | parent = null;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Extensions/ReferenceExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Extensions
4 | {
5 | ///
6 | /// Extension methods on all reference types.
7 | ///
8 | public static class ObjectExt
9 | {
10 | ///
11 | /// Throws an ArgumentNullException if the given data item is null.
12 | ///
13 | /// The item to check for nullity.
14 | /// The name to use when throwing an exception, if necessary
15 | public static void ThrowIfNull(this T data, string name) where T : class
16 | {
17 | if (data == null)
18 | {
19 | throw new ArgumentNullException(name);
20 | }
21 | }
22 |
23 | ///
24 | /// Throws an ArgumentNullException if the given data item is null.
25 | /// No parameter name is specified.
26 | ///
27 | /// The item to check for nullity.
28 | public static void ThrowIfNull(this T data) where T : class
29 | {
30 | if (data == null)
31 | {
32 | throw new ArgumentNullException();
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Collections/LinkedComparer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using MiscUtil.Extensions;
3 | namespace MiscUtil.Collections
4 | {
5 | ///
6 | /// Comparer to daisy-chain two existing comparers and
7 | /// apply in sequence (i.e. sort by x then y)
8 | ///
9 | ///
10 | internal class LinkedComparer : IComparer
11 | {
12 | readonly IComparer primary, secondary;
13 | ///
14 | /// Create a new LinkedComparer
15 | ///
16 | /// The first comparison to use
17 | /// The next level of comparison if the primary returns 0 (equivalent)
18 | public LinkedComparer(
19 | IComparer primary,
20 | IComparer secondary)
21 | {
22 | primary.ThrowIfNull("primary");
23 | secondary.ThrowIfNull("secondary");
24 |
25 | this.primary = primary;
26 | this.secondary = secondary;
27 | }
28 |
29 | int IComparer.Compare(T x, T y)
30 | {
31 | int result = primary.Compare(x, y);
32 | return result == 0 ? secondary.Compare(x, y) : result;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Linq/IDataProducer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Linq
4 | {
5 | ///
6 | /// Interface to be implemented by sequences of data which have a "push"
7 | /// nature rather than "pull" - instead of the IEnumerable model of
8 | /// the client pulling data from the sequence, here the client registers
9 | /// an interest in the data being produced, and in the sequence reaching
10 | /// an end. The data producer than produces data whenever it wishes, and the
11 | /// clients can react. This allows other actions to occur between items being
12 | /// pulled, as well as multiple clients for the same sequence of data.
13 | ///
14 | public interface IDataProducer
15 | {
16 | ///
17 | /// Event which is raised when an item of data is produced.
18 | /// This will not be raised after EndOfData has been raised.
19 | /// The parameter for the event is the
20 | ///
21 | event Action DataProduced;
22 | ///
23 | /// Event which is raised when the sequence has finished being
24 | /// produced. This will be raised exactly once, and after all
25 | /// DataProduced events (if any) have been raised.
26 | ///
27 | event Action EndOfData;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Linq/FutureProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Linq
4 | {
5 | ///
6 | /// Implementation of IFuture which retrieves it value from a delegate.
7 | /// This is primarily used for FromFuture, which will transform another
8 | /// Future's value on demand.
9 | ///
10 | public class FutureProxy : IFuture
11 | {
12 | readonly Func fetcher;
13 |
14 | ///
15 | /// Creates a new FutureProxy using the given method
16 | /// to obtain the value when needed
17 | ///
18 | public FutureProxy(Func fetcher)
19 | {
20 | this.fetcher = fetcher;
21 | }
22 |
23 | ///
24 | /// Creates a new FutureProxy from an existing future using
25 | /// the supplied transformation to obtain the value as needed
26 | ///
27 | public static FutureProxy FromFuture(IFuture future, Func projection)
28 | {
29 | return new FutureProxy(() => projection(future.Value));
30 | }
31 | ///
32 | /// Returns the value of the Future
33 | ///
34 | public T Value
35 | {
36 | get
37 | {
38 | return fetcher();
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Collections/Extensions/RangeBasedExt.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Collections.Extensions
3 | {
4 | ///
5 | /// Extension methods to do with ranges.
6 | ///
7 | public static class RangeBasedExt
8 | {
9 | ///
10 | /// Creates an inclusive range between two values. The default comparer is used
11 | /// to compare values.
12 | ///
13 | /// Type of the values
14 | /// Start of range.
15 | /// End of range.
16 | /// An inclusive range between the start point and the end point.
17 | public static Range To(this T start, T end)
18 | {
19 | return new Range(start, end);
20 | }
21 |
22 | ///
23 | /// Returns a RangeIterator over the given range, where the stepping function
24 | /// is to step by the given number of characters.
25 | ///
26 | /// The range to create an iterator for
27 | /// How many characters to step each time
28 | /// A RangeIterator with a suitable stepping function
29 | public static RangeIterator StepChar(this Range range, int step)
30 | {
31 | return range.Step(c => (char)(c + step));
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Collections/ReverseComparer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | using MiscUtil.Extensions;
4 |
5 | namespace MiscUtil.Collections
6 | {
7 | ///
8 | /// Implementation of IComparer{T} based on another one;
9 | /// this simply reverses the original comparison.
10 | ///
11 | ///
12 | public sealed class ReverseComparer : IComparer
13 | {
14 | readonly IComparer originalComparer;
15 |
16 | ///
17 | /// Returns the original comparer; this can be useful to avoid multiple
18 | /// reversals.
19 | ///
20 | public IComparer OriginalComparer
21 | {
22 | get { return originalComparer; }
23 | }
24 |
25 | ///
26 | /// Creates a new reversing comparer.
27 | ///
28 | /// The original comparer to use for comparisons.
29 | public ReverseComparer(IComparer original)
30 | {
31 | original.ThrowIfNull("original");
32 | this.originalComparer = original;
33 | }
34 |
35 | ///
36 | /// Returns the result of comparing the specified values using the original
37 | /// comparer, but reversing the order of comparison.
38 | ///
39 | public int Compare(T x, T y)
40 | {
41 | return originalComparer.Compare(y, x);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Linq/EditableLookup.LookupGrouping.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace MiscUtil.Linq
5 | {
6 | partial class EditableLookup
7 | {
8 | internal sealed class LookupGrouping : IGrouping
9 | {
10 | private readonly TKey key;
11 | private List items = new List();
12 | public TKey Key { get { return key; } }
13 | public LookupGrouping(TKey key)
14 | {
15 | this.key = key;
16 | }
17 | public int Count
18 | {
19 | get { return items.Count; }
20 | }
21 | public void Add(TElement item)
22 | {
23 | items.Add(item);
24 | }
25 | public bool Contains(TElement item)
26 | {
27 | return items.Contains(item);
28 | }
29 | public bool Remove(TElement item)
30 | {
31 | return items.Remove(item);
32 | }
33 | public void TrimExcess()
34 | {
35 | items.TrimExcess();
36 | }
37 |
38 | public IEnumerator GetEnumerator()
39 | {
40 | return items.GetEnumerator();
41 | }
42 |
43 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
44 | {
45 | return GetEnumerator();
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Xml/Linq/Extensions/ObjectExt.cs:
--------------------------------------------------------------------------------
1 | #if DOTNET35
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Xml.Linq;
5 |
6 | namespace MiscUtil.Xml.Linq.Extensions
7 | {
8 | ///
9 | /// Extensions to System.Object for LINQ to XML purposes.
10 | ///
11 | public static class ObjectExt
12 | {
13 | ///
14 | /// Returns the properties of the given object as XElements.
15 | /// Properties with null values are still returned, but as empty
16 | /// elements. Underscores in property names are replaces with hyphens.
17 | ///
18 | public static IEnumerable AsXElements(this object source)
19 | {
20 | foreach (PropertyInfo prop in source.GetType().GetProperties())
21 | {
22 | object value = prop.GetValue(source, null);
23 | yield return new XElement(prop.Name.Replace("_", "-"), value);
24 | }
25 | }
26 |
27 | ///
28 | /// Returns the properties of the given object as XElements.
29 | /// Properties with null values are returned as empty attributes.
30 | /// Underscores in property names are replaces with hyphens.
31 | ///
32 | public static IEnumerable AsXAttributes(this object source)
33 | {
34 | foreach (PropertyInfo prop in source.GetType().GetProperties())
35 | {
36 | object value = prop.GetValue(source, null);
37 | yield return new XAttribute(prop.Name.Replace("_", "-"), value ?? "");
38 | }
39 | }
40 | }
41 | }
42 | #endif
--------------------------------------------------------------------------------
/Linq/Future.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Linq
4 | {
5 | ///
6 | /// Poor-man's version of a Future. This wraps a result which *will* be
7 | /// available in the future. It's up to the caller/provider to make sure
8 | /// that the value has been specified by the time it's requested.
9 | ///
10 | public class Future : IFuture
11 | {
12 | T value;
13 | bool valueSet = false;
14 | ///
15 | /// Returns the value of the future, once it has been set
16 | ///
17 | /// If the value is not yet available
18 | public T Value
19 | {
20 | get
21 | {
22 | if (!valueSet)
23 | {
24 | throw new InvalidOperationException("No value has been set yet");
25 | }
26 | return value;
27 | }
28 | set
29 | {
30 | if (valueSet)
31 | {
32 | throw new InvalidOperationException("Value has already been set");
33 | }
34 | valueSet = true;
35 | this.value = value;
36 | }
37 | }
38 | ///
39 | /// Returns a string representation of the value if available, null otherwise
40 | ///
41 | /// A string representation of the value if available, null otherwise
42 | public override string ToString()
43 | {
44 | return valueSet ? Convert.ToString(value) : null;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Collections/Extensions/ComparerExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MiscUtil.Collections.Extensions
5 | {
6 | ///
7 | /// Extensions to IComparer
8 | ///
9 | public static class ComparerExt
10 | {
11 | ///
12 | /// Reverses the original comparer; if it was already a reverse comparer,
13 | /// the previous version was reversed (rather than reversing twice).
14 | /// In other words, for any comparer X, X==X.Reverse().Reverse().
15 | ///
16 | public static IComparer Reverse(this IComparer original)
17 | {
18 | ReverseComparer originalAsReverse = original as ReverseComparer;
19 | if (originalAsReverse != null)
20 | {
21 | return originalAsReverse.OriginalComparer;
22 | }
23 | return new ReverseComparer(original);
24 | }
25 |
26 | ///
27 | /// Combines a comparer with a second comparer to implement composite sort
28 | /// behaviour.
29 | ///
30 | public static IComparer ThenBy(this IComparer firstComparer, IComparer secondComparer)
31 | {
32 | return new LinkedComparer(firstComparer, secondComparer);
33 | }
34 |
35 | ///
36 | /// Combines a comparer with a projection to implement composite sort behaviour.
37 | ///
38 | public static IComparer ThenBy(this IComparer firstComparer, Func projection)
39 | {
40 | return new LinkedComparer(firstComparer, new ProjectionComparer(projection));
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Compression/Vcdiff/IOHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace MiscUtil.Compression.Vcdiff
5 | {
6 | ///
7 | /// A few IO routines to make life easier. Most are basically available
8 | /// in EndianBinaryReader, but having them separately here makes VcdiffDecoder
9 | /// more easily movable to other places - and no endianness issues are involved in
10 | /// the first place.
11 | ///
12 | internal static class IOHelper
13 | {
14 | internal static byte[] CheckedReadBytes(Stream stream, int size)
15 | {
16 | byte[] ret = new byte[size];
17 | int index=0;
18 | while (index < size)
19 | {
20 | int read = stream.Read(ret, index, size-index);
21 | if (read==0)
22 | {
23 | throw new EndOfStreamException
24 | (String.Format("End of stream reached with {0} byte{1} left to read.", size-index,
25 | size-index==1 ? "s" : ""));
26 | }
27 | index += read;
28 | }
29 | return ret;
30 | }
31 |
32 | internal static byte CheckedReadByte (Stream stream)
33 | {
34 | int b = stream.ReadByte();
35 | if (b==-1)
36 | {
37 | throw new IOException ("Expected to be able to read a byte.");
38 | }
39 | return (byte)b;
40 | }
41 |
42 | internal static int ReadBigEndian7BitEncodedInt(Stream stream)
43 | {
44 | int ret=0;
45 | for (int i=0; i < 5; i++)
46 | {
47 | int b = stream.ReadByte();
48 | if (b==-1)
49 | {
50 | throw new EndOfStreamException();
51 | }
52 | ret = (ret << 7) | (b&0x7f);
53 | if ((b & 0x80) == 0)
54 | {
55 | return ret;
56 | }
57 | }
58 | // Still haven't seen a byte with the high bit unset? Dodgy data.
59 | throw new IOException("Invalid 7-bit encoded integer in stream.");
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/NullOp.cs:
--------------------------------------------------------------------------------
1 | #if DOTNET35
2 | namespace MiscUtil
3 | {
4 | interface INullOp
5 | {
6 | bool HasValue(T value);
7 | bool AddIfNotNull(ref T accumulator, T value);
8 | }
9 | sealed class StructNullOp
10 | : INullOp, INullOp
11 | where T : struct
12 | {
13 | public bool HasValue(T value)
14 | {
15 | return true;
16 | }
17 | public bool AddIfNotNull(ref T accumulator, T value)
18 | {
19 | accumulator = Operator.Add(accumulator, value);
20 | return true;
21 | }
22 | public bool HasValue(T? value)
23 | {
24 | return value.HasValue;
25 | }
26 | public bool AddIfNotNull(ref T? accumulator, T? value)
27 | {
28 | if (value.HasValue)
29 | {
30 | accumulator = accumulator.HasValue ?
31 | Operator.Add(
32 | accumulator.GetValueOrDefault(),
33 | value.GetValueOrDefault())
34 | : value;
35 | return true;
36 | }
37 | return false;
38 | }
39 | }
40 | sealed class ClassNullOp
41 | : INullOp
42 | where T : class
43 | {
44 | public bool HasValue(T value)
45 | {
46 | return value != null;
47 | }
48 | public bool AddIfNotNull(ref T accumulator, T value)
49 | {
50 | if (value != null)
51 | {
52 | accumulator = accumulator == null ?
53 | value : Operator.Add(accumulator, value);
54 | return true;
55 | }
56 | return false;
57 | }
58 | }
59 | }
60 | #endif
--------------------------------------------------------------------------------
/DotNet20/Delegates.cs:
--------------------------------------------------------------------------------
1 | #if !DOTNET35
2 | namespace System
3 | {
4 | ///
5 | /// Delegate taking no parameters and returning no value.
6 | ///
7 | public delegate void Action();
8 | ///
9 | /// Generic delegate taking two parameters and returning no value.
10 | ///
11 | public delegate void Action(T1 arg1, T2 arg2);
12 | ///
13 | /// Generic delegate taking three parameters and returning no value.
14 | ///
15 | public delegate void Action(T1 arg1, T2 arg2, T3 arg3);
16 | ///
17 | /// Generic delegate taking four parameters and returning no value.
18 | ///
19 | public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
20 |
21 | ///
22 | /// Generic delegate taking no parameters and returning a value of the specified type.
23 | ///
24 | public delegate TResult Func();
25 | ///
26 | /// Generic delegate taking one parameter and returning a value of the specified type.
27 | ///
28 | public delegate TResult Func(T arg);
29 | ///
30 | /// Generic delegate taking two parameters and returning a value of the specified type.
31 | ///
32 | public delegate TResult Func(T1 arg1, T2 arg2);
33 | ///
34 | /// Generic delegate taking three parameters and returning a value of the specified type.
35 | ///
36 | public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3);
37 | ///
38 | /// Generic delegate taking four parameters and returning a value of the specified type.
39 | ///
40 | public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
41 | }
42 | #endif
--------------------------------------------------------------------------------
/Compression/Vcdiff/AddressCache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace MiscUtil.Compression.Vcdiff
5 | {
6 | ///
7 | /// Cache used for encoding/decoding addresses.
8 | ///
9 | internal sealed class AddressCache
10 | {
11 | const byte SelfMode = 0;
12 | const byte HereMode = 1;
13 |
14 | int nearSize;
15 | int sameSize;
16 | int[] near;
17 | int nextNearSlot;
18 | int[] same;
19 |
20 | Stream addressStream;
21 |
22 | internal AddressCache(int nearSize, int sameSize)
23 | {
24 | this.nearSize = nearSize;
25 | this.sameSize = sameSize;
26 | near = new int[nearSize];
27 | same = new int[sameSize*256];
28 | }
29 |
30 | internal void Reset(byte[] addresses)
31 | {
32 | nextNearSlot = 0;
33 | Array.Clear(near, 0, near.Length);
34 | Array.Clear(same, 0, same.Length);
35 |
36 | addressStream = new MemoryStream(addresses, false);
37 | }
38 |
39 | internal int DecodeAddress (int here, byte mode)
40 | {
41 | int ret;
42 | if (mode==SelfMode)
43 | {
44 | ret = IOHelper.ReadBigEndian7BitEncodedInt(addressStream);
45 | }
46 | else if (mode==HereMode)
47 | {
48 | ret = here - IOHelper.ReadBigEndian7BitEncodedInt(addressStream);
49 | }
50 | else if (mode-2 < nearSize) // Near cache
51 | {
52 | ret = near[mode-2] + IOHelper.ReadBigEndian7BitEncodedInt(addressStream);
53 | }
54 | else // Same cache
55 | {
56 | int m = mode-(2+nearSize);
57 | ret = same[(m*256)+IOHelper.CheckedReadByte(addressStream)];
58 | }
59 |
60 | Update (ret);
61 | return ret;
62 | }
63 |
64 | void Update (int address)
65 | {
66 | if (nearSize > 0)
67 | {
68 | near[nextNearSlot] = address;
69 | nextNearSlot=(nextNearSlot+1)%nearSize;
70 | }
71 | if (sameSize > 0)
72 | {
73 | same[address%(sameSize*256)] = address;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/GenericMath.cs:
--------------------------------------------------------------------------------
1 | #if DOTNET35
2 | namespace MiscUtil
3 | {
4 | ///
5 | /// Generic math equivalents of System.Math.
6 | /// (Calling this just Math makes far too much mess.)
7 | ///
8 | public static class GenericMath
9 | {
10 | ///
11 | /// Returns the absolute value of a specified number.
12 | ///
13 | /// Type to calculate with
14 | /// Input to return the absolute value of.
15 | /// The input value if it is greater than or equal to the default value of T,
16 | /// or the negated input value otherwise
17 | public static T Abs(T input)
18 | {
19 | return Operator.GreaterThanOrEqual(input, default(T))
20 | ? input
21 | : Operator.Negate(input);
22 | }
23 |
24 | ///
25 | /// Returns whether or not two inputs are "close" to each other with respect to a given delta.
26 | ///
27 | ///
28 | /// This implementation currently does no overflow checking - if (input1-input2) overflows, it
29 | /// could yield the wrong result.
30 | ///
31 | /// Type to calculate with
32 | /// First input value
33 | /// Second input value
34 | /// Permitted range (exclusive)
35 | /// True if Abs(input1-input2) is less than or equal to delta; false otherwise.
36 | public static bool WithinDelta(T input1, T input2, T delta)
37 | {
38 | return Operator.LessThanOrEqual(Abs(Operator.Subtract(input1, input2)), delta);
39 | }
40 | }
41 | }
42 | #endif
43 |
--------------------------------------------------------------------------------
/Linq/Extensions/ListExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using MiscUtil.Collections;
4 | using MiscUtil.Collections.Extensions;
5 | namespace MiscUtil.Linq.Extensions
6 | {
7 | ///
8 | /// Provides extension methods to List<T>
9 | ///
10 | public static class ListExt
11 | {
12 | ///
13 | /// Sorts the elements in the entire System.Collections.Generic.List{T} using
14 | /// a projection.
15 | ///
16 | /// Data source
17 | /// The projection to use to obtain values for comparison
18 | /// The comparer to use to compare projected values (on null to use the default comparer)
19 | /// Should the list be sorted ascending or descending?
20 | public static void Sort(this List source, Func selector, IComparer comparer, bool descending)
21 | {
22 | if (source == null) throw new ArgumentNullException("source");
23 | if (comparer == null) comparer = Comparer.Default;
24 | IComparer itemComparer = new ProjectionComparer(selector, comparer);
25 | if(descending) itemComparer = itemComparer.Reverse();
26 | source.Sort(itemComparer);
27 | }
28 |
29 | ///
30 | /// Sorts the elements in the entire System.Collections.Generic.List{T} using
31 | /// a projection.
32 | ///
33 | /// Data source
34 | /// The projection to use to obtain values for comparison
35 | public static void Sort(this List source, Func selector)
36 | {
37 | Sort(source, selector, null, false);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Linq/ProducerGrouping.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Linq
4 | {
5 | ///
6 | /// Simple implementation of IProducerGrouping which proxies to an existing
7 | /// IDataProducer.
8 | ///
9 | public class ProducerGrouping : IProducerGrouping
10 | {
11 | readonly IDataProducer source;
12 | readonly TKey key;
13 | ///
14 | /// Event which is raised when an item of data is produced.
15 | /// This will not be raised after EndOfData has been raised.
16 | /// The parameter for the event is the
17 | ///
18 | ///
19 | public event Action DataProduced
20 | {
21 | add { source.DataProduced += value; }
22 | remove { source.DataProduced -= value; }
23 | }
24 |
25 | ///
26 | /// Event which is raised when the sequence has finished being
27 | /// produced. This will be raised exactly once, and after all
28 | /// DataProduced events (if any) have been raised.
29 | ///
30 | ///
31 | public event Action EndOfData
32 | {
33 | add { source.EndOfData += value; }
34 | remove { source.EndOfData -= value; }
35 | }
36 |
37 | ///
38 | /// The key for this grouping.
39 | ///
40 | public TKey Key
41 | {
42 | get { return key; }
43 | }
44 |
45 | ///
46 | /// Constructs a new grouping with the given key
47 | ///
48 | public ProducerGrouping(TKey key, IDataProducer source)
49 | {
50 | this.key = key;
51 | this.source = source;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Collections/ComparisonComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MiscUtil.Collections
5 | {
6 | ///
7 | /// Utility to build an IComparer implementation from a Comparison delegate,
8 | /// and a static method to do the reverse.
9 | ///
10 | public sealed class ComparisonComparer : IComparer
11 | {
12 | readonly Comparison comparison;
13 |
14 | ///
15 | /// Creates a new instance which will proxy to the given Comparison
16 | /// delegate when called.
17 | ///
18 | /// Comparison delegate to proxy to. Must not be null.
19 | public ComparisonComparer(Comparison comparison)
20 | {
21 | if (comparison == null)
22 | {
23 | throw new ArgumentNullException("comparison");
24 | }
25 | this.comparison = comparison;
26 | }
27 |
28 | ///
29 | /// Implementation of IComparer.Compare which simply proxies
30 | /// to the originally specified Comparison delegate.
31 | ///
32 | public int Compare(T x, T y)
33 | {
34 | return comparison(x, y);
35 | }
36 |
37 | ///
38 | /// Creates a Comparison delegate from the given Comparer.
39 | ///
40 | /// Comparer to use when the returned delegate is called. Must not be null.
41 | /// A Comparison delegate which proxies to the given Comparer.
42 | public static Comparison CreateComparison(IComparer comparer)
43 | {
44 | if (comparer == null)
45 | {
46 | throw new ArgumentNullException("comparer");
47 | }
48 | return delegate(T x, T y) { return comparer.Compare(x, y); };
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 |
9 | [assembly: InternalsVisibleTo("MiscUtil.UnitTests, PublicKey="
10 | + "0024000004800000940000000602000000240000525341310004000001000100bb16d9f0c36900"
11 | + "bbe4124ff25cbb883abce8e5bc49e9d6185918d978ddc62d9dd2fb31f12c4bca5b5b3ca02a9f85"
12 | + "b094449d96d0a91bcc13f321ecc9446966e35a3b709f5f5b22c66ccea05ee564a91e6ea5959df8"
13 | + "333a40847ed8938194612ce84f7b3e6056ada43918444a883c7ef82583185a8f379281b62d6d2b"
14 | + "2236679c")]
15 | [assembly: AssemblyTitle("MiscUtil")]
16 | [assembly: AssemblyDescription("Miscellaneous Utility Library")]
17 | [assembly: AssemblyConfiguration("")]
18 | [assembly: AssemblyCompany("")]
19 | [assembly: AssemblyProduct("MiscUtil")]
20 | [assembly: AssemblyCopyright("Copyright © 2006")]
21 | [assembly: AssemblyTrademark("")]
22 | [assembly: AssemblyCulture("")]
23 |
24 | // Setting ComVisible to false makes the types in this assembly not visible
25 | // to COM components. If you need to access a type in this assembly from
26 | // COM, set the ComVisible attribute to true on that type.
27 | [assembly: ComVisible(false)]
28 |
29 | // The following GUID is for the ID of the typelib if this project is exposed to COM
30 | [assembly: Guid("90fc96ca-4f38-453f-a805-720f3dbf2f08")]
31 |
32 | // Version information for an assembly consists of the following four values:
33 | //
34 | // Major Version
35 | // Minor Version
36 | // Build Number
37 | // Revision
38 | //
39 | // You can specify all the values or you can default the Revision and Build Numbers
40 | // by using the '*' as shown below:
41 | [assembly: AssemblyVersion("1.0.0.0")]
42 | // This is filled in automatically with the revision number from buildkit.build
43 | [assembly: AssemblyFileVersion("1.0.0.285")]
44 |
--------------------------------------------------------------------------------
/Extensions/TimeRelated/TimeSpanBasedExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Extensions.TimeRelated
4 | {
5 | ///
6 | /// Extension methods producing TimeSpan values. Note: Ticks should really
7 | /// take a long, and the rest should all take doubles. It looks like extension
8 | /// methods don't quite work properly with implicit numeric conversions :(
9 | ///
10 | public static class TimeSpanBasedExt
11 | {
12 | ///
13 | /// Returns a TimeSpan representing the specified number of ticks.
14 | ///
15 | public static TimeSpan Ticks(this int ticks)
16 | {
17 | return TimeSpan.FromTicks(ticks);
18 | }
19 |
20 | ///
21 | /// Returns a TimeSpan representing the specified number of milliseconds.
22 | ///
23 | public static TimeSpan Milliseconds(this int milliseconds)
24 | {
25 | return TimeSpan.FromMilliseconds(milliseconds);
26 | }
27 |
28 | ///
29 | /// Returns a TimeSpan representing the specified number of seconds.
30 | ///
31 | public static TimeSpan Seconds(this int seconds)
32 | {
33 | return TimeSpan.FromSeconds(seconds);
34 | }
35 |
36 | ///
37 | /// Returns a TimeSpan representing the specified number of minutes.
38 | ///
39 | public static TimeSpan Minutes(this int minutes)
40 | {
41 | return TimeSpan.FromMinutes(minutes);
42 | }
43 |
44 | ///
45 | /// Returns a TimeSpan representing the specified number of hours.
46 | ///
47 | public static TimeSpan Hours(this int hours)
48 | {
49 | return TimeSpan.FromHours(hours);
50 | }
51 |
52 | ///
53 | /// Returns a TimeSpan representing the specified number of days.
54 | ///
55 | public static TimeSpan Days(this int days)
56 | {
57 | return TimeSpan.FromDays(days);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Collections/DictionaryByType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | namespace MiscUtil.Collections
4 | {
5 | ///
6 | /// Map from types to instances of those types, e.g. int to 10 and
7 | /// string to "hi" within the same dictionary. This cannot be done
8 | /// without casting (and boxing for value types) as .NET cannot
9 | /// represent this relationship with generics in their current form.
10 | /// This class encapsulates the nastiness in a single place.
11 | ///
12 | public class DictionaryByType
13 | {
14 | private readonly IDictionary dictionary = new Dictionary();
15 |
16 | ///
17 | /// Maps the specified type argument to the given value. If
18 | /// the type argument already has a value within the dictionary,
19 | /// ArgumentException is thrown.
20 | ///
21 | public void Add(T value)
22 | {
23 | dictionary.Add(typeof(T), value);
24 | }
25 |
26 | ///
27 | /// Maps the specified type argument to the given value. If
28 | /// the type argument already has a value within the dictionary, it
29 | /// is overwritten.
30 | ///
31 | public void Put(T value)
32 | {
33 | dictionary[typeof(T)] = value;
34 | }
35 |
36 | ///
37 | /// Attempts to fetch a value from the dictionary, throwing a
38 | /// KeyNotFoundException if the specified type argument has no
39 | /// entry in the dictionary.
40 | ///
41 | public T Get()
42 | {
43 | return (T) dictionary[typeof(T)];
44 | }
45 |
46 | ///
47 | /// Attempts to fetch a value from the dictionary, returning false and
48 | /// setting the output parameter to the default value for T if it
49 | /// fails, or returning true and setting the output parameter to the
50 | /// fetched value if it succeeds.
51 | ///
52 | public bool TryGet(out T value)
53 | {
54 | object tmp;
55 | if (dictionary.TryGetValue(typeof(T), out tmp))
56 | {
57 | value = (T) tmp;
58 | return true;
59 | }
60 | value = default(T);
61 | return false;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Conversion/LittleEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Conversion
3 | {
4 | ///
5 | /// Implementation of EndianBitConverter which converts to/from little-endian
6 | /// byte arrays.
7 | ///
8 | public sealed class LittleEndianBitConverter : EndianBitConverter
9 | {
10 | ///
11 | /// Indicates the byte order ("endianess") in which data is converted using this class.
12 | ///
13 | ///
14 | /// Different computer architectures store data using different byte orders. "Big-endian"
15 | /// means the most significant byte is on the left end of a word. "Little-endian" means the
16 | /// most significant byte is on the right end of a word.
17 | ///
18 | /// true if this converter is little-endian, false otherwise.
19 | public sealed override bool IsLittleEndian()
20 | {
21 | return true;
22 | }
23 |
24 | ///
25 | /// Indicates the byte order ("endianess") in which data is converted using this class.
26 | ///
27 | public sealed override Endianness Endianness
28 | {
29 | get { return Endianness.LittleEndian; }
30 | }
31 |
32 | ///
33 | /// Copies the specified number of bytes from value to buffer, starting at index.
34 | ///
35 | /// The value to copy
36 | /// The number of bytes to copy
37 | /// The buffer to copy the bytes into
38 | /// The index to start at
39 | protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
40 | {
41 | for (int i=0; i < bytes; i++)
42 | {
43 | buffer[i+index] = unchecked((byte)(value&0xff));
44 | value = value >> 8;
45 | }
46 | }
47 |
48 | ///
49 | /// Returns a value built from the specified number of bytes from the given buffer,
50 | /// starting at index.
51 | ///
52 | /// The data in byte array format
53 | /// The first index to use
54 | /// The number of bytes to use
55 | /// The value built from the given bytes
56 | protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
57 | {
58 | long ret = 0;
59 | for (int i=0; i < bytesToConvert; i++)
60 | {
61 | ret = unchecked((ret << 8) | buffer[startIndex+bytesToConvert-1-i]);
62 | }
63 | return ret;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Conversion/BigEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace MiscUtil.Conversion
3 | {
4 | ///
5 | /// Implementation of EndianBitConverter which converts to/from big-endian
6 | /// byte arrays.
7 | ///
8 | public sealed class BigEndianBitConverter : EndianBitConverter
9 | {
10 | ///
11 | /// Indicates the byte order ("endianess") in which data is converted using this class.
12 | ///
13 | ///
14 | /// Different computer architectures store data using different byte orders. "Big-endian"
15 | /// means the most significant byte is on the left end of a word. "Little-endian" means the
16 | /// most significant byte is on the right end of a word.
17 | ///
18 | /// true if this converter is little-endian, false otherwise.
19 | public sealed override bool IsLittleEndian()
20 | {
21 | return false;
22 | }
23 |
24 | ///
25 | /// Indicates the byte order ("endianess") in which data is converted using this class.
26 | ///
27 | public sealed override Endianness Endianness
28 | {
29 | get { return Endianness.BigEndian; }
30 | }
31 |
32 | ///
33 | /// Copies the specified number of bytes from value to buffer, starting at index.
34 | ///
35 | /// The value to copy
36 | /// The number of bytes to copy
37 | /// The buffer to copy the bytes into
38 | /// The index to start at
39 | protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
40 | {
41 | int endOffset = index+bytes-1;
42 | for (int i=0; i < bytes; i++)
43 | {
44 | buffer[endOffset-i] = unchecked((byte)(value&0xff));
45 | value = value >> 8;
46 | }
47 | }
48 |
49 | ///
50 | /// Returns a value built from the specified number of bytes from the given buffer,
51 | /// starting at index.
52 | ///
53 | /// The data in byte array format
54 | /// The first index to use
55 | /// The number of bytes to use
56 | /// The value built from the given bytes
57 | protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
58 | {
59 | long ret = 0;
60 | for (int i=0; i < bytesToConvert; i++)
61 | {
62 | ret = unchecked((ret << 8) | buffer[startIndex+i]);
63 | }
64 | return ret;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Threading/Delegates.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Threading
4 | {
5 | ///
6 | /// Delegate for handling exceptions.
7 | ///
8 | public delegate void ExceptionHandler(object sender, Exception e);
9 |
10 | #region Delegates from CustomThreadPool
11 | ///
12 | /// Delegate for handling exceptions thrown by work items executing
13 | /// in a custom thread pool.
14 | ///
15 | /// The pool which created the worker thread
16 | /// The work item which threw the exception
17 | /// The exception thrown
18 | ///
19 | /// Whether or not the exception has been handled by this delegate. The value
20 | /// of this parameter will be false on entry, and changing it to true will
21 | /// prevent any further delegates in the event from being executed.
22 | ///
23 | public delegate void ThreadPoolExceptionHandler (CustomThreadPool pool,
24 | ThreadPoolWorkItem workItem,
25 | Exception e,
26 | ref bool handled);
27 |
28 | ///
29 | /// Delegate for handling the event that a thread is about to execute
30 | /// a work item.
31 | ///
32 | /// The pool which created the worker thread
33 | /// The work item which is about to execute
34 | ///
35 | /// Whether or not the work item should be cancelled. The value
36 | /// of this parameter will be false on entry, and changing it to true will
37 | /// prevent any further delegates in the event from being executed, and
38 | /// prevent the work item itself from being executed.
39 | ///
40 | public delegate void BeforeWorkItemHandler (CustomThreadPool pool,
41 | ThreadPoolWorkItem workItem,
42 | ref bool cancel);
43 |
44 | ///
45 | /// Delegate for handling the event that a thread has executed a work item.
46 | ///
47 | /// The pool which created the worker thread
48 | /// The work item which has executed
49 | public delegate void AfterWorkItemHandler (CustomThreadPool pool,
50 | ThreadPoolWorkItem workItem);
51 | #endregion
52 |
53 | ///
54 | /// Delegate for handling the event that a thread has changed state
55 | /// (e.g. it's about to execute a work item, it's just executed one, etc).
56 | /// Also used for requests for a thread to change state (e.g. if a stop
57 | /// request has been received).
58 | ///
59 | public delegate void ThreadProgress(object sender);
60 |
61 | ///
62 | /// Represents the method that is executed by a ThreadController.
63 | ///
64 | public delegate void ControlledThreadStart (ThreadController controller, object state);
65 | }
66 |
--------------------------------------------------------------------------------
/StaticRandom.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Thread-safe equivalent of System.Random, using just static methods.
7 | /// If all you want is a source of random numbers, this is an easy class to
8 | /// use. If you need to specify your own seeds (eg for reproducible sequences
9 | /// of numbers), use System.Random.
10 | ///
11 | public static class StaticRandom
12 | {
13 | static Random random = new Random();
14 | static object myLock = new object();
15 |
16 | ///
17 | /// Returns a nonnegative random number.
18 | ///
19 | /// A 32-bit signed integer greater than or equal to zero and less than Int32.MaxValue.
20 | public static int Next()
21 | {
22 | lock (myLock)
23 | {
24 | return random.Next();
25 | }
26 | }
27 |
28 | ///
29 | /// Returns a nonnegative random number less than the specified maximum.
30 | ///
31 | ///
32 | /// A 32-bit signed integer greater than or equal to zero, and less than maxValue;
33 | /// that is, the range of return values includes zero but not maxValue.
34 | ///
35 | /// maxValue is less than zero.
36 | public static int Next(int max)
37 | {
38 | lock (myLock)
39 | {
40 | return random.Next(max);
41 | }
42 | }
43 |
44 | ///
45 | /// Returns a random number within a specified range.
46 | ///
47 | /// The inclusive lower bound of the random number returned.
48 | ///
49 | /// The exclusive upper bound of the random number returned.
50 | /// maxValue must be greater than or equal to minValue.
51 | ///
52 | ///
53 | /// A 32-bit signed integer greater than or equal to minValue and less than maxValue;
54 | /// that is, the range of return values includes minValue but not maxValue.
55 | /// If minValue equals maxValue, minValue is returned.
56 | ///
57 | /// minValue is greater than maxValue.
58 | public static int Next(int min, int max)
59 | {
60 | lock (myLock)
61 | {
62 | return random.Next(min, max);
63 | }
64 | }
65 |
66 | ///
67 | /// Returns a random number between 0.0 and 1.0.
68 | ///
69 | /// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
70 | public static double NextDouble()
71 | {
72 | lock (myLock)
73 | {
74 | return random.NextDouble();
75 | }
76 | }
77 |
78 | ///
79 | /// Fills the elements of a specified array of bytes with random numbers.
80 | ///
81 | /// An array of bytes to contain random numbers.
82 | /// buffer is a null reference (Nothing in Visual Basic).
83 | public static void NextBytes(byte[] buffer)
84 | {
85 | lock (myLock)
86 | {
87 | random.NextBytes(buffer);
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Linq/OrderedDataProducer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using MiscUtil.Extensions;
5 |
6 | namespace MiscUtil.Linq
7 | {
8 | ///
9 | /// A DataProducer with ordering capabilities
10 | /// Note that this may cause data to be buffered
11 | ///
12 | internal class OrderedDataProducer : IOrderedDataProducer
13 | {
14 | private bool dataHasEnded;
15 | private readonly IDataProducer baseProducer;
16 | private readonly IComparer comparer;
17 | private List buffer;
18 |
19 | public IDataProducer BaseProducer
20 | {
21 | get { return baseProducer; }
22 | }
23 |
24 | public IComparer Comparer
25 | {
26 | get { return comparer; }
27 | }
28 |
29 | public event Action DataProduced;
30 | public event Action EndOfData;
31 |
32 | ///
33 | /// Create a new OrderedDataProducer
34 | ///
35 | /// The base source which will supply data
36 | /// The comparer to use when sorting the data (once complete)
37 | public OrderedDataProducer(
38 | IDataProducer baseProducer,
39 | IComparer comparer)
40 | {
41 | baseProducer.ThrowIfNull("baseProducer");
42 |
43 | this.baseProducer = baseProducer;
44 | this.comparer = comparer ?? Comparer.Default;
45 |
46 | baseProducer.DataProduced += new Action(OriginalDataProduced);
47 | baseProducer.EndOfData += new Action(EndOfOriginalData);
48 | }
49 |
50 |
51 | void OriginalDataProduced(T item)
52 | {
53 | if (dataHasEnded)
54 | {
55 | throw new InvalidOperationException("EndOfData already occurred");
56 | }
57 | if (DataProduced != null)
58 | { // only get excited if somebody is listening
59 | if (buffer == null) buffer = new List();
60 | buffer.Add(item);
61 | }
62 | }
63 |
64 | void EndOfOriginalData()
65 | {
66 | if (dataHasEnded)
67 | {
68 | throw new InvalidOperationException("EndOfData already occurred");
69 | }
70 | dataHasEnded = true;
71 | // only do the sort if somebody is still listening
72 | if (DataProduced != null && buffer != null)
73 | {
74 | buffer.Sort(Comparer);
75 | foreach (T item in buffer)
76 | {
77 | OnDataProduced(item);
78 | }
79 | }
80 | buffer = null;
81 | OnEndOfData();
82 | }
83 |
84 | void OnEndOfData()
85 | {
86 | if (EndOfData != null) EndOfData();
87 | }
88 |
89 | void OnDataProduced(T item)
90 | {
91 | if (DataProduced != null) DataProduced(item);
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/IO/StringWriterWithEncoding.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace MiscUtil.IO
6 | {
7 | ///
8 | /// A simple class derived from StringWriter, but which allows
9 | /// the user to select which Encoding is used. This is most
10 | /// likely to be used with XmlTextWriter, which uses the Encoding
11 | /// property to determine which encoding to specify in the XML.
12 | ///
13 | public class StringWriterWithEncoding : StringWriter
14 | {
15 | ///
16 | /// The encoding to return in the Encoding property.
17 | ///
18 | readonly Encoding encoding;
19 |
20 | ///
21 | /// Initializes a new instance of the StringWriterWithEncoding class
22 | /// with the specified encoding.
23 | ///
24 | /// The encoding to report.
25 | public StringWriterWithEncoding(Encoding encoding)
26 | {
27 | if (encoding == null)
28 | {
29 | throw new ArgumentNullException("encoding");
30 | }
31 | this.encoding = encoding;
32 | }
33 |
34 | ///
35 | /// Initializes a new instance of the StringWriter class with the
36 | /// specified format control and encoding.
37 | ///
38 | /// An IFormatProvider object that controls formatting.
39 | /// The encoding to report.
40 | public StringWriterWithEncoding (IFormatProvider formatProvider, Encoding encoding)
41 | : base (formatProvider)
42 | {
43 | if (encoding == null)
44 | {
45 | throw new ArgumentNullException("encoding");
46 | }
47 | this.encoding = encoding;
48 | }
49 |
50 | ///
51 | /// Initializes a new instance of the StringWriter class that writes to the
52 | /// specified StringBuilder, and reports the specified encoding.
53 | ///
54 | /// The StringBuilder to write to.
55 | /// The encoding to report.
56 | public StringWriterWithEncoding (StringBuilder sb, Encoding encoding)
57 | : base (sb)
58 | {
59 | if (encoding == null)
60 | {
61 | throw new ArgumentNullException("encoding");
62 | }
63 | this.encoding = encoding;
64 | }
65 |
66 | ///
67 | /// Initializes a new instance of the StringWriter class that writes to the specified
68 | /// StringBuilder, has the specified format provider, and reports the specified encoding.
69 | ///
70 | /// The StringBuilder to write to.
71 | /// An IFormatProvider object that controls formatting.
72 | /// The encoding to report.
73 | public StringWriterWithEncoding (StringBuilder sb, IFormatProvider formatProvider, Encoding encoding)
74 | : base (sb, formatProvider)
75 | {
76 | if (encoding == null)
77 | {
78 | throw new ArgumentNullException("encoding");
79 | }
80 | this.encoding = encoding;
81 | }
82 |
83 | ///
84 | /// Gets the Encoding in which the output is written.
85 | ///
86 | public override Encoding Encoding
87 | {
88 | get
89 | {
90 | return encoding;
91 | }
92 | }
93 |
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Checksum/Adler32.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace MiscUtil.Checksum
4 | {
5 | ///
6 | /// Implementation of the Adler32 checksum routine.
7 | /// TODO: Derive from HashAlgorithm.
8 | ///
9 | public class Adler32
10 | {
11 | ///
12 | /// Base for modulo arithmetic
13 | ///
14 | const int Base = 65521;
15 |
16 | ///
17 | /// Number of iterations we can safely do before applying the modulo.
18 | ///
19 | const int NMax = 5552;
20 |
21 | ///
22 | /// Computes the Adler32 checksum for the given data.
23 | ///
24 | ///
25 | /// Initial value or previous result. Use 1 for the
26 | /// first transformation.
27 | ///
28 | /// The data to compute the checksum of
29 | /// Index of first byte to compute checksum for
30 | /// Number of bytes to compute checksum for
31 | /// The checksum of the given data
32 | public static int ComputeChecksum (int initial, byte[] data, int start, int length)
33 | {
34 | if (data == null)
35 | {
36 | throw (new System.ArgumentNullException("data"));
37 | }
38 | uint s1 = (uint)(initial & 0xffff);
39 | uint s2 = (uint)((initial >> 16) & 0xffff);
40 |
41 | int index=start;
42 | int len = length;
43 |
44 | int k;
45 | while (len > 0)
46 | {
47 | k = (len < NMax) ? len : NMax;
48 | len -= k;
49 |
50 | for (int i=0; i < k; i++)
51 | {
52 | s1 += data[index++];
53 | s2 += s1;
54 | }
55 | s1 %= Base;
56 | s2 %= Base;
57 | }
58 |
59 | return (int)((s2<<16) | s1);
60 | }
61 |
62 | ///
63 | /// Computes the Adler32 checksum for the given data.
64 | ///
65 | ///
66 | /// Initial value or previous result. Use 1 for the
67 | /// first transformation.
68 | ///
69 | /// The data to compute the checksum of
70 | /// The checksum of the given data
71 | public static int ComputeChecksum (int initial, byte[] data)
72 | {
73 | if (data == null)
74 | {
75 | throw (new System.ArgumentNullException("data"));
76 | }
77 | return ComputeChecksum(initial, data, 0, data.Length);
78 | }
79 |
80 | ///
81 | /// Computes the checksum for a stream, starting from the current
82 | /// position and reading until no more can be read
83 | ///
84 | /// The stream to compute the checksum for
85 | /// The checksum for the stream
86 | public static int ComputeChecksum (Stream stream)
87 | {
88 | if (stream == null)
89 | {
90 | throw (new System.ArgumentNullException("stream"));
91 | }
92 | byte[] buffer = new byte[8172];
93 | int size;
94 | int checksum=1;
95 | while ((size = stream.Read(buffer, 0, buffer.Length)) > 0)
96 | {
97 | checksum = ComputeChecksum(checksum, buffer, 0, size);
98 | }
99 | return checksum;
100 | }
101 |
102 | ///
103 | /// Computes the checksum of a file
104 | ///
105 | /// The file to compute the checksum of
106 | /// The checksum for the file
107 | public static int ComputeChecksum (string path)
108 | {
109 | using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
110 | {
111 | return ComputeChecksum(stream);
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/IO/LineReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace MiscUtil.IO
8 | {
9 | ///
10 | /// Reads a data source line by line. The source can be a file, a stream,
11 | /// or a text reader. In any case, the source is only opened when the
12 | /// enumerator is fetched, and is closed when the iterator is disposed.
13 | ///
14 | public sealed class LineReader : IEnumerable
15 | {
16 | ///
17 | /// Means of creating a TextReader to read from.
18 | ///
19 | readonly Func dataSource;
20 |
21 | ///
22 | /// Creates a LineReader from a stream source. The delegate is only
23 | /// called when the enumerator is fetched. UTF-8 is used to decode
24 | /// the stream into text.
25 | ///
26 | /// Data source
27 | public LineReader(Func streamSource)
28 | : this(streamSource, Encoding.UTF8)
29 | {
30 | }
31 |
32 | ///
33 | /// Creates a LineReader from a stream source. The delegate is only
34 | /// called when the enumerator is fetched.
35 | ///
36 | /// Data source
37 | /// Encoding to use to decode the stream into text
38 | public LineReader(Func streamSource, Encoding encoding)
39 | : this(() => new StreamReader(streamSource(), encoding))
40 | {
41 | }
42 |
43 | ///
44 | /// Creates a LineReader from a filename. The file is only opened
45 | /// (or even checked for existence) when the enumerator is fetched.
46 | /// UTF8 is used to decode the file into text.
47 | ///
48 | /// File to read from
49 | public LineReader(string filename)
50 | : this(filename, Encoding.UTF8)
51 | {
52 | }
53 |
54 | ///
55 | /// Creates a LineReader from a filename. The file is only opened
56 | /// (or even checked for existence) when the enumerator is fetched.
57 | ///
58 | /// File to read from
59 | /// Encoding to use to decode the file into text
60 | public LineReader(string filename, Encoding encoding)
61 | : this(() => new StreamReader(filename, encoding))
62 | {
63 | }
64 |
65 | ///
66 | /// Creates a LineReader from a TextReader source. The delegate
67 | /// is only called when the enumerator is fetched
68 | ///
69 | /// Data source
70 | public LineReader(Func dataSource)
71 | {
72 | this.dataSource = dataSource;
73 | }
74 |
75 | ///
76 | /// Enumerates the data source line by line.
77 | ///
78 | public IEnumerator GetEnumerator()
79 | {
80 | using (TextReader reader = dataSource())
81 | {
82 | string line;
83 | while ((line = reader.ReadLine()) != null)
84 | {
85 | yield return line;
86 | }
87 | }
88 | }
89 |
90 | ///
91 | /// Enumerates the data source line by line.
92 | ///
93 | IEnumerator IEnumerable.GetEnumerator()
94 | {
95 | return GetEnumerator();
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Collections/Extensions/DictionaryExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MiscUtil.Collections.Extensions
5 | {
6 | ///
7 | /// Extensions to IDictionary
8 | ///
9 | public static class DictionaryExt
10 | {
11 | ///
12 | /// Returns the value associated with the specified key if there
13 | /// already is one, or inserts a new value for the specified key and
14 | /// returns that.
15 | ///
16 | /// Type of key
17 | /// Type of value, which must either have
18 | /// a public parameterless constructor or be a value type
19 | /// Dictionary to access
20 | /// Key to lookup
21 | /// Existing value in the dictionary, or new one inserted
22 | public static TValue GetOrCreate(this IDictionary dictionary,
23 | TKey key)
24 | where TValue : new()
25 | {
26 | TValue ret;
27 | if (!dictionary.TryGetValue(key, out ret))
28 | {
29 | ret = new TValue();
30 | dictionary[key] = ret;
31 | }
32 | return ret;
33 | }
34 |
35 | ///
36 | /// Returns the value associated with the specified key if there already
37 | /// is one, or calls the specified delegate to create a new value which is
38 | /// stored and returned.
39 | ///
40 | /// Type of key
41 | /// Type of value
42 | /// Dictionary to access
43 | /// Key to lookup
44 | /// Delegate to provide new value if required
45 | /// Existing value in the dictionary, or new one inserted
46 | public static TValue GetOrCreate(this IDictionary dictionary,
47 | TKey key,
48 | Func valueProvider)
49 | {
50 | TValue ret;
51 | if (!dictionary.TryGetValue(key, out ret))
52 | {
53 | ret = valueProvider();
54 | dictionary[key] = ret;
55 | }
56 | return ret;
57 | }
58 |
59 | ///
60 | /// Returns the value associated with the specified key if there
61 | /// already is one, or inserts the specified value and returns it.
62 | ///
63 | /// Type of key
64 | /// Type of value
65 | /// Dictionary to access
66 | /// Key to lookup
67 | /// Value to use when key is missing
68 | /// Existing value in the dictionary, or new one inserted
69 | public static TValue GetOrCreate(this IDictionary dictionary,
70 | TKey key,
71 | TValue missingValue)
72 | {
73 | TValue ret;
74 | if (!dictionary.TryGetValue(key, out ret))
75 | {
76 | ret = missingValue;
77 | dictionary[key] = ret;
78 | }
79 | return ret;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Compression/Vcdiff/CodeTable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Compression.Vcdiff
4 | {
5 | ///
6 | /// Table used to encode/decode instructions.
7 | ///
8 | internal sealed class CodeTable
9 | {
10 | ///
11 | /// Default code table specified in RFC 3284.
12 | ///
13 | static internal CodeTable Default = BuildDefaultCodeTable();
14 |
15 | ///
16 | /// Array of entries in the code table
17 | ///
18 | Instruction[,] entries = new Instruction[256,2];
19 |
20 | ///
21 | ///
22 | ///
23 | internal Instruction this[int i, int j]
24 | {
25 | get
26 | {
27 | return entries[i, j];
28 | }
29 | }
30 |
31 | internal CodeTable(byte[] bytes)
32 | {
33 | for (int i=0; i < 256; i++)
34 | {
35 | entries[i,0] = new Instruction((InstructionType)bytes[i], bytes[i+512], bytes[i+1024]);
36 | entries[i,1] = new Instruction((InstructionType)bytes[i+256], bytes[i+768], bytes[i+1280]);
37 | }
38 | }
39 |
40 | internal CodeTable(Instruction[,] entries)
41 | {
42 | if (entries==null)
43 | {
44 | throw new ArgumentNullException("entries");
45 | }
46 | if (entries.Rank != 2)
47 | {
48 | throw new ArgumentException ("Array must be rectangular.", "entries");
49 | }
50 | if (entries.GetLength(0) != 256)
51 | {
52 | throw new ArgumentException ("Array must have outer length 256.", "entries");
53 | }
54 | if (entries.GetLength(1) != 2)
55 | {
56 | throw new ArgumentException ("Array must have inner length 256.", "entries");
57 | }
58 | Array.Copy (entries, 0, this.entries, 0, 512);
59 | }
60 |
61 | ///
62 | /// Builds the default code table specified in RFC 3284
63 | ///
64 | ///
65 | /// The default code table.
66 | ///
67 | static CodeTable BuildDefaultCodeTable()
68 | {
69 | // Defaults are NoOps with size and mode 0.
70 | Instruction[,] entries = new Instruction[256,2];
71 | entries[0, 0] = new Instruction(InstructionType.Run, 0, 0);
72 | for (byte i=0; i < 18; i++)
73 | {
74 | entries[i+1, 0] = new Instruction(InstructionType.Add, i, 0);
75 | }
76 |
77 | int index = 19;
78 |
79 | // Entries 19-162
80 | for (byte mode = 0; mode < 9; mode++)
81 | {
82 | entries[index++, 0] = new Instruction (InstructionType.Copy, 0, mode);
83 | for (byte size = 4; size < 19; size++)
84 | {
85 | entries[index++, 0] = new Instruction (InstructionType.Copy, size, mode);
86 | }
87 | }
88 |
89 | // Entries 163-234
90 | for (byte mode = 0; mode < 6; mode++)
91 | {
92 | for (byte addSize = 1; addSize < 5; addSize++)
93 | {
94 | for (byte copySize = 4; copySize < 7; copySize++)
95 | {
96 | entries[index, 0] = new Instruction (InstructionType.Add, addSize, 0);
97 | entries[index++, 1] = new Instruction (InstructionType.Copy, copySize, mode);
98 | }
99 | }
100 | }
101 |
102 | // Entries 235-246
103 | for (byte mode = 6; mode < 9; mode++)
104 | {
105 | for (byte addSize = 1; addSize < 5; addSize++)
106 | {
107 | entries[index, 0] = new Instruction (InstructionType.Add, addSize, 0);
108 | entries[index++, 1] = new Instruction (InstructionType.Copy, 4, mode);
109 | }
110 | }
111 |
112 | // Entries 247-255
113 | for (byte mode = 0; mode < 9; mode++)
114 | {
115 | entries[index, 0] = new Instruction (InstructionType.Copy, 4, mode);
116 | entries[index++, 1] = new Instruction (InstructionType.Add, 1, 0);
117 | }
118 |
119 | return new CodeTable(entries);
120 | }
121 |
122 | internal byte[] GetBytes()
123 | {
124 | byte[] ret = new byte[1536];
125 | for (int i=0; i < 256; i++)
126 | {
127 | ret[i]=(byte)entries[i,0].Type;
128 | ret[i+256]=(byte)entries[i,1].Type;
129 | ret[i+512]=entries[i,0].Size;
130 | ret[i+768]=entries[i,1].Size;
131 | ret[i+1024]=entries[i,0].Mode;
132 | ret[i+1280]=entries[i,1].Mode;
133 | }
134 | return ret;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/PartialComparer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Class to provide partial comparisons, which can be useful when
7 | /// implementing full comparisons in other classes.
8 | ///
9 | public static class PartialComparer
10 | {
11 | ///
12 | /// Provides comparisons for just the references, returning 0
13 | /// if the arguments are the same reference, -1 if just the first is null,
14 | /// and 1 if just the second is null. Otherwise, this method returns null.
15 | /// It can be used to make life easier for an initial comparison
16 | /// before comparing individual components of an object.
17 | ///
18 | /// The type of objects to compare
19 | /// The first object to compare
20 | /// The second object to compare
21 | public static int? ReferenceCompare(T first, T second)
22 | where T : class
23 | {
24 | if (first==second)
25 | {
26 | return 0;
27 | }
28 | if (first==null)
29 | {
30 | return -1;
31 | }
32 | if (second==null)
33 | {
34 | return 1;
35 | }
36 | return null;
37 | }
38 |
39 | ///
40 | /// Compares two instances of T using the default comparer for T,
41 | /// returning a non-null value in the case of inequality, or null
42 | /// where the default comparer would return 0. This aids chained
43 | /// comparisons (where if the first values are equal, you move
44 | /// on to the next ones) if you use the null coalescing operator.
45 | ///
46 | /// The type of objects to compare
47 | /// The first object to compare
48 | /// The second object to compare
49 | public static int? Compare(T first, T second)
50 | {
51 | return Compare(Comparer.Default, first, second);
52 | }
53 |
54 | ///
55 | /// Compares two instances of T using the specified comparer for T,
56 | /// returning a non-null value in the case of inequality, or null
57 | /// where the comparer would return 0. This aids chained
58 | /// comparisons (where if the first values are equal, you move
59 | /// on to the next ones) if you use the null coalescing operator.
60 | ///
61 | /// The type of objects to compare
62 | /// The comparer to use
63 | /// The first object to compare
64 | /// The second object to compare
65 | public static int? Compare(IComparer comparer, T first, T second)
66 | {
67 | int ret = comparer.Compare(first, second);
68 | if (ret == 0)
69 | {
70 | return null;
71 | }
72 | return ret;
73 | }
74 |
75 | ///
76 | /// Compares two instances of T, returning true if they are definitely
77 | /// the same (i.e. the same references), false if exactly one reference is
78 | /// null, or null otherwise. This aids implementing equality operations.
79 | ///
80 | /// The type of objects to compare
81 | /// The first object to compare
82 | /// The second object to compare
83 | public static bool? Equals(T first, T second)
84 | where T : class
85 | {
86 | if (first==second)
87 | {
88 | return true;
89 | }
90 | if (first==null || second==null)
91 | {
92 | return false;
93 | }
94 | return null;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Reflection/PropertyCopy.cs:
--------------------------------------------------------------------------------
1 | #if DOTNET35
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 |
7 | namespace MiscUtil.Reflection
8 | {
9 | ///
10 | /// Generic class which copies to its target type from a source
11 | /// type specified in the Copy method. The types are specified
12 | /// separately to take advantage of type inference on generic
13 | /// method arguments.
14 | ///
15 | public static class PropertyCopy where TTarget : class, new()
16 | {
17 | ///
18 | /// Copies all readable properties from the source to a new instance
19 | /// of TTarget.
20 | ///
21 | public static TTarget CopyFrom(TSource source) where TSource : class
22 | {
23 | return PropertyCopier.Copy(source);
24 | }
25 |
26 | ///
27 | /// Static class to efficiently store the compiled delegate which can
28 | /// do the copying. We need a bit of work to ensure that exceptions are
29 | /// appropriately propagated, as the exception is generated at type initialization
30 | /// time, but we wish it to be thrown as an ArgumentException.
31 | ///
32 | private static class PropertyCopier where TSource : class
33 | {
34 | private static readonly Func copier;
35 | private static readonly Exception initializationException;
36 |
37 | internal static TTarget Copy(TSource source)
38 | {
39 | if (initializationException != null)
40 | {
41 | throw initializationException;
42 | }
43 | if (source == null)
44 | {
45 | throw new ArgumentNullException("source");
46 | }
47 | return copier(source);
48 | }
49 |
50 | static PropertyCopier()
51 | {
52 | try
53 | {
54 | copier = BuildCopier();
55 | initializationException = null;
56 | }
57 | catch (Exception e)
58 | {
59 | copier = null;
60 | initializationException = e;
61 | }
62 | }
63 |
64 | private static Func BuildCopier()
65 | {
66 | ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
67 | var bindings = new List();
68 | foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties())
69 | {
70 | if (!sourceProperty.CanRead)
71 | {
72 | continue;
73 | }
74 | PropertyInfo targetProperty = typeof(TTarget).GetProperty(sourceProperty.Name);
75 | if (targetProperty == null)
76 | {
77 | throw new ArgumentException("Property " + sourceProperty.Name + " is not present and accessible in " + typeof(TTarget).FullName);
78 | }
79 | if (!targetProperty.CanWrite)
80 | {
81 | throw new ArgumentException("Property " + sourceProperty.Name + " is not writable in " + typeof(TTarget).FullName);
82 | }
83 | if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
84 | {
85 | throw new ArgumentException("Property " + sourceProperty.Name + " has an incompatible type in " + typeof(TTarget).FullName);
86 | }
87 | bindings.Add(Expression.Bind(targetProperty, Expression.Property(sourceParameter, sourceProperty)));
88 | }
89 | Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
90 | return Expression.Lambda>(initializer, sourceParameter).Compile();
91 | }
92 | }
93 | }
94 | }
95 | #endif
96 |
--------------------------------------------------------------------------------
/Extensions/TimeRelated/DateTimeBasedExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil.Extensions.TimeRelated
4 | {
5 | ///
6 | /// Extension methods producing DateTime values. These are useful
7 | /// when writing unit tests with fixed dates which should be easily understandable.
8 | ///
9 | public static class DateTimeBasedExt
10 | {
11 | ///
12 | /// Returns a DateTime representing the specified day in January
13 | /// in the specified year.
14 | ///
15 | public static DateTime January(this int day, int year)
16 | {
17 | return new DateTime(year, 1, day);
18 | }
19 |
20 | ///
21 | /// Returns a DateTime representing the specified day in February
22 | /// in the specified year.
23 | ///
24 | public static DateTime February(this int day, int year)
25 | {
26 | return new DateTime(year, 2, day);
27 | }
28 |
29 | ///
30 | /// Returns a DateTime representing the specified day in March
31 | /// in the specified year.
32 | ///
33 | public static DateTime March(this int day, int year)
34 | {
35 | return new DateTime(year, 3, day);
36 | }
37 |
38 | ///
39 | /// Returns a DateTime representing the specified day in April
40 | /// in the specified year.
41 | ///
42 | public static DateTime April(this int day, int year)
43 | {
44 | return new DateTime(year, 4, day);
45 | }
46 |
47 | ///
48 | /// Returns a DateTime representing the specified day in May
49 | /// in the specified year.
50 | ///
51 | public static DateTime May(this int day, int year)
52 | {
53 | return new DateTime(year, 5, day);
54 | }
55 |
56 | ///
57 | /// Returns a DateTime representing the specified day in June
58 | /// in the specified year.
59 | ///
60 | public static DateTime June(this int day, int year)
61 | {
62 | return new DateTime(year, 6, day);
63 | }
64 |
65 | ///
66 | /// Returns a DateTime representing the specified day in July
67 | /// in the specified year.
68 | ///
69 | public static DateTime July(this int day, int year)
70 | {
71 | return new DateTime(year, 7, day);
72 | }
73 |
74 | ///
75 | /// Returns a DateTime representing the specified day in August
76 | /// in the specified year.
77 | ///
78 | public static DateTime August(this int day, int year)
79 | {
80 | return new DateTime(year, 8, day);
81 | }
82 |
83 | ///
84 | /// Returns a DateTime representing the specified day in September
85 | /// in the specified year.
86 | ///
87 | public static DateTime September(this int day, int year)
88 | {
89 | return new DateTime(year, 9, day);
90 | }
91 |
92 | ///
93 | /// Returns a DateTime representing the specified day in October
94 | /// in the specified year.
95 | ///
96 | public static DateTime October(this int day, int year)
97 | {
98 | return new DateTime(year, 10, day);
99 | }
100 |
101 | ///
102 | /// Returns a DateTime representing the specified day in November
103 | /// in the specified year.
104 | ///
105 | public static DateTime November(this int day, int year)
106 | {
107 | return new DateTime(year, 11, day);
108 | }
109 |
110 | ///
111 | /// Returns a DateTime representing the specified day in December
112 | /// in the specified year.
113 | ///
114 | public static DateTime December(this int day, int year)
115 | {
116 | return new DateTime(year, 12, day);
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Collections/RangeIterator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using MiscUtil.Collections.Extensions;
5 | using MiscUtil.Extensions;
6 |
7 | namespace MiscUtil.Collections
8 | {
9 | ///
10 | /// Iterates over a range. Despite its name, this implements IEnumerable{T} rather than
11 | /// IEnumerator{T} - it just sounds better, frankly.
12 | ///
13 | public class RangeIterator : IEnumerable
14 | {
15 | readonly Range range;
16 | ///
17 | /// Returns the range this object iterates over
18 | ///
19 | public Range Range
20 | {
21 | get { return range; }
22 | }
23 |
24 | readonly Func step;
25 | ///
26 | /// Returns the step function used for this range
27 | ///
28 | public Func Step
29 | {
30 | get { return step; }
31 | }
32 |
33 | readonly bool ascending;
34 | ///
35 | /// Returns whether or not this iterator works up from the start point (ascending)
36 | /// or down from the end point (descending)
37 | ///
38 | public bool Ascending
39 | {
40 | get { return ascending; }
41 | }
42 |
43 | ///
44 | /// Creates an ascending iterator over the given range with the given step function
45 | ///
46 | public RangeIterator(Range range, Func step)
47 | : this(range, step, true)
48 | {
49 | }
50 |
51 | ///
52 | /// Creates an iterator over the given range with the given step function,
53 | /// with the specified direction.
54 | ///
55 | public RangeIterator(Range range, Func step, bool ascending)
56 | {
57 | step.ThrowIfNull("step");
58 |
59 | if ((ascending && range.Comparer.Compare(range.Start, step(range.Start)) >= 0) ||
60 | (!ascending && range.Comparer.Compare(range.End, step(range.End)) <= 0))
61 | {
62 | throw new ArgumentException("step does nothing, or progresses the wrong way");
63 | }
64 | this.ascending = ascending;
65 | this.range = range;
66 | this.step = step;
67 | }
68 |
69 | ///
70 | /// Returns an IEnumerator{T} running over the range.
71 | ///
72 | public IEnumerator GetEnumerator()
73 | {
74 | // A descending range effectively has the start and end points (and inclusions)
75 | // reversed, and a reverse comparer.
76 | bool includesStart = ascending ? range.IncludesStart : range.IncludesEnd;
77 | bool includesEnd = ascending ? range.IncludesEnd : range.IncludesStart;
78 | T start = ascending ? range.Start : range.End;
79 | T end = ascending ? range.End : range.Start;
80 | IComparer comparer = ascending ? range.Comparer : range.Comparer.Reverse();
81 |
82 | // Now we can use our local version of the range variables to iterate
83 |
84 | T value = start;
85 |
86 | if (includesStart)
87 | {
88 | // Deal with possibility that start point = end point
89 | if (includesEnd || comparer.Compare(value, end) < 0)
90 | {
91 | yield return value;
92 | }
93 | }
94 | value = step(value);
95 |
96 | while (comparer.Compare(value, end) < 0)
97 | {
98 | yield return value;
99 | value = step(value);
100 | }
101 |
102 | // We've already performed a step, therefore we can't
103 | // still be at the start point
104 | if (includesEnd && comparer.Compare(value, end) == 0)
105 | {
106 | yield return value;
107 | }
108 | }
109 |
110 | ///
111 | /// Returns an IEnumerator running over the range.
112 | ///
113 | IEnumerator IEnumerable.GetEnumerator()
114 | {
115 | return GetEnumerator();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Collections/SmartEnumerable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace MiscUtil.Collections
6 | {
7 | ///
8 | /// Static class to make creation easier. If possible though, use the extension
9 | /// method in SmartEnumerableExt.
10 | ///
11 | public static class SmartEnumerable
12 | {
13 | ///
14 | /// Extension method to make life easier.
15 | ///
16 | /// Type of enumerable
17 | /// Source enumerable
18 | /// A new SmartEnumerable of the appropriate type
19 | public static SmartEnumerable Create(IEnumerable source)
20 | {
21 | return new SmartEnumerable(source);
22 | }
23 | }
24 |
25 | ///
26 | /// Type chaining an IEnumerable<T> to allow the iterating code
27 | /// to detect the first and last entries simply.
28 | ///
29 | /// Type to iterate over
30 | public class SmartEnumerable : IEnumerable.Entry>
31 | {
32 | ///
33 | /// Enumerable we proxy to
34 | ///
35 | readonly IEnumerable enumerable;
36 |
37 | ///
38 | /// Constructor.
39 | ///
40 | /// Collection to enumerate. Must not be null.
41 | public SmartEnumerable(IEnumerable enumerable)
42 | {
43 | if (enumerable==null)
44 | {
45 | throw new ArgumentNullException ("enumerable");
46 | }
47 | this.enumerable = enumerable;
48 | }
49 |
50 | ///
51 | /// Returns an enumeration of Entry objects, each of which knows
52 | /// whether it is the first/last of the enumeration, as well as the
53 | /// current value.
54 | ///
55 | public IEnumerator GetEnumerator()
56 | {
57 | using (IEnumerator enumerator = enumerable.GetEnumerator())
58 | {
59 | if (!enumerator.MoveNext())
60 | {
61 | yield break;
62 | }
63 | bool isFirst = true;
64 | bool isLast = false;
65 | int index=0;
66 | while (!isLast)
67 | {
68 | T current = enumerator.Current;
69 | isLast = !enumerator.MoveNext();
70 | yield return new Entry(isFirst, isLast, current, index++);
71 | isFirst = false;
72 | }
73 | }
74 | }
75 |
76 | ///
77 | /// Non-generic form of GetEnumerator.
78 | ///
79 | IEnumerator IEnumerable.GetEnumerator()
80 | {
81 | return GetEnumerator();
82 | }
83 |
84 | ///
85 | /// Represents each entry returned within a collection,
86 | /// containing the value and whether it is the first and/or
87 | /// the last entry in the collection's. enumeration
88 | ///
89 | public class Entry
90 | {
91 | readonly bool isFirst;
92 | readonly bool isLast;
93 | readonly T value;
94 | readonly int index;
95 |
96 | internal Entry(bool isFirst, bool isLast, T value, int index)
97 | {
98 | this.isFirst = isFirst;
99 | this.isLast = isLast;
100 | this.value = value;
101 | this.index = index;
102 | }
103 |
104 | ///
105 | /// The value of the entry.
106 | ///
107 | public T Value { get { return value; } }
108 |
109 | ///
110 | /// Whether or not this entry is first in the collection's enumeration.
111 | ///
112 | public bool IsFirst { get { return isFirst; } }
113 |
114 | ///
115 | /// Whether or not this entry is last in the collection's enumeration.
116 | ///
117 | public bool IsLast { get { return isLast; } }
118 |
119 | ///
120 | /// The 0-based index of this entry (i.e. how many entries have been returned before this one)
121 | ///
122 | public int Index { get { return index; } }
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/Linq/ExpressionUtil.cs:
--------------------------------------------------------------------------------
1 | #if DOTNET35
2 | using System;
3 | using System.Linq.Expressions;
4 |
5 | namespace MiscUtil.Linq
6 | {
7 | ///
8 | /// General purpose Expression utilities
9 | ///
10 | public static class ExpressionUtil
11 | {
12 | ///
13 | /// Create a function delegate representing a unary operation
14 | ///
15 | /// The parameter type
16 | /// The return type
17 | /// Body factory
18 | /// Compiled function delegate
19 | public static Func CreateExpression(
20 | Func body)
21 | {
22 | ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp");
23 | try
24 | {
25 | return Expression.Lambda>(body(inp), inp).Compile();
26 | }
27 | catch (Exception ex)
28 | {
29 | string msg = ex.Message; // avoid capture of ex itself
30 | return delegate { throw new InvalidOperationException(msg); };
31 | }
32 | }
33 |
34 | ///
35 | /// Create a function delegate representing a binary operation
36 | ///
37 | /// The first parameter type
38 | /// The second parameter type
39 | /// The return type
40 | /// Body factory
41 | /// Compiled function delegate
42 | public static Func CreateExpression(
43 | Func body)
44 | {
45 | return CreateExpression(body, false);
46 | }
47 |
48 | ///
49 | /// Create a function delegate representing a binary operation
50 | ///
51 | ///
52 | /// If no matching operation is possible, attempt to convert
53 | /// TArg1 and TArg2 to TResult for a match? For example, there is no
54 | /// "decimal operator /(decimal, int)", but by converting TArg2 (int) to
55 | /// TResult (decimal) a match is found.
56 | ///
57 | /// The first parameter type
58 | /// The second parameter type
59 | /// The return type
60 | /// Body factory
61 | /// Compiled function delegate
62 | public static Func CreateExpression(
63 | Func body, bool castArgsToResultOnFailure)
64 | {
65 | ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs");
66 | ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs");
67 | try
68 | {
69 | try
70 | {
71 | return Expression.Lambda>(body(lhs, rhs), lhs, rhs).Compile();
72 | }
73 | catch (InvalidOperationException)
74 | {
75 | if (castArgsToResultOnFailure && !( // if we show retry
76 | typeof(TArg1) == typeof(TResult) && // and the args aren't
77 | typeof(TArg2) == typeof(TResult)))
78 | { // already "TValue, TValue, TValue"...
79 | // convert both lhs and rhs to TResult (as appropriate)
80 | Expression castLhs = typeof(TArg1) == typeof(TResult) ?
81 | (Expression)lhs :
82 | (Expression)Expression.Convert(lhs, typeof(TResult));
83 | Expression castRhs = typeof(TArg2) == typeof(TResult) ?
84 | (Expression)rhs :
85 | (Expression)Expression.Convert(rhs, typeof(TResult));
86 |
87 | return Expression.Lambda>(
88 | body(castLhs, castRhs), lhs, rhs).Compile();
89 | }
90 | else throw;
91 | }
92 | }
93 | catch (Exception ex)
94 | {
95 | string msg = ex.Message; // avoid capture of ex itself
96 | return delegate { throw new InvalidOperationException(msg); };
97 | }
98 | }
99 | }
100 | }
101 | #endif
--------------------------------------------------------------------------------
/Linq/DataProducer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MiscUtil.Linq
5 | {
6 | ///
7 | /// Very simple implementation of IDataProducer.
8 | ///
9 | ///
10 | public class DataProducer : IDataProducer
11 | {
12 | ///
13 | /// Event which is raised when an item of data is produced.
14 | /// This will not be raised after EndOfData has been raised.
15 | /// The parameter for the event is the
16 | ///
17 | ///
18 | public event Action DataProduced;
19 | ///
20 | /// Event which is raised when the sequence has finished being
21 | /// produced. This will be raised exactly once, and after all
22 | /// DataProduced events (if any) have been raised.
23 | ///
24 | ///
25 | public event Action EndOfData;
26 | bool endReached = false;
27 |
28 | ///
29 | /// Signals a single item of data.
30 | ///
31 | public void Produce(T item)
32 | {
33 | if (endReached)
34 | {
35 | throw new InvalidOperationException("Cannot produce after end of data");
36 | }
37 | if (DataProduced != null)
38 | {
39 | DataProduced(item);
40 | }
41 | }
42 |
43 | ///
44 | /// Signals multiple items of data, one at a time, then ends.
45 | /// Note that this method only exists to support the params modifier.
46 | /// In every other way it's equivalent to the ProduceAndEnd(IEnumerable{T}).
47 | ///
48 | public void ProduceAndEnd(params T[] items)
49 | {
50 | ProduceAndEnd((IEnumerable)items);
51 | }
52 |
53 | ///
54 | /// Signals multiple items of data, one at a time, then ends.
55 | ///
56 | public void ProduceAndEnd(IEnumerable items)
57 | {
58 | foreach (T item in items)
59 | {
60 | Produce(item);
61 | }
62 | End();
63 | }
64 |
65 | ///
66 | /// Pumps the specified items into this data producer, yielding results
67 | /// as they are received. Before an item is pumped, an internal queue is
68 | /// created. Pumping an item may yield results at the other end of the pipeline
69 | /// - any such results are buffered in the queue. When the pumping of a particular
70 | /// item has finished, all results in the queue are yielded. This means that
71 | /// naturally streaming operations (projection and filtering) require only a single item
72 | /// buffer. This producer "ends" when all the items have been produced. If the result
73 | /// pipeline ends before all items have been pumped, the buffered results are yielded
74 | /// but no more items are pumped.
75 | ///
76 | /// Type of element in the result pipeline
77 | /// Items to insert into the pipeline
78 | /// The pipeline to subscribe to for items to yield
79 | /// A sequence of yielded items.
80 | public IEnumerable PumpProduceAndEnd(IEnumerable items, IDataProducer pipeline)
81 | {
82 | bool stop = false;
83 | Queue resultBuffer = new Queue();
84 | pipeline.DataProduced += result => resultBuffer.Enqueue(result);
85 | pipeline.EndOfData += () => stop = true;
86 | foreach (T item in items)
87 | {
88 | Produce(item);
89 | // Unbuffer as we go
90 | while (resultBuffer.Count > 0)
91 | {
92 | yield return resultBuffer.Dequeue();
93 | }
94 | if (stop)
95 | {
96 | yield break;
97 | }
98 | }
99 | End();
100 | // Yield any final items which may have been produced due to ending the pipeline
101 | while (resultBuffer.Count > 0)
102 | {
103 | yield return resultBuffer.Dequeue();
104 | }
105 | }
106 |
107 | ///
108 | /// Signal the end of data. This can only be called once, and
109 | /// afterwards the Produce method must not be called.
110 | ///
111 | public void End()
112 | {
113 | if (endReached)
114 | {
115 | throw new InvalidOperationException("Cannot produce end twice");
116 | }
117 | endReached = true;
118 | if (EndOfData != null)
119 | {
120 | EndOfData();
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/NonNullable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MiscUtil
4 | {
5 | ///
6 | /// Encapsulates a reference compatible with the type parameter. The reference
7 | /// is guaranteed to be non-null unless the value has been created with the
8 | /// parameterless constructor (e.g. as the default value of a field or array).
9 | /// Implicit conversions are available to and from the type parameter. The
10 | /// conversion to the non-nullable type will throw ArgumentNullException
11 | /// when presented with a null reference. The conversion from the non-nullable
12 | /// type will throw NullReferenceException if it contains a null reference.
13 | /// This type is a value type (to avoid taking any extra space) and as the CLR
14 | /// unfortunately has no knowledge of it, it will be boxed as any other value
15 | /// type. The conversions are also available through the Value property and the
16 | /// parameterised constructor.
17 | ///
18 | /// Type of non-nullable reference to encapsulate
19 | public struct NonNullable : IEquatable> where T : class
20 | {
21 | private readonly T value;
22 |
23 | ///
24 | /// Creates a non-nullable value encapsulating the specified reference.
25 | ///
26 | public NonNullable(T value)
27 | {
28 | if (value == null)
29 | {
30 | throw new ArgumentNullException("value");
31 | }
32 | this.value = value;
33 | }
34 |
35 | ///
36 | /// Retrieves the encapsulated value, or throws a NullReferenceException if
37 | /// this instance was created with the parameterless constructor or by default.
38 | ///
39 | public T Value
40 | {
41 | get
42 | {
43 | if (value == null)
44 | {
45 | throw new NullReferenceException();
46 | }
47 | return value;
48 | }
49 | }
50 |
51 | ///
52 | /// Implicit conversion from the specified reference.
53 | ///
54 | public static implicit operator NonNullable(T value)
55 | {
56 | return new NonNullable(value);
57 | }
58 |
59 | ///
60 | /// Implicit conversion to the type parameter from the encapsulated value.
61 | ///
62 | public static implicit operator T(NonNullable wrapper)
63 | {
64 | return wrapper.Value;
65 | }
66 |
67 | ///
68 | /// Equality operator, which performs an identity comparison on the encapuslated
69 | /// references. No exception is thrown even if the references are null.
70 | ///
71 | public static bool operator ==(NonNullable first, NonNullable second)
72 | {
73 | return first.value == second.value;
74 | }
75 |
76 | ///
77 | /// Inequality operator, which performs an identity comparison on the encapuslated
78 | /// references. No exception is thrown even if the references are null.
79 | ///
80 | public static bool operator !=(NonNullable first, NonNullable second)
81 | {
82 | return first.value != second.value;
83 | }
84 |
85 | ///
86 | /// Equality is deferred to encapsulated references, but there is no equality
87 | /// between a NonNullable[T] and a T. This method never throws an exception,
88 | /// even if a null reference is encapsulated.
89 | ///
90 | public override bool Equals(object obj)
91 | {
92 | if (!(obj is NonNullable))
93 | {
94 | return false;
95 | }
96 | return Equals((NonNullable) obj);
97 | }
98 |
99 | ///
100 | /// Type-safe (and non-boxing) equality check.
101 | ///
102 | public bool Equals(NonNullable other)
103 | {
104 | return object.Equals(this.value, other.value);
105 | }
106 |
107 | ///
108 | /// Type-safe (and non-boxing) static equality check.
109 | ///
110 | public static bool Equals(NonNullable first, NonNullable second)
111 | {
112 | return object.Equals(first.value, second.value);
113 | }
114 |
115 | ///
116 | /// Defers to the GetHashCode implementation of the encapsulated reference, or 0 if
117 | /// the reference is null.
118 | ///
119 | public override int GetHashCode()
120 | {
121 | return value == null ? 0 : value.GetHashCode();
122 | }
123 |
124 | ///
125 | /// Defers to the ToString implementation of the encapsulated reference, or an
126 | /// empty string if the reference is null.
127 | ///
128 | public override string ToString()
129 | {
130 | return value == null ? "" : value.ToString();
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/Threading/ThreadPoolWorkItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 |
4 | namespace MiscUtil.Threading
5 | {
6 | ///
7 | /// Class encapsulating an item of work to be executed in a CustomThreadPool.
8 | ///
9 | public class ThreadPoolWorkItem
10 | {
11 | Delegate target;
12 | ///
13 | /// The target delegate for the work item. This is the delegate
14 | /// which is run when the work item is executed.
15 | ///
16 | public Delegate Target
17 | {
18 | get { return target; }
19 | }
20 |
21 | object[] parameters;
22 | ///
23 | /// The parameters passed to the delegate. This may be null,
24 | /// and will definitely be null if PreserveParameters is false
25 | /// and the work item has started executing. The contents of
26 | /// the returned array should not be changed.
27 | ///
28 | public object[] Parameters
29 | {
30 | get { return parameters; }
31 | }
32 |
33 | int priority;
34 | ///
35 | /// The priority of this work item compared with others. Note
36 | /// that this is entirely independent of the thread priority - it
37 | /// serves only to specify the order of execution of a work item.
38 | /// Items with a higher priority are added ahead of items with a lower
39 | /// priority in the queue.
40 | ///
41 | public int Priority
42 | {
43 | get { return priority; }
44 | }
45 |
46 | bool preserveParameters;
47 | ///
48 | /// Whether or not to preserve parameters during and after
49 | /// execution. If this is true, the parameters are available in
50 | /// the AfterWorkItem and WorkerException events of the containing
51 | /// CustomThreadPool. However, this means that the contents cannot
52 | /// be garbage collected until after the work item has finished
53 | /// executing, which may be costly in some situations.
54 | ///
55 | public bool PreserveParameters
56 | {
57 | get { return preserveParameters; }
58 | }
59 |
60 | object id;
61 | ///
62 | /// The ID of the work item, which may be null. This is provided
63 | /// by the caller when the work item is constructed, and is used
64 | /// for cancellation purposes.
65 | ///
66 | public object ID
67 | {
68 | get { return id; }
69 | }
70 |
71 | ///
72 | /// Creates a new instance of this class.
73 | ///
74 | /// The ID of the work item. May be null.
75 | ///
76 | /// Whether or not the parameter array should be preserved during the work item's
77 | /// execution to allow the information to be retrieved in the WorkerException and
78 | /// AfterWorkItem events.
79 | ///
80 | ///
81 | /// Whether or not the parameter array provided should be cloned. This should be
82 | /// true if the contents of the passed array will be changed by the caller afterwards,
83 | /// but false in the common case of creating the array solely for the purpose of
84 | /// constructing this work item. Note that the values within the array are not cloned
85 | /// - just the array itself.
86 | ///
87 | /// The priority of this work item.
88 | ///
89 | /// The delegate to run when the work item is executed. Must not be null.
90 | ///
91 | ///
92 | /// The parameters to pass to the target delegate. May be null if the delegate
93 | /// takes no parameters.
94 | ///
95 | public ThreadPoolWorkItem (object id, bool preserveParameters, bool cloneParameters,
96 | int priority, Delegate target, params object[] parameters)
97 | {
98 | if (target==null)
99 | {
100 | throw new ArgumentNullException("target");
101 | }
102 | this.id = id;
103 | this.priority = priority;
104 | this.preserveParameters = preserveParameters;
105 | this.target = target;
106 | if (parameters != null)
107 | {
108 | this.parameters = (cloneParameters ? (object[])parameters.Clone() : parameters);
109 | }
110 | }
111 |
112 | ///
113 | /// Creates a new work item with the given target delegate and parameters.
114 | /// The parameters (if any) are cloned on construction and preserved during
115 | /// the work item's execution. The ID of the constructed work item is null,
116 | /// and the priority is 0.
117 | ///
118 | ///
119 | /// The delegate to run when the work item is executed. Must not be null.
120 | ///
121 | ///
122 | /// The parameters to pass to the target delegate. May be null if the delegate
123 | /// takes no parameters.
124 | ///
125 | public ThreadPoolWorkItem (Delegate target, params object[] parameters)
126 | : this ((object)null, true, true, 0, target, parameters)
127 | {
128 | }
129 |
130 | ///
131 | /// Invokes the work item.
132 | ///
133 | internal void Invoke()
134 | {
135 | object[] p = parameters;
136 | if (!preserveParameters)
137 | {
138 | parameters = null;
139 | }
140 | // Should be faster than dynamic invoke
141 | if (target is ThreadStart)
142 | {
143 | ((ThreadStart)target)();
144 | }
145 | else
146 | {
147 | target.DynamicInvoke(p);
148 | }
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/Collections/ProjectionComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using MiscUtil.Extensions;
5 |
6 | namespace MiscUtil.Collections
7 | {
8 | ///
9 | /// Non-generic class to produce instances of the generic class,
10 | /// optionally using type inference.
11 | ///
12 | public static class ProjectionComparer
13 | {
14 | ///
15 | /// Creates an instance of ProjectionComparer using the specified projection.
16 | ///
17 | /// Type parameter for the elements to be compared
18 | /// Type parameter for the keys to be compared, after being projected from the elements
19 | /// Projection to use when determining the key of an element
20 | /// A comparer which will compare elements by projecting each element to its key, and comparing keys
21 | public static ProjectionComparer Create(Func projection)
22 | {
23 | return new ProjectionComparer(projection);
24 | }
25 |
26 | ///
27 | /// Creates an instance of ProjectionComparer using the specified projection.
28 | /// The ignored parameter is solely present to aid type inference.
29 | ///
30 | /// Type parameter for the elements to be compared
31 | /// Type parameter for the keys to be compared, after being projected from the elements
32 | /// Value is ignored - type may be used by type inference
33 | /// Projection to use when determining the key of an element
34 | /// A comparer which will compare elements by projecting each element to its key, and comparing keys
35 | public static ProjectionComparer Create
36 | (TSource ignored,
37 | Func projection)
38 | {
39 | return new ProjectionComparer(projection);
40 | }
41 |
42 | }
43 |
44 | ///
45 | /// Class generic in the source only to produce instances of the
46 | /// doubly generic class, optionally using type inference.
47 | ///
48 | public static class ProjectionComparer
49 | {
50 | ///
51 | /// Creates an instance of ProjectionComparer using the specified projection.
52 | ///
53 | /// Type parameter for the keys to be compared, after being projected from the elements
54 | /// Projection to use when determining the key of an element
55 | /// A comparer which will compare elements by projecting each element to its key, and comparing keys
56 | public static ProjectionComparer Create(Func projection)
57 | {
58 | return new ProjectionComparer(projection);
59 | }
60 | }
61 |
62 | ///
63 | /// Comparer which projects each element of the comparison to a key, and then compares
64 | /// those keys using the specified (or default) comparer for the key type.
65 | ///
66 | /// Type of elements which this comparer will be asked to compare
67 | /// Type of the key projected from the element
68 | public class ProjectionComparer : IComparer
69 | {
70 | readonly Func projection;
71 | readonly IComparer comparer;
72 |
73 | ///
74 | /// Creates a new instance using the specified projection, which must not be null.
75 | /// The default comparer for the projected type is used.
76 | ///
77 | /// Projection to use during comparisons
78 | public ProjectionComparer(Func projection)
79 | : this (projection, null)
80 | {
81 | }
82 |
83 | ///
84 | /// Creates a new instance using the specified projection, which must not be null.
85 | ///
86 | /// Projection to use during comparisons
87 | /// The comparer to use on the keys. May be null, in
88 | /// which case the default comparer will be used.
89 | public ProjectionComparer(Func projection, IComparer comparer)
90 | {
91 | projection.ThrowIfNull("projection");
92 | this.comparer = comparer ?? Comparer.Default;
93 | this.projection = projection;
94 | }
95 |
96 | ///
97 | /// Compares x and y by projecting them to keys and then comparing the keys.
98 | /// Null values are not projected; they obey the
99 | /// standard comparer contract such that two null values are equal; any null value is
100 | /// less than any non-null value.
101 | ///
102 | public int Compare(TSource x, TSource y)
103 | {
104 | // Don't want to project from nullity
105 | if (x==null && y==null)
106 | {
107 | return 0;
108 | }
109 | if (x==null)
110 | {
111 | return -1;
112 | }
113 | if (y==null)
114 | {
115 | return 1;
116 | }
117 | return comparer.Compare(projection(x), projection(y));
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/ApplicationChooser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Reflection;
5 |
6 | namespace MiscUtil
7 | {
8 | ///
9 | /// Class allowing a user to choose a console application to run, after
10 | /// examining an assembly for all classes containing a static Main method, either
11 | /// parameterless or with a string array parameter.
12 | ///
13 | public class ApplicationChooser
14 | {
15 | const string Keys = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
16 |
17 | ///
18 | /// Displays entry points and prompts the user to choose one.
19 | ///
20 | /// Type within the assembly containing the applications. This type is
21 | /// not included in the list of entry points to run.
22 | /// Arguments to pass in for methods which have a single string[] parameter.
23 | public static void Run(Type type, string[] args)
24 | {
25 | Assembly assembly = type.Assembly;
26 |
27 | List entryPoints = new List();
28 | foreach (Type candidate in assembly.GetTypes())
29 | {
30 | if (candidate == type)
31 | {
32 | continue;
33 | }
34 | MethodBase entryPoint = GetEntryPoint(candidate);
35 | if (entryPoint != null)
36 | {
37 | entryPoints.Add(entryPoint);
38 | }
39 | }
40 |
41 | entryPoints.Sort(delegate (MethodBase x, MethodBase y) { return x.DeclaringType.Name.CompareTo(y.DeclaringType.Name); });
42 |
43 | if (entryPoints.Count == 0)
44 | {
45 | Console.WriteLine("No entry points found. Press return to exit.");
46 | Console.ReadLine();
47 | return;
48 | }
49 |
50 | for (int i = 0; i < entryPoints.Count; i++)
51 | {
52 | Console.WriteLine("{0}: {1}", Keys[i],
53 | GetEntryPointName(entryPoints[i]));
54 | }
55 | Console.WriteLine();
56 | Console.Write("Entry point to run? ");
57 | Console.Out.Flush();
58 | char key = Console.ReadKey().KeyChar;
59 | Console.WriteLine();
60 |
61 | // "Enter" means "Oops, let's just quit"
62 | if (key == '\r')
63 | {
64 | return;
65 | }
66 |
67 | int entry = Keys.IndexOf(char.ToUpper(key));
68 | if (entry == -1 || entry >= entryPoints.Count)
69 | {
70 | Console.WriteLine("Invalid choice");
71 | }
72 | else
73 | {
74 | try
75 | {
76 | MethodBase main = entryPoints[entry];
77 | main.Invoke(null, main.GetParameters().Length == 0 ? null : new object[] { args });
78 | }
79 | catch (Exception e)
80 | {
81 | Console.WriteLine("Exception: {0}", e);
82 | }
83 | }
84 | Console.WriteLine();
85 | Console.WriteLine("Press return to exit.");
86 | Console.ReadLine();
87 | }
88 |
89 | private static object GetEntryPointName(MethodBase methodBase)
90 | {
91 | Type type = methodBase.DeclaringType;
92 |
93 | object[] descriptions = type.GetCustomAttributes(typeof(DescriptionAttribute), false);
94 | return descriptions.Length == 0 ?
95 | type.Name :
96 | string.Format("{0} [{1}]", type.Name, ((DescriptionAttribute)descriptions[0]).Description);
97 | }
98 |
99 | ///
100 | /// Returns the entry point for a method, or null if no entry points can be used.
101 | /// An entry point taking string[] is preferred to one with no parameters.
102 | ///
103 | internal static MethodBase GetEntryPoint(Type type)
104 | {
105 | if (type.IsGenericTypeDefinition || type.IsGenericType)
106 | {
107 | return null;
108 | }
109 |
110 | BindingFlags anyStatic = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
111 | // Can't use GetMethod directly as then we can't ignore generic methods :(
112 |
113 | MethodInfo[] methods = type.GetMethods(anyStatic);
114 |
115 | MethodInfo parameterless = null;
116 | MethodInfo stringArrayParameter = null;
117 |
118 | foreach (MethodInfo method in methods)
119 | {
120 | if (method.Name != "Main")
121 | {
122 | continue;
123 | }
124 | if (method.IsGenericMethod || method.IsGenericMethodDefinition)
125 | {
126 | continue;
127 | }
128 | ParameterInfo[] parameters = method.GetParameters();
129 | if (parameters.Length == 0)
130 | {
131 | parameterless = method;
132 | }
133 | else
134 | {
135 | if (parameters.Length == 1 &&
136 | !parameters[0].IsOut &&
137 | !parameters[0].IsOptional &&
138 | parameters[0].ParameterType==typeof(string[]))
139 | {
140 | stringArrayParameter = method;
141 | }
142 | }
143 | }
144 |
145 | // Prefer the version with parameters, return null if neither have been found
146 | return stringArrayParameter ?? parameterless;
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/Linq/KeyValueTuple.cs:
--------------------------------------------------------------------------------
1 | namespace MiscUtil.Linq
2 | {
3 | ///
4 | /// Generic tuple for a key and a single value
5 | ///
6 | /// The Type of the key
7 | /// The Type of the value
8 | public struct KeyValueTuple
9 | {
10 | readonly TKey key;
11 | readonly T value;
12 | ///
13 | /// The key for the tuple
14 | ///
15 | public TKey Key
16 | {
17 | get { return key; }
18 | }
19 | ///
20 | /// The value for the tuple
21 | ///
22 | public T Value
23 | {
24 | get { return value; }
25 | }
26 | ///
27 | /// Creates a new tuple with the given key and value
28 | ///
29 | public KeyValueTuple(TKey key, T value)
30 | {
31 | this.key = key;
32 | this.value = value;
33 | }
34 | }
35 | ///
36 | /// Generic tuple for a key and a pair of values
37 | ///
38 | /// The Type of the key
39 | /// The Type of the first value
40 | /// The Type of the second value
41 | public struct KeyValueTuple
42 | {
43 | readonly TKey key;
44 | readonly T1 value1;
45 | readonly T2 value2;
46 | ///
47 | /// The key for the tuple
48 | ///
49 | public TKey Key
50 | {
51 | get { return key; }
52 | }
53 | ///
54 | /// The first value
55 | ///
56 | public T1 Value1
57 | {
58 | get { return value1; }
59 | }
60 | ///
61 | /// The second value
62 | ///
63 | public T2 Value2
64 | {
65 | get { return value2; }
66 | }
67 | ///
68 | /// Creates a new tuple with the given key and values
69 | ///
70 | public KeyValueTuple(TKey key, T1 value1, T2 value2)
71 | {
72 | this.key = key;
73 | this.value1 = value1;
74 | this.value2 = value2;
75 | }
76 | }
77 | ///
78 | /// Generic tuple for a key and a trio of values
79 | ///
80 | /// The Type of the key
81 | /// The Type of the first value
82 | /// The Type of the second value
83 | /// The Type of the third value
84 | public struct KeyValueTuple
85 | {
86 | readonly TKey key;
87 | readonly T1 value1;
88 | readonly T2 value2;
89 | readonly T3 value3;
90 | ///
91 | /// The key for the tuple
92 | ///
93 | public TKey Key
94 | {
95 | get { return key; }
96 | }
97 | ///
98 | /// The first value
99 | ///
100 | public T1 Value1
101 | {
102 | get { return value1; }
103 | }
104 | ///
105 | /// The second value
106 | ///
107 | public T2 Value2
108 | {
109 | get { return value2; }
110 | }
111 | ///
112 | /// The third value
113 | ///
114 | public T3 Value3
115 | {
116 | get { return value3; }
117 | }
118 | ///
119 | /// Creates a new tuple with the given key and values
120 | ///
121 | public KeyValueTuple(TKey key, T1 value1, T2 value2, T3 value3)
122 | {
123 | this.key = key;
124 | this.value1 = value1;
125 | this.value2 = value2;
126 | this.value3 = value3;
127 | }
128 | }
129 | ///
130 | /// Generic tuple for a key and a quartet of values
131 | ///
132 | /// The Type of the key
133 | /// The Type of the first value
134 | /// The Type of the second value
135 | /// The Type of the third value
136 | /// The Type of the fourth value
137 | public struct KeyValueTuple
138 | {
139 | readonly TKey key;
140 | readonly T1 value1;
141 | readonly T2 value2;
142 | readonly T3 value3;
143 | readonly T4 value4;
144 |
145 | ///
146 | /// The key for the tuple
147 | ///
148 | public TKey Key
149 | {
150 | get { return key; }
151 | }
152 | ///
153 | /// The first value
154 | ///
155 | public T1 Value1
156 | {
157 | get { return value1; }
158 | }
159 | ///
160 | /// The second value
161 | ///
162 | public T2 Value2
163 | {
164 | get { return value2; }
165 | }
166 | ///
167 | /// The third value
168 | ///
169 | public T3 Value3
170 | {
171 | get { return value3; }
172 | }
173 | ///
174 | /// The fourth value
175 | ///
176 | public T4 Value4
177 | {
178 | get { return value4; }
179 | }
180 | ///
181 | /// Creates a new tuple with the given key and values
182 | ///
183 | public KeyValueTuple(TKey key, T1 value1, T2 value2, T3 value3, T4 value4)
184 | {
185 | this.key = key;
186 | this.value1 = value1;
187 | this.value2 = value2;
188 | this.value3 = value3;
189 | this.value4 = value4;
190 | }
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/Threading/OrderedLock.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 |
3 | namespace MiscUtil.Threading
4 | {
5 | ///
6 | /// Class used for locking, as an alternative to just locking on normal monitors.
7 | /// Allows for timeouts when locking, and each Lock method returns a token which
8 | /// must then be disposed of to release the internal monitor (i.e. to unlock).
9 | /// All properties and methods of this class are thread-safe.
10 | ///
11 | public class OrderedLock : SyncLock
12 | {
13 | #region Fields which aren't backing properties
14 | ///
15 | /// Lock count (incremented with Lock, decremented with Unlock).
16 | ///
17 | int count;
18 | #endregion
19 |
20 | #region Properties
21 | volatile Thread owner;
22 | ///
23 | /// The current owner of the lock, if any.
24 | ///
25 | public Thread Owner
26 | {
27 | get { return owner; }
28 | }
29 |
30 | volatile OrderedLock innerLock;
31 | ///
32 | /// Gets or sets the "inner" lock for this lock. This lock must not be acquired
33 | /// after the inner one, unless it has already been acquired previously.
34 | /// Inner locks are transitive - if A has an inner lock B, and B has
35 | /// an inner lock C, then C is also effectively an inner lock of A.
36 | /// If this property to null, this lock is considered not to have an inner lock.
37 | ///
38 | public OrderedLock InnerLock
39 | {
40 | set
41 | {
42 | innerLock = value;
43 | }
44 | get
45 | {
46 | return innerLock;
47 | }
48 | }
49 | #endregion
50 |
51 | #region Constructors
52 | ///
53 | /// Creates a new lock with no name, and the default timeout specified by DefaultDefaultTimeout.
54 | ///
55 | public OrderedLock() : base()
56 | {
57 | }
58 |
59 | ///
60 | /// Creates a new lock with the specified name, and the default timeout specified by
61 | /// DefaultDefaultTimeout.
62 | ///
63 | /// The name of the new lock
64 | public OrderedLock (string name) : base(name)
65 | {
66 | }
67 |
68 | ///
69 | /// Creates a new lock with no name, and the specified default timeout
70 | ///
71 | /// Default timeout, in milliseconds
72 | public OrderedLock(int defaultTimeout) : base(defaultTimeout)
73 | {
74 | }
75 |
76 | ///
77 | /// Creates a new lock with the specified name, and an
78 | /// infinite default timeout.
79 | ///
80 | /// The name of the new lock
81 | ///
82 | /// Default timeout, in milliseconds. Use Timeout.Infinite
83 | /// for an infinite timeout, or a non-negative number otherwise.
84 | ///
85 | public OrderedLock (string name, int defaultTimeout) : base (name, defaultTimeout)
86 | {
87 | }
88 | #endregion
89 |
90 | #region Deadlock detection
91 | ///
92 | /// Sets the "inner" lock for this lock, returning this lock. This
93 | /// is a convenience method for setting InnerLock as part of a variable
94 | /// declaration.
95 | ///
96 | ///
97 | /// OrderedLock inner = new OrderedLock();
98 | /// OrderedLock outer = new OrderedLock().SetInnerLock(inner);
99 | ///
100 | /// The inner
101 | /// This lock is returned.
102 | public OrderedLock SetInnerLock (OrderedLock inner)
103 | {
104 | InnerLock = inner;
105 | return this;
106 | }
107 | #endregion
108 |
109 | #region Lock methods
110 | ///
111 | /// Locks the monitor, with the specified timeout. This implementation validates
112 | /// the ordering of locks, and maintains the current owner.
113 | ///
114 | /// The timeout, in milliseconds. Must be Timeout.Infinite,
115 | /// or non-negative.
116 | /// A lock token which should be disposed to release the lock
117 | /// The operation times out.
118 | ///
119 | /// The lock order would be violated if this lock were taken out. (i.e. attempting
120 | /// to acquire the lock could cause deadlock.)
121 | ///
122 | public override LockToken Lock (int timeout)
123 | {
124 | // Check whether we should be allowed to take out this lock, according to
125 | // the inner locks we have.
126 | // Performance note: This would be in a separate method, but the cost of
127 | // making a method call (which can't be inlined in this case) is sufficiently
128 | // high as to make it worth manually inlining.
129 | OrderedLock inner = InnerLock;
130 | // Performance note: This would be a single if statement with shortcutting,
131 | // but fetching the current thread is mildly expensive.
132 | if (inner!=null)
133 | {
134 | Thread currentThread = Thread.CurrentThread;
135 | if (Owner!=currentThread)
136 | {
137 | while (inner != null)
138 | {
139 | if (inner.Owner==currentThread)
140 | {
141 | throw new LockOrderException("Unable to acquire lock {0} as lock {1} is already held",
142 | Name, inner.Name);
143 | }
144 | inner = inner.InnerLock;
145 | }
146 | }
147 | }
148 |
149 | LockToken ret = base.Lock(timeout);
150 |
151 | // Now remember that we've locked, and set the owner if necessary
152 | // Performance note: On a single processor, it is slightly cheaper
153 | // to assign owner every time, without a test. On multiple processor
154 | // boxes, it is cheaper to avoid the volatile write.
155 | if (Interlocked.Increment(ref count)==1)
156 | {
157 | owner = Thread.CurrentThread;
158 | }
159 | return ret;
160 | }
161 |
162 | ///
163 | /// Unlocks the monitor, decreasing the count and setting the owner to null
164 | /// if the count becomes 0.
165 | ///
166 | protected internal override void Unlock()
167 | {
168 | base.Unlock();
169 | if (Interlocked.Decrement(ref count)==0)
170 | {
171 | owner = null;
172 | }
173 | }
174 | #endregion
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/Collections/ProjectionEqualityComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using MiscUtil.Extensions;
4 |
5 | namespace MiscUtil.Collections
6 | {
7 | ///
8 | /// Non-generic class to produce instances of the generic class,
9 | /// optionally using type inference.
10 | ///
11 | public static class ProjectionEqualityComparer
12 | {
13 | ///
14 | /// Creates an instance of ProjectionEqualityComparer using the specified projection.
15 | ///
16 | /// Type parameter for the elements to be compared
17 | /// Type parameter for the keys to be compared, after being projected from the elements
18 | /// Projection to use when determining the key of an element
19 | /// A comparer which will compare elements by projecting each element to its key, and comparing keys
20 | public static ProjectionEqualityComparer Create(Func projection)
21 | {
22 | return new ProjectionEqualityComparer(projection);
23 | }
24 |
25 | ///