• Lexical
Show / Hide Table of Contents
  • Lexical.FileSystem
    • Introduction
    • Abstractions
      • IFileSystem
        • IFileSystem
        • IFileSystemBrowse
        • IFileSystemCreateDirectory
        • IFileSystemDelete
        • IFileSystemFileAttribute
        • IFileSystemMount
        • IFileSystemMove
        • IFileSystemObserve
        • IFileSystemOpen
      • IEvent
      • IEntry
      • IOption
      • IToken
    • FileSystem
    • VirtualFileSystem
    • MemoryFileSystem
    • EmbeddedFileSystem
    • HttpFileSystem
    • Decoration
    • IFileProvider
    • Utility
      • DisposeList
      • FileScanner
      • VisitTree
      • File Operation
  • Lexical.FileProvider
    • Introduction
    • Package
    • Package.Abstractions
    • Root
    • Zip
    • Dll
    • SharpCompress
    • SharpZipLib
    • FileScanner
    • Utils
  • Lexical.Localization
    • Introduction
    • Tutorial
    • Asset
      • IAsset
      • IStringAsset
    • Line
      • ILine
      • ILineFactory
      • ILineRoot
      • ILineFormat
      • ILineLogger
      • LineComparer
    • File
      • ILineReader
      • ILineWriter
      • Ini
      • Json
      • Xml
      • Resx
      • Resources
    • Miscellaneous
      • Plurality
      • ICulturePolicy
      • IStringFormat
      • Dependency Injection
    • Practices
      • Class Library
      • Class Library DI
      • Class Library DI opt.
  • Lexical.Utilities
    • Introduction
    • UnicodeString
    • FileScanner
    • Permutation
    • Tuples
    • StructList

Lexical.Utils

This is a namespace for various utility class libraries.

  • Website
  • Github

Class Libraries.

  • UnicodeString
  • Tuples
  • Permutation
  • FileSystem

Contents:

  • Permutation
  • Tuples
  • UnicodeString
  • FileScanner
  • Collections

Lexical.Utils.Permutation

Lexical.Utils.Permutation is a class library for unit testing. It's a toolkit for feeding different variations of parameters.

PermutationSetup is populated with properties and possible values.

PermutationSetup permutation = new PermutationSetup();

// Add property "Color"
permutation.Add("Color", "Red");
permutation.Add("Color", "Green");
permutation.Add("Color", "Blue");

// Add property "Number"
permutation.Add("Number", "10");
permutation.Add("Number", "100");
permutation.Add("Number", "1000");

// Add property "Size"
permutation.Add("Size", "Small");
permutation.Add("Size", "Medium");
permutation.Add("Size", "Large");

Every scenario can be iterated.

foreach (Scenario scenario in permutation.Scenarios)
{
    string color = scenario["Color"].Name;
    string number = scenario["Number"].Name;
    string size = scenario["Size"].Name;

    Console.WriteLine($"Color={color}, Number={number}, Size={size}");
}

The result. (Click here)

Color=Red, Number=10, Size=Small
Color=Green, Number=10, Size=Small
Color=Blue, Number=10, Size=Small
Color=Red, Number=100, Size=Small
Color=Green, Number=100, Size=Small
Color=Blue, Number=100, Size=Small
Color=Red, Number=1000, Size=Small
Color=Green, Number=1000, Size=Small
Color=Blue, Number=1000, Size=Small
Color=Red, Number=10, Size=Medium
Color=Green, Number=10, Size=Medium
Color=Blue, Number=10, Size=Medium
Color=Red, Number=100, Size=Medium
Color=Green, Number=100, Size=Medium
Color=Blue, Number=100, Size=Medium
Color=Red, Number=1000, Size=Medium
Color=Green, Number=1000, Size=Medium
Color=Blue, Number=1000, Size=Medium
Color=Red, Number=10, Size=Large
Color=Green, Number=10, Size=Large
Color=Blue, Number=10, Size=Large
Color=Red, Number=100, Size=Large
Color=Green, Number=100, Size=Large
Color=Blue, Number=100, Size=Large
Color=Red, Number=1000, Size=Large
Color=Green, Number=1000, Size=Large
Color=Blue, Number=1000, Size=Large

Each value can be associated with an object. The object is initialized with a delegate Func<Run, object>, and can be cleaned with another delegate Action<Run>.

PermutationSetup permutation = new PermutationSetup();

// Add property "Color"
permutation.Add("Color", "Red", null, run => Color.Red, run => { /*finalizer here*/ });
permutation.Add("Color", "Green", null, run => Color.Green);
permutation.Add("Color", "Blue", null, run => Color.Blue);

// Add property "Number"
permutation.Add("Number", "10", null, run => 10);
permutation.Add("Number", "100", null, run => 100);
permutation.Add("Number", "1000", null, run => 1000);

// Add property "Size"
permutation.Add("Size", "Small", null, run => Size.Small);
permutation.Add("Size", "Medium", null, run => Size.Medium);
permutation.Add("Size", "Large", null, run => Size.Large);

Use Run() to execute the initializers and finalizers.

foreach (Scenario scenario in permutation.Scenarios)
{
    using (Run run = scenario.Run().Initialize())
    {
        Color color = (Color)run["Color"];
        int number = (int)run["Number"];
        Size size = (Size)run["Size"];

        Console.WriteLine($"Color={color}, Number={number}, Size={size}");
    }
}

Enums used in this permutation

enum Color { Red, Green, Blue }
enum Size { Small, Medium, Large }

Tuples

Tuples are not entirely trivial. There is variance in the features that are needed in different situations.

  • Website
  • Github
  • Nuget

In this package there are tuples that come from the permutations of the following features.

Value-Typed and Reference-Typed

There are value-typed struct versions and reference-typed class versions of each tuple. Reference-typed tuples have suffix Object, for example "PairObject".

// Stack allocated
var pair_stack = new Pair<int, int>(1, 2);

// Heap allocated
var pair_heap = new PairObject<int, int>(1, 2);

Mutability

Tuples that are mutable have suffix Mutable. Immutable tuples don't have a suffix. Immutable tuples cache their hashcode, and mutable calculate as needed.

// Immutable
var pair_immutable = new Pair<int, int>(1, 2);
int hash_is_cached = pair_immutable.GetHashCode();

// Mutable
var pair_mutable = new PairMutable<int, int>(2, 3);
pair_mutable.a = 4;
pair_mutable.b = 6;
int hash_is_calculated = pair_mutable.GetHashCode();

Set Tuples

The elements of set tuples are interchangeable, the order of elements doesn't matter in hash-equals comparisons. That means that PairSet(1, 2) is equal to PairSet(2, 1). The name suffix is "Set", for example "PairSet".

// Create pairs
var pair1 = new PairSet<int>(1, 2);
var pair2 = new PairSet<int>(2, 1);

// Get equality comparer singleton instance
IEqualityComparer<PairSet<int>> equalsComparer = PairSet<int>.EqualityComparer.Default;

// Compare
bool areEqual = equalsComparer.Equals(pair1, pair2);

EqualityComparer

Each tuple class comes with an EqualityComparer implementation. There is a singleton instance TupleType.EqualityComparer.Default.

// Create pairs
var pair1 = new Pair<int, int>(1, 2);
var pair2 = new Pair<int, int>(2, 3);

// Get equality comparer singleton instance
IEqualityComparer<Pair<int, int>> equalsComparer = Pair<int, int>.EqualityComparer.Default;

// Compare
bool areEqual = equalsComparer.Equals(pair1, pair2);

Tuple types implement IEquatable<TupleType> any way, so they comparable as is. This makes value typed tuples comparable without boxing.

// Compare
bool areEqual = pair1.Equals(pair2);

Comparer

Each non-Set tuple class comes with a Comparer implementation. There is a singleton instance TupleType.Comparer.Default.

// Create pairs
var pair1 = new Pair<int, int>(1, 2);
var pair2 = new Pair<int, int>(2, 3);

// Get equality comparer singleton instance
IComparer<Pair<int, int>> comparer = Pair<int, int>.Comparer.Default;

// Compare
int c = comparer.Compare(pair1, pair2);

Tuple types implement IComparable<TupleType> any way, so they comparable as is. This makes value typed tuples comparable without boxing.

// Compare
int c = pair1.CompareTo(pair2);

Argument Count

There is a separate tuple type for cases with different number of arguments. The stem of the name is based on the count.

  1. Container
  2. Pair
  3. Triple
  4. Quad
  5. Pento
  6. Sextim
  7. Septim
  8. Octet
// One argument
var container = new ContainerMutableObject<string>("Hello");
container.a = "New Hello";

// Two arguments
var pair = new PairMutable<int, int>(1, 2);

// Three arguments
var triple = new TripleSet<int>(5, 6, 7);

// Four arguments
var quad = new QuadObject<byte, byte, byte, byte>(1, 2, 3, 4);

Classes

Name Type Hashcode Mutability Elements Ordered
Container<A> struct cached immutable are ordered
ContainerObject<A> class cached immutable are ordered
ContainerMutable<A> struct not cached mutable are ordered
ContainerMutableObject<A> class not cached mutable are ordered
Pair<A, B> struct cached immutable are ordered
PairObject<A, B> class cached immutable are ordered
PairMutable<A, B> struct not cached mutable are ordered
PairMutableObject<A, B> class not cached mutable are ordered
PairSet<T> struct cached immutable are interchangeable
PairSetObject<T> class cached immutable are interchangeable
PairSetMutable<T> struct not cached mutable are interchangeable
PairSetMutableObject<T> class not cached mutable are interchangeable
Triple<A, B, C> struct cached immutable are ordered
TripleObject<A, B, C> class cached immutable are ordered
TripleMutable<A, B, C> struct not cached mutable are ordered
TripleMutableObject<A, B, C> class not cached mutable are ordered
TripleSet<T> struct cached immutable are interchangeable
TripleSetObject<T> class cached immutable are interchangeable
TripleSetMutable<T> struct not cached mutable are interchangeable
TripleSetMutableObject<T> class not cached mutable are interchangeable
Quad<A, B, C, D> struct cached immutable are ordered
QuadObject<A, B, C, D> class cached immutable are ordered
QuadMutable<A, B, C, D> struct not cached mutable are ordered
QuadMutableObject<A, B, C, D> class not cached mutable are ordered
QuadSet<T> struct cached immutable are interchangeable
QuadSetObject<T> class cached immutable are interchangeable
QuadSetMutable<T> struct not cached mutable are interchangeable
QuadSetMutableObject<T> class not cached mutable are interchangeable
Pento<A, B, C, D, E> struct cached immutable are ordered
PentoObject<A, B, C, D, E> class cached immutable are ordered
PentoMutable<A, B, C, D, E> struct not cached mutable are ordered
PentoMutableObject<A, B, C, D, E> class not cached mutable are ordered
Sextim<A, B, C, D, E, F> struct cached immutable are ordered
SextimObject<A, B, C, D, E, F> class cached immutable are ordered
SextimMutable<A, B, C, D, E, F> struct not cached mutable are ordered
SextimMutableObject<A, B, C, D, E, F> class not cached mutable are ordered
Septim<A, B, C, D, E, F, G> struct cached immutable are ordered
SeptimObject<A, B, C, D, E, F, G> class cached immutable are ordered
SeptimMutable<A, B, C, D, E, F, G> struct not cached mutable are ordered
SeptimMutableObject<A, B, C, D, E, F, G> class not cached mutable are ordered
Octet<A, B, C, D, E, F, G, H> struct cached immutable are ordered
OctetObject<A, B, C, D, E, F, G, H> class cached immutable are ordered
OctetMutable<A, B, C, D, E, F, G, H> struct not cached mutable are ordered
OctetMutableObject<A, B, C, D, E, F, G, H> class not cached mutable are ordered

UnicodeString

UnicodeString addresses issues that come when handing strings with different encodings.

  • Website
  • Github
  • Nuget

Construct

UnicodeString can be constructed from

  • IEnumerable<byte>, byte[]
  • IEnumerable<char>, char[], String
  • IEnumerable<int>., int[]

UnicodeString is a wrapper that keeps reference to the source object that it was constructed from.

// Construct from String, IEnumerable<byte>, IEnumerable<char>, IEnumerable<int>
UnicodeString str = new UnicodeString("European castle \uD83C\uDFF0");
UnicodeString str8 = new UnicodeString(new byte[] { 69, 117, 114, 111, 112, 101, 97, 110, 32, 99, 97, 115, 116, 108, 101, 32, 240, 159, 143, 176 });
UnicodeString str16 = new UnicodeString(new char[] { 'E', 'u', 'r', 'o', 'p', 'e', 'a', 'n', ' ', 'c', 'a', 's', 't', 'l', 'e', ' ', '\uD83C', '\uDFF0' });
UnicodeString str32 = new UnicodeString(new int[] { 69, 117, 114, 111, 112, 101, 97, 110, 32, 99, 97, 115, 116, 108, 101, 32, 127984 });

Uniform use

Regardless of what source object is, as long as the encoding describes same unicode codepoints, UnicodeString describes the same uniform content.

Console.WriteLine($"Src={str8.Source.GetType().Name},  Str=\"{str8}\", Length={str8.Length}, Hashcode={str8.GetHashCode()}");
Console.WriteLine($"Src={str16.Source.GetType().Name},  Str=\"{str16}\", Length={str16.Length}, Hashcode={str16.GetHashCode()}");
Console.WriteLine($"Src={str32.Source.GetType().Name}, Str=\"{str32}\", Length={str32.Length}, Hashcode={str32.GetHashCode()}");

Encoding

Stack allocated IEnumerables and IEnumerators to UTF8, UTF16 and UTF32 encodings can be used.

// Encode to utf-8, utf-16, utf-32 codepoints
foreach (byte codepoint in str) { }
foreach (char codepoint in str) { }
foreach (int codepoint in str) { }

// Get stack allocated enumerator encoders
for (UTF8Enumerator enumr = str8.GetEnumeratorUTF8(); enumr.MoveNext();) { }
for (UTF16Enumerator enumr = str8.GetEnumeratorUTF16(); enumr.MoveNext();) { }
for (UTF32Enumerator enumr = str8.GetEnumerator(); enumr.MoveNext();) { }

// Length to different encodings can be calculated
int utf8length = str8.UTF8Length;
int utf16length = str8.UTF16Length;
int utf32length = str8.Length;

And converted to arrays of different encodings.

// Convert to utf 8/16/32 codepoints
Console.WriteLine($"Utf8 [ {String.Join(", ", str.ToUtf8Array())} ]");
Console.WriteLine($"Utf16 [ {String.Join(", ", str.ToUtf16Array())} ]");
Console.WriteLine($"Utf32 [ {String.Join(", ", str.ToArray())} ]");

Hash-Equals

UnicodeStrings can be compared for unicode equality.

// Compare for unicode equality and hashcode
var equals1 = str8.Equals(str32);
var equals2 = str16.Equals(str8);

var hashcode_equal1 = str8.GetHashCode() == str16.GetHashCode();
var hashcode_equal2 = str16.GetHashCode() == str8.GetHashCode();

Assign to IList

UnicodeString can be assigned to

  • IEnumerable<byte>, IList<byte>
  • IEnumerable<char>, IList<char>
  • IEnumerable<int>, IList<int>
// Assign UTF8 to ILists of various encodings
IList<byte> utf8_to_utf8 = str8;
IList<char> utf8_to_utf16 = str8;
IList<int> utf8_to_utf32 = str8;

// Assign UTF16 to ILists of various encodings
IList<byte> utf16_to_utf8 = str16;
IList<char> utf16_to_utf16 = str16;
IList<int> utf16_to_utf32 = str16;

// Assign UTF32 to ILists of various encodings
IList<byte> utf32_to_utf8 = str32;
IList<char> utf32_to_utf16 = str32;
IList<int> utf32_to_utf32 = str32;

File Scanner

FileScanner is a tool that scans directories recursively searching for files. It uses concurrent threads.

FileScanner fileScanner = new FileScanner();

It needs to be populated with filters, such as wildcard pattern with .AddFilename(string).

fileScanner.AddFilename("*.zip");

Or regular expressions.

fileScanner.AddRegex(".", new Regex(@".*\.zip"));

Or glob pattern.

fileScanner.AddGlobPattern(".", "**.zip");

Search is started when IEnumerator<string> is taken from the scanner.

foreach (string filepath in fileScanner)
{
    Console.WriteLine(filepath);
}

Exceptions that occur at real-time can be captured into concurrent collection.

fileScanner.errors = new ConcurrentBag<Exception>();

Glob Pattern

Glob pattern is a file matching pattern, an alternatite to wildcard pattern.

Glob pattern uses the following notation:

  • "*" matches to string of characters within the same directory.
  • "?" matches to any character except directory separator.
  • "**" matches to any characters, including directory separators.
Regex globPattern = new GlobPattern("**/*.dll/**.resources");

Test matching. "somefile.zip/" is excluded because of the separator in the pattern.

string[] files = new[]
{
    "somefile.zip",
    "somefile.zip/somefile.ext",
    "somefile.zip/somefile.ext/someresource",
    "somefile.zip/somelib.dll",
    "somefile.zip/somelib.dll/someresource.resources",
    "somelib.dll",
    "somelib.dll/someresource.resources",
};

foreach (string filename in files.Where(fn => globPattern.IsMatch(fn)))
    Console.WriteLine(filename);

The result.

somefile.zip/somelib.dll/someresource.resources
Back to top Copyright © 2015-2020 Toni Kalajainen