Ejemplo n.º 1
0
        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>()));
                }
            }
        }