public static unsafe ImmutableDictionary <TKey, TValue> Add <TFrom, TTo, TValueNodes>( TFrom @from, TKey key, TValue value, uint hash, uint index, uint indexValues, int shift, ulong bitmapNodes, ulong bitmapValues, TValueNodes values) where TFrom : struct, IBranchNodes <TKey, TValue> where TTo : struct, IBranchNodes <TKey, TValue> where TValueNodes : struct, IValueNodes <TKey, TValue> { var to = default(TTo); var ptrFrom = Unsafe.AsPointer(ref @from); var ptrTo = Unsafe.AsPointer(ref to); Unsafe.CopyBlock(ptrTo, ptrFrom, (uint)(index * IntPtr.Size)); var key2 = values.GetKey(indexValues); var value2 = values.GetValue(indexValues); var newNode = BitMapNode <TKey, TValue, TValueNodes, TFrom> .From(key, value, hash, shift + ImmutableDictionary.Shift, key2, value2); Unsafe.Write((byte *)ptrTo + (uint)(index * IntPtr.Size), newNode); Unsafe.CopyBlock( (byte *)ptrTo + (uint)((index + 1) * IntPtr.Size), (byte *)ptrFrom + (uint)((index) * IntPtr.Size), (uint)(Unsafe.SizeOf <TFrom>() - index * IntPtr.Size)); for (int i = 0; i < Unsafe.SizeOf <TTo>(); i += IntPtr.Size) { Debug.Assert(Unsafe.AsRef <ImmutableDictionary <TKey, TValue> >((byte *)ptrTo + i) != null); } return(values.Shrink(bitmapNodes, to, bitmapValues, (uint)indexValues)); }
internal static ImmutableDictionary <TKey, TValue> From(TKey key, TValue value, uint hash, int shift, TKey key2, TValue value2) { if (hash == (uint)key2.GetHashCode() && key.Equals(key2)) { // TODO lift hash and key equlity (update) to above layer var newValues = new ValueNode1 <TKey, TValue>(key, value); return(new BitMapNode <TKey, TValue, ValueNode1 <TKey, TValue>, BranchNodes0 <TKey, TValue> >( 0, new BranchNodes0 <TKey, TValue>(), 1U << (int)((hash >> shift) & Mask), newValues)); } else if (hash == (uint)key2.GetHashCode()) { // TODO handle collisions, at what shift level? throw new NotImplementedException(); } else { var bit1 = 1U << (int)(((uint)key2.GetHashCode() >> shift) & Mask); var bit2 = 1U << (int)((hash >> shift) & Mask); if (bit1 < bit2) { var newValues = new ValueNode2 <TKey, TValue>(key2, value2, key, value); return(new BitMapNode <TKey, TValue, ValueNode2 <TKey, TValue>, BranchNodes0 <TKey, TValue> >( 0, new BranchNodes0 <TKey, TValue>(), bit1 | bit2, newValues)); } else if (bit1 > bit2) { var newValues = new ValueNode2 <TKey, TValue>(key, value, key2, value2); return(new BitMapNode <TKey, TValue, ValueNode2 <TKey, TValue>, BranchNodes0 <TKey, TValue> >( 0, new BranchNodes0 <TKey, TValue>(), bit1 | bit2, newValues)); } else { var newNodes = BitMapNode <TKey, TValue, TValueNodes, TBranchNodes> .From(key, value, hash, shift + Shift, key2, value2); return(new BitMapNode <TKey, TValue, ValueNode0 <TKey, TValue>, BranchNodes1 <TKey, TValue> >(bit1, new BranchNodes1 <TKey, TValue>(newNodes), 0, new ValueNode0 <TKey, TValue>())); } } }