Skip to content

Commit

Permalink
wip: tree234 for #32
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Jun 11, 2020
1 parent fffc2c5 commit e6d2d52
Showing 1 changed file with 183 additions and 5 deletions.
188 changes: 183 additions & 5 deletions src/ImTools/ImTools.Experimental.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,185 @@
using System.Runtime.CompilerServices;
using System.Threading;

namespace ImTools.Experimental.Tree234
{
/// <summary>Represents an empty map</summary>
public class ImMap<V>
{
/// <summary>Empty tree to start with.</summary>
public static readonly ImMap<V> Empty = new ImMap<V>();
protected ImMap() { }
}

/// <summary>Wraps the stored data with "fixed" reference semantics -
/// when added to the tree it won't be changed or reconstructed in memory</summary>
public sealed class ImMapEntry<V> : ImMap<V>
{
/// <summary>The Key is basically the hash, or the Height for ImMapTree</summary>
public readonly int Key;

/// <summary>The value - may be modified if you need a Ref{V} semantics</summary>
public V Value;

/// <summary>Constructs the entry with the default value</summary>
public ImMapEntry(int key) => Key = key;

/// <summary>Constructs the entry with the key and value</summary>
public ImMapEntry(int key, V value)
{
Key = key;
Value = value;
}

/// Prints the key value pair
public override string ToString() => Key + ":" + Value;
}

/// <summary></summary>
public class ImMapLeafs2<V> : ImMap<V>
{
/// <summary>Left entry</summary>
public readonly ImMapEntry<V> Entry0;

/// <summary>Right entry</summary>
public readonly ImMapEntry<V> Entry1;

public ImMapLeafs2(ImMapEntry<V> entry0, ImMapEntry<V> entry1)
{
Entry0 = entry0;
Entry1 = entry1;
}
}

public sealed class ImMapLeafs3<V> : ImMapLeafs2<V>
{
/// <summary></summary>
public readonly ImMapEntry<V> Entry2;

public ImMapLeafs3(ImMapEntry<V> entry0, ImMapEntry<V> entry1, ImMapEntry<V> entry2)
: base(entry0, entry1)
{
Entry2 = entry2;
}
}

public class ImMapBranch2<V> : ImMap<V>
{
public readonly ImMapEntry<V> Entry0;

/// <summary></summary>
public readonly ImMap<V> Branch0; // can be Branchs | Entry | Leaf2 | Leaf3, if it is an Entry then other Tree cannot be an Entry

/// <summary></summary>
public readonly ImMap<V> Branch1;

public ImMapBranch2(ImMapEntry<V> entry0, ImMap<V> branch0, ImMap<V> branch1)
{
Entry0 = entry0;
Branch0 = branch0;
Branch1 = branch1;
}
}

public class ImMapBranch3<V> : ImMapBranch2<V>
{
public readonly ImMapEntry<V> Entry1;

/// <summary></summary>
public readonly ImMap<V> Branch2;

public ImMapBranch3(ImMapEntry<V> entry0, ImMap<V> branch0, ImMap<V> branch1,
ImMapEntry<V> entry1, ImMap<V> branch2) : base(entry0, branch0, branch1)
{
Entry1 = entry1;
Branch2 = branch2;
}
}

/// <summary>ImMap methods</summary>
public static class ImMap
{
/// <summary> Adds or updates the value by key in the map, always returns a modified map </summary>
public static ImMap<V> AddOrUpdateEntry<V>(this ImMap<V> map, ImMapEntry<V> entry)
{
if (map == ImMap<V>.Empty)
return entry;

var key = entry.Key;
if (map is ImMapEntry<V> leaf)
return key > leaf.Key ? new ImMapLeafs2<V>(leaf, entry)
: key < leaf.Key ? new ImMapLeafs2<V>(entry, leaf)
: (ImMap<V>)entry;

if (map is ImMapLeafs2<V> leaf2)
return key > leaf2.Entry1.Key ? new ImMapLeafs3<V>(leaf2.Entry0, leaf2.Entry1, entry)
: key < leaf2.Entry0.Key ? new ImMapLeafs3<V>(entry, leaf2.Entry0, leaf2.Entry1)
: key > leaf2.Entry0.Key && key < leaf2.Entry1.Key ? new ImMapLeafs3<V>(leaf2.Entry0, entry, leaf2.Entry1)
: (ImMap<V>)entry;

// we need to split
if (map is ImMapLeafs3<V> leaf3)
{
// [1 3 5] and we are adding 7
// =>
// [3]
// [1] [5, 7]

if (key > leaf3.Entry2.Key)
return new ImMapBranch2<V>(leaf3.Entry1,
leaf3.Entry0, new ImMapLeafs2<V>(leaf3.Entry2, entry));

if (key < leaf3.Entry0.Key)
return new ImMapBranch2<V>(leaf3.Entry1,
new ImMapLeafs2<V>(entry, leaf3.Entry0), leaf3.Entry2);

if (key < leaf3.Entry2.Key && key > leaf3.Entry1.Key)
return new ImMapBranch2<V>(leaf3.Entry1,
leaf3.Entry0, new ImMapLeafs2<V>(entry, leaf3.Entry2));

if (key > leaf3.Entry0.Key && key < leaf3.Entry1.Key)
return new ImMapBranch2<V>(leaf3.Entry1,
new ImMapLeafs2<V>(leaf3.Entry0, entry), leaf3.Entry2);

return entry;
}

// todo: @incomplete add to branches
return map;

// if (map is ImMapBranch<V> branch)
// {
// if (key > branch.Entry.Key)
// // 5 10
// // 10 => 5 11
// // 11
// return key > branch.RightEntry.Key
// ? new ImMapTree<V>(branch.RightEntry, branch.Entry, entry)
// // 5 7
// // 10 => 5 10
// // 7
// : key < branch.RightEntry.Key // rotate if right
// ? new ImMapTree<V>(entry, branch.Entry, branch.RightEntry)
// : (ImMap<V>)new ImMapBranch<V>(branch.Entry, entry);

// return key < branch.Entry.Key
// ? new ImMapTree<V>(branch.Entry, entry, branch.RightEntry)
// : (ImMap<V>)new ImMapBranch<V>(entry, branch.RightEntry);
// }

// var tree = (ImMapTree<V>)map;
// return key == tree.Entry.Key
// ? new ImMapTree<V>(entry, tree.Left, tree.Right, tree.TreeHeight)
// : tree.AddOrUpdateLeftOrRight(key, entry);
}

/// <summary> Adds or updates the value by key in the map, always returns a modified map </summary>
[MethodImpl((MethodImplOptions) 256)]
public static ImMap<V> AddOrUpdate<V>(this ImMap<V> map, int key, V value) =>
map.AddOrUpdateEntry(new ImMapEntry<V>(key, value));
}
}

namespace ImTools.Experimental
{
/// <summary>
Expand All @@ -13,8 +192,6 @@ public class ImMap<V>
{
/// <summary>Empty tree to start with.</summary>
public static readonly ImMap<V> Empty = new ImMap<V>();

/// Prevents multiple creation of an empty tree
protected ImMap() { }

/// <summary>Height of the longest sub-tree/branch - 0 for the empty tree</summary>
Expand All @@ -24,7 +201,8 @@ protected ImMap() { }
public override string ToString() => "empty";
}

/// <summary>Wraps the stored data with "fixed" reference semantics - when added to the tree it did not change or reconstructed in memory</summary>
/// <summary>Wraps the stored data with "fixed" reference semantics -
/// when added to the tree it won't be changed or reconstructed in memory</summary>
public sealed class ImMapEntry<V> : ImMap<V>
{
/// <inheritdoc />
Expand Down Expand Up @@ -61,7 +239,7 @@ public sealed class ImMapBranch<V> : ImMap<V>
/// Contains the once created data node
public readonly ImMapEntry<V> Entry;

/// Left sub-tree/branch, or empty.
/// Right sub-tree/branch, or empty.
public ImMapEntry<V> RightEntry;

/// Constructor
Expand Down Expand Up @@ -99,7 +277,7 @@ public sealed class ImMapTree<V> : ImMap<V>
/// Left sub-tree/branch, or empty.
public ImMap<V> Left;

/// Right sub-tree/branch, or empty.md
/// Right sub-tree/branch, or empty
public ImMap<V> Right;

internal ImMapTree(ImMapEntry<V> entry, ImMap<V> left, ImMap<V> right, int height)
Expand Down

0 comments on commit e6d2d52

Please sign in to comment.