/// <summary>
        /// Updates with the given value.
        /// </summary>
        /// <param name="x"> the value </param>
        public virtual void Accumulate(double x)
        {
            Cell[] @as;
            long   b, v, r;
            int    m;
            Cell   a;

            if ((@as = Cells) != null || (r = Double.doubleToRawLongBits(Function.ApplyAsDouble(Double.longBitsToDouble(b = @base), x))) != b && !CasBase(b, r))
            {
                bool uncontended = true;
                if (@as == null || (m = @as.Length - 1) < 0 || (a = @as[Probe & m]) == null || !(uncontended = (r = Double.doubleToRawLongBits(Function.ApplyAsDouble(Double.longBitsToDouble(v = a.Value), x))) == v || a.Cas(v, r)))
                {
                    DoubleAccumulate(x, Function, uncontended);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Same as longAccumulate, but injecting long/double conversions
        /// in too many places to sensibly merge with long version, given
        /// the low-overhead requirements of this class. So must instead be
        /// maintained by copy/paste/adapt.
        /// </summary>
        internal void DoubleAccumulate(double x, DoubleBinaryOperator fn, bool wasUncontended)
        {
            int h;

            if ((h = Probe) == 0)
            {
                ThreadLocalRandom.Current();                 // force initialization
                h = Probe;
                wasUncontended = true;
            }
            bool collide = false;             // True if last slot nonempty

            for (;;)
            {
                Cell[] @as;
                Cell   a;
                int    n;
                long   v;
                if ((@as = Cells) != null && (n = @as.Length) > 0)
                {
                    if ((a = @as[(n - 1) & h]) == null)
                    {
                        if (CellsBusy == 0)                         // Try to attach new Cell
                        {
                            Cell r = new Cell(Double.doubleToRawLongBits(x));
                            if (CellsBusy == 0 && CasCellsBusy())
                            {
                                bool created = false;
                                try                                 // Recheck under lock
                                {
                                    Cell[] rs;
                                    int    m, j;
                                    if ((rs = Cells) != null && (m = rs.Length) > 0 && rs[j = (m - 1) & h] == null)
                                    {
                                        rs[j]   = r;
                                        created = true;
                                    }
                                }
                                finally
                                {
                                    CellsBusy = 0;
                                }
                                if (created)
                                {
                                    break;
                                }
                                continue;                                 // Slot is now non-empty
                            }
                        }
                        collide = false;
                    }
                    else if (!wasUncontended)                     // CAS already known to fail
                    {
                        wasUncontended = true;                    // Continue after rehash
                    }
                    else if (a.Cas(v = a.Value, ((fn == null) ? Double.doubleToRawLongBits(Double.longBitsToDouble(v) + x) : Double.doubleToRawLongBits(fn.ApplyAsDouble(Double.longBitsToDouble(v), x)))))
                    {
                        break;
                    }
                    else if (n >= NCPU || Cells != @as)
                    {
                        collide = false;                         // At max size or stale
                    }
                    else if (!collide)
                    {
                        collide = true;
                    }
                    else if (CellsBusy == 0 && CasCellsBusy())
                    {
                        try
                        {
                            if (Cells == @as)                             // Expand table unless stale
                            {
                                Cell[] rs = new Cell[n << 1];
                                for (int i = 0; i < n; ++i)
                                {
                                    rs[i] = @as[i];
                                }
                                Cells = rs;
                            }
                        }
                        finally
                        {
                            CellsBusy = 0;
                        }
                        collide = false;
                        continue;                         // Retry with expanded table
                    }
                    h = AdvanceProbe(h);
                }
                else if (CellsBusy == 0 && Cells == @as && CasCellsBusy())
                {
                    bool init = false;
                    try                     // Initialize table
                    {
                        if (Cells == @as)
                        {
                            Cell[] rs = new Cell[2];
                            rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
                            Cells     = rs;
                            init      = true;
                        }
                    }
                    finally
                    {
                        CellsBusy = 0;
                    }
                    if (init)
                    {
                        break;
                    }
                }
                else if (CasBase(v = @base, ((fn == null) ? Double.doubleToRawLongBits(Double.longBitsToDouble(v) + x) : Double.doubleToRawLongBits(fn.ApplyAsDouble(Double.longBitsToDouble(v), x)))))
                {
                    break;                     // Fall back on using base
                }
            }
        }