public CellCacheEntry[] GetCacheEntries()
        {

            FormulaCellCacheEntry[] result = new FormulaCellCacheEntry[_formulaEntriesByCell.Count];
            _formulaEntriesByCell.Values.CopyTo(result,0);
            return result;
        }
Beispiel #2
0
        public void NotifyDeleteCell(int bookIndex, int sheetIndex, IEvaluationCell cell)
        {
            if (cell.CellType == NPOI.SS.UserModel.CellType.Formula)
            {
                FormulaCellCacheEntry fcce = _formulaCellCache.Remove(cell);
                if (fcce == null)
                {
                    // formula cell Has not been evaluated yet
                }
                else
                {
                    fcce.SetSensitiveInputCells(null);
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                }
            }
            else
            {
                Loc loc = new Loc(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
                PlainValueCellCacheEntry pcce = _plainCellCache.Get(loc);

                if (pcce == null)
                {
                    // cache entry doesn't exist. nothing To do
                }
                else
                {
                    pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                }
            }
        }
Beispiel #3
0
 public void ClearConsumingCell(FormulaCellCacheEntry cce)
 {
     if (!_consumingCells.Remove(cce))
     {
         throw new InvalidOperationException("Specified formula cell is not consumed by this cell");
     }
 }
Beispiel #4
0
        public FormulaCellCacheEntry[] ToArray()
        {
            int nItems = _size;

            if (nItems < 1)
            {
                return(FormulaCellCacheEntry.EMPTY_ARRAY);
            }
            FormulaCellCacheEntry[] result = new FormulaCellCacheEntry[nItems];
            int j = 0;

            for (int i = 0; i < _arr.Length; i++)
            {
                FormulaCellCacheEntry cce = _arr[i];
                if (cce != null)
                {
                    result[j++] = cce;
                }
            }
            if (j != nItems)
            {
                throw new InvalidOperationException("size mismatch");
            }
            return(result);
        }
Beispiel #5
0
 public void ClearConsumingCell(FormulaCellCacheEntry cce)
 {
     if (!_consumingCells.Remove(cce))
     {
         throw new InvalidOperationException("Specified formula cell is not consumed by this cell");
     }
 }
Beispiel #6
0
        public FormulaCellCacheEntry Remove(IEvaluationCell cell)
        {
            FormulaCellCacheEntry tmp = (FormulaCellCacheEntry)_formulaEntriesByCell[cell.IdentityKey];

            _formulaEntriesByCell.Remove(cell);
            return(tmp);
        }
Beispiel #7
0
        public bool Remove(CellCacheEntry cce)
        {
            FormulaCellCacheEntry[] arr = _arr;

            if (_size * 3 < _arr.Length && _arr.Length > 8)
            {
                // re-Hash
                bool found = false;
                FormulaCellCacheEntry[] prevArr = _arr;
                FormulaCellCacheEntry[] newArr  = new FormulaCellCacheEntry[_arr.Length / 2]; // shrink 50%
                for (int i = 0; i < prevArr.Length; i++)
                {
                    FormulaCellCacheEntry prevCce = _arr[i];
                    if (prevCce != null)
                    {
                        if (prevCce == cce)
                        {
                            found = true;
                            _size--;
                            // skip it
                            continue;
                        }
                        AddInternal(newArr, prevCce);
                    }
                }
                _arr = newArr;
                return(found);
            }
            // else - usual case
            // delete single element (without re-Hashing)

            int startIx = cce.GetHashCode() % arr.Length;

            // note - can't exit loops upon finding null because of potential previous deletes
            for (int i = startIx; i < arr.Length; i++)
            {
                FormulaCellCacheEntry item = arr[i];
                if (item == cce)
                {
                    // found it
                    arr[i] = null;
                    _size--;
                    return(true);
                }
            }
            for (int i = 0; i < startIx; i++)
            {
                FormulaCellCacheEntry item = arr[i];
                if (item == cce)
                {
                    // found it
                    arr[i] = null;
                    _size--;
                    return(true);
                }
            }
            return(false);
        }
Beispiel #8
0
        public FormulaCellCacheEntry GetOrCreateFormulaCellEntry(IEvaluationCell cell)
        {
            FormulaCellCacheEntry result = _formulaCellCache.Get(cell);

            if (result == null)
            {
                result = new FormulaCellCacheEntry();
                _formulaCellCache.Put(cell, result);
            }
            return(result);
        }
Beispiel #9
0
        /**
         * Calls formulaCell.SetFormulaResult(null, null) recursively all the way up the tree of
         * dependencies. Calls usedCell.ClearConsumingCell(fc) for each child of a cell that Is
         * Cleared along the way.
         * @param formulaCells
         */
        protected void RecurseClearCachedFormulaResults()
        {
            FormulaCellCacheEntry[] formulaCells = GetConsumingCells();

            for (int i = 0; i < formulaCells.Length; i++)
            {
                FormulaCellCacheEntry fc = formulaCells[i];
                fc.ClearFormulaEntry();
                fc.RecurseClearCachedFormulaResults();
            }
        }
Beispiel #10
0
        public FormulaCellCacheEntry GetOrCreateFormulaCellEntry(EvaluationCell cell)
        {
            FormulaCellCacheEntry result = _formulaCellCache.Get(cell);
            if (result == null)
            {

                result = new FormulaCellCacheEntry();
                _formulaCellCache.Put(cell, result);
            }
            return result;
        }
        public void TestBasicCellCacheEntry()
        {
            CellCacheEntry pcce = new PlainValueCellCacheEntry(new NumberEval(42.0));
            ValueEval ve = pcce.GetValue();
            Assert.AreEqual(42, ((NumberEval)ve).NumberValue, 0.0);

            FormulaCellCacheEntry fcce = new FormulaCellCacheEntry();
            fcce.UpdateFormulaResult(new NumberEval(10.0), CellCacheEntry.EMPTY_ARRAY, null);

            ve = fcce.GetValue();
            Assert.AreEqual(10, ((NumberEval)ve).NumberValue, 0.0);
        }
Beispiel #12
0
        /**
         * Identical To {@link #RecurseClearCachedFormulaResults()} except for the listener call-backs
         */
        protected void RecurseClearCachedFormulaResults(IEvaluationListener listener, int depth)
        {
            FormulaCellCacheEntry[] formulaCells = GetConsumingCells();

            listener.SortDependentCachedValues(formulaCells);
            for (int i = 0; i < formulaCells.Length; i++)
            {
                FormulaCellCacheEntry fc = formulaCells[i];
                listener.OnClearDependentCachedValue(fc, depth);
                fc.ClearFormulaEntry();
                fc.RecurseClearCachedFormulaResults(listener, depth + 1);
            }
        }
Beispiel #13
0
 /**
  * Notifies this evaluation tracker that evaluation of the specified cell Is
  * about To start.<br/>
  *
  * In the case of a <c>true</c> return code, the caller should
  * continue evaluation of the specified cell, and also be sure To call
  * <c>endEvaluate()</c> when complete.<br/>
  *
  * In the case of a <c>null</c> return code, the caller should
  * return an evaluation result of
  * <c>ErrorEval.CIRCULAR_REF_ERROR</c>, and not call <c>endEvaluate()</c>.
  * <br/>
  * @return <c>false</c> if the specified cell is already being evaluated
  */
 public bool StartEvaluate(FormulaCellCacheEntry cce)
 {
     if (cce == null)
     {
         throw new ArgumentException("cellLoc must not be null");
     }
     if (_currentlyEvaluatingCells.Contains(cce))
     {
         return(false);
     }
     _currentlyEvaluatingCells.Add(cce);
     _evaluationFrames.Add(new CellEvaluationFrame(cce));
     return(true);
 }
 /**
  * Notifies this evaluation tracker that evaluation of the specified cell Is
  * about To start.<br/>
  *
  * In the case of a <c>true</c> return code, the caller should
  * continue evaluation of the specified cell, and also be sure To call
  * <tt>endEvaluate()</tt> when complete.<br/>
  *
  * In the case of a <c>null</c> return code, the caller should
  * return an evaluation result of
  * <tt>ErrorEval.CIRCULAR_REF_ERROR<tt>, and not call <tt>endEvaluate()</tt>.
  * <br/>
  * @return <c>false</c> if the specified cell is already being evaluated
  */
 public bool StartEvaluate(FormulaCellCacheEntry cce)
 {
     if (cce == null)
     {
         throw new ArgumentException("cellLoc must not be null");
     }
     if (_currentlyEvaluatingCells.Contains(cce))
     {
         return false;
     }
     _currentlyEvaluatingCells.Add(cce);
     _evaluationFrames.Add(new CellEvaluationFrame(cce));
     return true;
 }
Beispiel #15
0
 public void Add(CellCacheEntry cce)
 {
     if (_size * 3 >= _arr.Length * 2)
     {
         // re-Hash
         FormulaCellCacheEntry[] prevArr = _arr;
         FormulaCellCacheEntry[] newArr  = new FormulaCellCacheEntry[4 + _arr.Length * 3 / 2]; // grow 50%
         for (int i = 0; i < prevArr.Length; i++)
         {
             FormulaCellCacheEntry prevCce = _arr[i];
             if (prevCce != null)
             {
                 AddInternal(newArr, prevCce);
             }
         }
         _arr = newArr;
     }
     if (AddInternal(_arr, cce))
     {
         _size++;
     }
 }
 public void Add(CellCacheEntry cce)
 {
     if (_size * 3 >= _arr.Length * 2)
     {
         // re-Hash
         FormulaCellCacheEntry[] prevArr = _arr;
         FormulaCellCacheEntry[] newArr = new FormulaCellCacheEntry[4 + _arr.Length * 3 / 2]; // grow 50%
         for (int i = 0; i < prevArr.Length; i++)
         {
             FormulaCellCacheEntry prevCce = _arr[i];
             if (prevCce != null)
             {
                 AddInternal(newArr, prevCce);
             }
         }
         _arr = newArr;
     }
     if (AddInternal(_arr, cce))
     {
         _size++;
     }
 }
 public FormulaCellCacheEntry[] ToArray()
 {
     int nItems = _size;
     if (nItems < 1)
     {
         return FormulaCellCacheEntry.EMPTY_ARRAY;
     }
     FormulaCellCacheEntry[] result = new FormulaCellCacheEntry[nItems];
     int j = 0;
     for (int i = 0; i < _arr.Length; i++)
     {
         FormulaCellCacheEntry cce = _arr[i];
         if (cce != null)
         {
             result[j++] = cce;
         }
     }
     if (j != nItems)
     {
         throw new InvalidOperationException("size mismatch");
     }
     return result;
 }
Beispiel #18
0
 public void ProcessEntry(FormulaCellCacheEntry entry)
 {
     entry.NotifyUpdatedBlankCell(bsk, rowIndex, columnIndex, evaluationListener);
 }
 public void Put(EvaluationCell cell, FormulaCellCacheEntry entry)
 {
     _formulaEntriesByCell[cell] = entry;
 }
Beispiel #20
0
 public CellEvaluationFrame(FormulaCellCacheEntry cce)
 {
     _cce = cce;
     _sensitiveInputCells = new ArrayList();
 }
Beispiel #21
0
 public void Put(IEvaluationCell cell, FormulaCellCacheEntry entry)
 {
     _formulaEntriesByCell[cell.IdentityKey] = entry;
 }
        public void AddConsumingCell(FormulaCellCacheEntry cellLoc)
        {
            _consumingCells.Add(cellLoc);

        }
Beispiel #23
0
        /**
         * @return never <c>null</c>, never {@link BlankEval}
         */
        private ValueEval EvaluateAny(IEvaluationCell srcCell, int sheetIndex,
                                      int rowIndex, int columnIndex, EvaluationTracker tracker)
        {
            bool shouldCellDependencyBeRecorded = _stabilityClassifier == null ? true
                    : !_stabilityClassifier.IsCellFinal(sheetIndex, rowIndex, columnIndex);
            ValueEval result;

            if (srcCell == null || srcCell.CellType != CellType.FORMULA)
            {
                result = GetValueFromNonFormulaCell(srcCell);
                if (shouldCellDependencyBeRecorded)
                {
                    tracker.AcceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
                }
                return(result);
            }

            FormulaCellCacheEntry cce = _cache.GetOrCreateFormulaCellEntry(srcCell);

            if (shouldCellDependencyBeRecorded || cce.IsInputSensitive)
            {
                tracker.AcceptFormulaDependency(cce);
            }
            IEvaluationListener evalListener = _evaluationListener;

            if (cce.GetValue() == null)
            {
                if (!tracker.StartEvaluate(cce))
                {
                    return(ErrorEval.CIRCULAR_REF_ERROR);
                }
                OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);

                try
                {
                    Ptg[] ptgs = _workbook.GetFormulaTokens(srcCell);
                    if (evalListener == null)
                    {
                        result = EvaluateFormula(ec, ptgs);
                    }
                    else
                    {
                        evalListener.OnStartEvaluate(srcCell, cce);
                        result = EvaluateFormula(ec, ptgs);
                        evalListener.OnEndEvaluate(cce, result);
                    }

                    tracker.UpdateCacheResult(result);
                }
                catch (NotImplementedException e)
                {
                    throw AddExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
                }
                finally
                {
                    tracker.EndEvaluate(cce);
                }
            }
            else
            {
                if (evalListener != null)
                {
                    evalListener.OnCacheHit(sheetIndex, rowIndex, columnIndex, cce.GetValue());
                }
                return(cce.GetValue());
            }
            if (IsDebugLogEnabled())
            {
                String        sheetName = GetSheetName(sheetIndex);
                CellReference cr        = new CellReference(rowIndex, columnIndex);
                LogDebug("Evaluated " + sheetName + "!" + cr.FormatAsString() + " To " + cce.GetValue().ToString());
            }
            // Usually (result === cce.getValue())
            // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
            // When circular references are detected, the cache entry is only updated for
            // the top evaluation frame
            //return cce.GetValue();
            return(result);
        }
Beispiel #24
0
 public void ProcessEntry(FormulaCellCacheEntry entry)
 {
     entry.NotifyUpdatedBlankCell(bsk, rowIndex, columnIndex, evaluationListener);
 }
        public bool Remove(CellCacheEntry cce)
        {
            FormulaCellCacheEntry[] arr = _arr;

            if (_size * 3 < _arr.Length && _arr.Length > 8)
            {
                // re-Hash
                bool found = false;
                FormulaCellCacheEntry[] prevArr = _arr;
                FormulaCellCacheEntry[] newArr = new FormulaCellCacheEntry[_arr.Length / 2]; // shrink 50%
                for (int i = 0; i < prevArr.Length; i++)
                {
                    FormulaCellCacheEntry prevCce = _arr[i];
                    if (prevCce != null)
                    {
                        if (prevCce == cce)
                        {
                            found = true;
                            _size--;
                            // skip it
                            continue;
                        }
                        AddInternal(newArr, prevCce);
                    }
                }
                _arr = newArr;
                return found;
            }
            // else - usual case
            // delete single element (without re-Hashing)

            int startIx = cce.GetHashCode() % arr.Length;

            // note - can't exit loops upon finding null because of potential previous deletes
            for (int i = startIx; i < arr.Length; i++)
            {
                FormulaCellCacheEntry item = arr[i];
                if (item == cce)
                {
                    // found it
                    arr[i] = null;
                    _size--;
                    return true;
                }
            }
            for (int i = 0; i < startIx; i++)
            {
                FormulaCellCacheEntry item = arr[i];
                if (item == cce)
                {
                    // found it
                    arr[i] = null;
                    _size--;
                    return true;
                }
            }
            return false;
        }
Beispiel #26
0
        public void NotifyUpdateCell(int bookIndex, int sheetIndex, IEvaluationCell cell)
        {
            FormulaCellCacheEntry fcce = _formulaCellCache.Get(cell);

            int rowIndex    = cell.RowIndex;
            int columnIndex = cell.ColumnIndex;
            Loc loc         = new Loc(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
            PlainValueCellCacheEntry pcce = _plainCellCache.Get(loc);

            if (cell.CellType == NPOI.SS.UserModel.CellType.Formula)
            {
                if (fcce == null)
                {
                    fcce = new FormulaCellCacheEntry();

                    if (pcce == null)
                    {
                        if (_evaluationListener != null)
                        {
                            _evaluationListener.OnChangeFromBlankValue(sheetIndex, rowIndex,
                                                                       columnIndex, cell, fcce);
                        }
                        UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, rowIndex, columnIndex);
                    }
                    _formulaCellCache.Put(cell, fcce);
                }
                else
                {
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    fcce.ClearFormulaEntry();
                }
                if (pcce == null)
                {
                    // was formula cell before - no Change of type
                }
                else
                {
                    // changing from plain cell To formula cell
                    pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    _plainCellCache.Remove(loc);
                }
            }
            else
            {
                ValueEval value = WorkbookEvaluator.GetValueFromNonFormulaCell(cell);
                if (pcce == null)
                {
                    if (value != BlankEval.instance)
                    {
                        pcce = new PlainValueCellCacheEntry(value);
                        if (fcce == null)
                        {
                            if (_evaluationListener != null)
                            {
                                _evaluationListener.OnChangeFromBlankValue(sheetIndex, rowIndex,
                                                                           columnIndex, cell, pcce);
                            }
                            UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, rowIndex, columnIndex);
                        }
                        _plainCellCache.Put(loc, pcce);
                    }
                }
                else
                {
                    if (pcce.UpdateValue(value))
                    {
                        pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    }
                    if (value == BlankEval.instance)
                    {
                        _plainCellCache.Remove(loc);
                    }
                }
                if (fcce == null)
                {
                    // was plain cell before - no Change of type
                }
                else
                {
                    // was formula cell before - now a plain value
                    _formulaCellCache.Remove(cell);
                    fcce.SetSensitiveInputCells(null);
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                }
            }
        }
Beispiel #27
0
 public void Put(EvaluationCell cell, FormulaCellCacheEntry entry)
 {
     _formulaEntriesByCell[cell] = entry;
 }
Beispiel #28
0
        /**
         * @return never <c>null</c>, never {@link BlankEval}
         */
        private ValueEval EvaluateAny(IEvaluationCell srcCell, int sheetIndex,
                                      int rowIndex, int columnIndex, EvaluationTracker tracker)
        {
            bool shouldCellDependencyBeRecorded = _stabilityClassifier == null ? true
                    : !_stabilityClassifier.IsCellFinal(sheetIndex, rowIndex, columnIndex);
            ValueEval result;

            if (srcCell == null || srcCell.CellType != CellType.FORMULA)
            {
                result = GetValueFromNonFormulaCell(srcCell);
                if (shouldCellDependencyBeRecorded)
                {
                    tracker.AcceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
                }
                return(result);
            }

            FormulaCellCacheEntry cce = _cache.GetOrCreateFormulaCellEntry(srcCell);

            if (shouldCellDependencyBeRecorded || cce.IsInputSensitive)
            {
                tracker.AcceptFormulaDependency(cce);
            }
            IEvaluationListener evalListener = _evaluationListener;

            if (cce.GetValue() == null)
            {
                if (!tracker.StartEvaluate(cce))
                {
                    return(ErrorEval.CIRCULAR_REF_ERROR);
                }
                OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);

                try
                {
                    Ptg[] ptgs = _workbook.GetFormulaTokens(srcCell);
                    if (evalListener == null)
                    {
                        result = EvaluateFormula(ec, ptgs);
                    }
                    else
                    {
                        evalListener.OnStartEvaluate(srcCell, cce);
                        result = EvaluateFormula(ec, ptgs);
                        evalListener.OnEndEvaluate(cce, result);
                    }

                    tracker.UpdateCacheResult(result);
                }
                catch (NotImplementedException e)
                {
                    throw AddExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
                }
                catch (RuntimeException re)
                {
                    if (re.InnerException is WorkbookNotFoundException && _ignoreMissingWorkbooks)
                    {
                        LogInfo(re.InnerException.Message + " - Continuing with cached value!");
                        switch (srcCell.CachedFormulaResultType)
                        {
                        case CellType.NUMERIC:
                            result = new NumberEval(srcCell.NumericCellValue);
                            break;

                        case CellType.STRING:
                            result = new StringEval(srcCell.StringCellValue);
                            break;

                        case CellType.BLANK:
                            result = BlankEval.instance;
                            break;

                        case CellType.BOOLEAN:
                            result = BoolEval.ValueOf(srcCell.BooleanCellValue);
                            break;

                        case CellType.ERROR:
                            result = ErrorEval.ValueOf(srcCell.ErrorCellValue);
                            break;

                        case CellType.FORMULA:
                        default:
                            throw new RuntimeException("Unexpected cell type '" + srcCell.CellType + "' found!");
                        }
                    }
                    else
                    {
                        throw re;
                    }
                }
                finally
                {
                    tracker.EndEvaluate(cce);
                }
            }
            else
            {
                if (evalListener != null)
                {
                    evalListener.OnCacheHit(sheetIndex, rowIndex, columnIndex, cce.GetValue());
                }
                return(cce.GetValue());
            }
            if (IsDebugLogEnabled())
            {
                String        sheetName = GetSheetName(sheetIndex);
                CellReference cr        = new CellReference(rowIndex, columnIndex);
                LogDebug("Evaluated " + sheetName + "!" + cr.FormatAsString() + " To " + cce.GetValue());
            }
            // Usually (result === cce.getValue())
            // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
            // When circular references are detected, the cache entry is only updated for
            // the top evaluation frame
            //return cce.GetValue();
            return(result);
        }
Beispiel #29
0
 public CellCacheEntry[] GetCacheEntries()
 {
     FormulaCellCacheEntry[] result = new FormulaCellCacheEntry[_formulaEntriesByCell.Count];
     _formulaEntriesByCell.Values.CopyTo(result, 0);
     return(result);
 }
 public CellEvaluationFrame(FormulaCellCacheEntry cce)
 {
     _cce = cce;
     _sensitiveInputCells = new ArrayList();
 }
Beispiel #31
0
 public void Put(IEvaluationCell cell, FormulaCellCacheEntry entry)
 {
     _formulaEntriesByCell[cell.IdentityKey] = entry;
 }
Beispiel #32
0
 public void AddConsumingCell(FormulaCellCacheEntry cellLoc)
 {
     _consumingCells.Add(cellLoc);
 }
Beispiel #33
0
        public void NotifyUpdateCell(int bookIndex, int sheetIndex, IEvaluationCell cell)
        {
            FormulaCellCacheEntry fcce = _formulaCellCache.Get(cell);

            int rowIndex = cell.RowIndex;
            int columnIndex = cell.ColumnIndex;
            Loc loc = new Loc(bookIndex, sheetIndex, cell.RowIndex, cell.ColumnIndex);
            PlainValueCellCacheEntry pcce = _plainCellCache.Get(loc);

            if (cell.CellType == NPOI.SS.UserModel.CellType.FORMULA)
            {
                if (fcce == null)
                {
                    fcce = new FormulaCellCacheEntry();

                    if (pcce == null)
                    {
                        if (_evaluationListener != null)
                        {
                            _evaluationListener.OnChangeFromBlankValue(sheetIndex, rowIndex,
                                    columnIndex, cell, fcce);
                        }
                        UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, rowIndex, columnIndex);
                    }
                    _formulaCellCache.Put(cell, fcce);
                }
                else
                {
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    fcce.ClearFormulaEntry();
                }
                if (pcce == null)
                {
                    // was formula cell before - no Change of type
                }
                else
                {
                    // changing from plain cell To formula cell
                    pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    _plainCellCache.Remove(loc);
                }
            }
            else
            {
                ValueEval value = WorkbookEvaluator.GetValueFromNonFormulaCell(cell);
                if (pcce == null)
                {
                    if (value != BlankEval.instance)
                    {
                        pcce = new PlainValueCellCacheEntry(value);
                        if (fcce == null)
                        {
                            if (_evaluationListener != null)
                            {
                                _evaluationListener.OnChangeFromBlankValue(sheetIndex, rowIndex,
                                        columnIndex, cell, pcce);
                            }
                            UpdateAnyBlankReferencingFormulas(bookIndex, sheetIndex, rowIndex, columnIndex);
                        }
                        _plainCellCache.Put(loc, pcce);
                    }
                }
                else
                {
                    if (pcce.UpdateValue(value))
                    {
                        pcce.RecurseClearCachedFormulaResults(_evaluationListener);
                    }
                    if (value == BlankEval.instance)
                    {
                        _plainCellCache.Remove(loc);
                    }
                }
                if (fcce == null)
                {
                    // was plain cell before - no Change of type
                }
                else
                {
                    // was formula cell before - now a plain value
                    _formulaCellCache.Remove(cell);
                    fcce.SetSensitiveInputCells(null);
                    fcce.RecurseClearCachedFormulaResults(_evaluationListener);
                }
            }
        }
        /**
         * @return never <c>null</c>, never {@link BlankEval}
         */
        private ValueEval EvaluateAny(EvaluationCell srcCell, int sheetIndex,
                                      int rowIndex, int columnIndex, EvaluationTracker tracker)
        {
            if (srcCell == null || srcCell.CellType != CellType.FORMULA)
            {
                ValueEval result = GetValueFromNonFormulaCell(srcCell);
                tracker.AcceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
                return(result);
            }

            FormulaCellCacheEntry cce = _cache.GetOrCreateFormulaCellEntry(srcCell);

            tracker.AcceptFormulaDependency(cce);
            IEvaluationListener evalListener = _evaluationListener;

            if (cce.GetValue() == null)
            {
                if (!tracker.StartEvaluate(cce))
                {
                    return(ErrorEval.CIRCULAR_REF_ERROR);
                }
                OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);

                try
                {
                    ValueEval result;

                    Ptg[] ptgs = _workbook.GetFormulaTokens(srcCell);
                    if (evalListener == null)
                    {
                        result = EvaluateFormula(ec, ptgs);
                    }
                    else
                    {
                        evalListener.OnStartEvaluate(srcCell, cce);
                        result = EvaluateFormula(ec, ptgs);
                        evalListener.OnEndEvaluate(cce, result);
                    }

                    tracker.UpdateCacheResult(result);
                }
                finally
                {
                    tracker.EndEvaluate(cce);
                }
            }
            else
            {
                if (evalListener != null)
                {
                    evalListener.OnCacheHit(sheetIndex, rowIndex, columnIndex, cce.GetValue());
                }
                return(cce.GetValue());
            }
            if (IsDebugLogEnabled())
            {
                String        sheetName = GetSheetName(sheetIndex);
                CellReference cr        = new CellReference(rowIndex, columnIndex);
                LogDebug("Evaluated " + sheetName + "!" + cr.FormatAsString() + " To " + cce.GetValue().ToString());
            }
            return(cce.GetValue());
        }