LibreOffice Module sc (master)  1
rangecache.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <rangecache.hxx>
21 #include <cellvalue.hxx>
22 #include <document.hxx>
23 #include <brdcst.hxx>
24 #include <queryevaluator.hxx>
25 #include <queryparam.hxx>
26 
27 #include <sal/log.hxx>
29 
30 static bool needsDescending(const ScQueryParam& param)
31 {
32  assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
33  && param.GetEntry(0).GetQueryItems().size() == 1);
34  assert(param.GetEntry(0).eOp == SC_GREATER || param.GetEntry(0).eOp == SC_GREATER_EQUAL
35  || param.GetEntry(0).eOp == SC_LESS || param.GetEntry(0).eOp == SC_LESS_EQUAL
36  || param.GetEntry(0).eOp == SC_EQUAL);
37  // We want all matching values to start in the sort order,
38  // since the data is searched from start until the last matching one.
39  return param.GetEntry(0).eOp == SC_GREATER || param.GetEntry(0).eOp == SC_GREATER_EQUAL;
40 }
41 
43 {
44  assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
45  && param.GetEntry(0).GetQueryItems().size() == 1);
52 }
53 
55  const ScQueryParam& param, ScInterpreterContext* context)
56  : maRange(rRange)
57  , mpDoc(pDoc)
58  , mDescending(needsDescending(param))
59  , mValues(toValueType(param))
60 {
61  assert(maRange.aStart.Col() == maRange.aEnd.Col());
62  assert(maRange.aStart.Tab() == maRange.aEnd.Tab());
63  SCTAB nTab = maRange.aStart.Tab();
64  SCTAB nCol = maRange.aStart.Col();
65  assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
66  && param.GetEntry(0).GetQueryItems().size() == 1);
67  const ScQueryEntry& entry = param.GetEntry(0);
68  const ScQueryEntry::Item& item = entry.GetQueryItem();
69 
70  SCROW startRow = maRange.aStart.Row();
71  SCROW endRow = maRange.aEnd.Row();
72  SCCOL startCol = maRange.aStart.Col();
73  SCCOL endCol = maRange.aEnd.Col();
74  if (!item.mbMatchEmpty)
75  if (!pDoc->ShrinkToDataArea(nTab, startCol, startRow, endCol, endRow))
76  return;
77 
79  {
80  struct RowData
81  {
82  SCROW row;
83  double value;
84  };
85  std::vector<RowData> rowData;
86  for (SCROW nRow = startRow; nRow <= endRow; ++nRow)
87  {
88  ScRefCellValue cell(pDoc->GetRefCellValue(ScAddress(nCol, nRow, nTab)));
89  if (ScQueryEvaluator::isQueryByValue(entry, item, cell))
90  rowData.push_back(RowData{ nRow, cell.getValue() });
91  }
92  std::stable_sort(rowData.begin(), rowData.end(),
93  [](const RowData& d1, const RowData& d2) { return d1.value < d2.value; });
94  if (mDescending)
95  for (auto it = rowData.rbegin(); it != rowData.rend(); ++it)
96  mSortedRows.emplace_back(it->row);
97  else
98  for (const RowData& d : rowData)
99  mSortedRows.emplace_back(d.row);
100  }
101  else
102  {
103  struct RowData
104  {
105  SCROW row;
106  OUString string;
107  };
108  std::vector<RowData> rowData;
109  // Try to reuse as much ScQueryEvaluator code as possible, this should
110  // basically do the same comparisons.
111  assert(pDoc->FetchTable(nTab) != nullptr);
112  ScQueryEvaluator evaluator(*pDoc, *pDoc->FetchTable(nTab), param, context);
113  for (SCROW nRow = startRow; nRow <= endRow; ++nRow)
114  {
115  ScRefCellValue cell(pDoc->GetRefCellValue(ScAddress(nCol, nRow, nTab)));
116  if (ScQueryEvaluator::isQueryByString(entry, item, cell))
117  {
118  const svl::SharedString* sharedString = nullptr;
119  OUString string = evaluator.getCellString(cell, nRow, entry, &sharedString);
120  if (sharedString)
121  string = sharedString->getString();
122  rowData.push_back(RowData{ nRow, string });
123  }
124  }
125  CollatorWrapper& collator
127  std::stable_sort(rowData.begin(), rowData.end(),
128  [&collator](const RowData& d1, const RowData& d2) {
129  return collator.compareString(d1.string, d2.string) < 0;
130  });
131  if (mDescending)
132  for (auto it = rowData.rbegin(); it != rowData.rend(); ++it)
133  mSortedRows.emplace_back(it->row);
134  else
135  for (const RowData& d : rowData)
136  mSortedRows.emplace_back(d.row);
137  }
138  mRowToIndex.resize(maRange.aEnd.Row() - maRange.aStart.Row() + 1, mSortedRows.max_size());
139  for (size_t i = 0; i < mSortedRows.size(); ++i)
141 }
142 
144 {
145  if (!mpDoc->IsInDtorClear())
146  {
147  const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
148  if ((p && (p->GetId() == SfxHintId::ScDataChanged))
149  || dynamic_cast<const ScAreaChangedHint*>(&rHint))
150  {
152  delete this;
153  }
154  }
155 }
156 
158  const ScQueryParam& param)
159 {
160  return { range, needsDescending(param), toValueType(param) };
161 }
162 
163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScDocument * mpDoc
Definition: rangecache.hxx:102
OUString getString() const
ScAddress aStart
Definition: address.hxx:497
std::vector< SCROW > mSortedRows
Definition: rangecache.hxx:99
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
SCROW Row() const
Definition: address.hxx:274
const Item & GetQueryItem() const
Definition: queryentry.hxx:85
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2536
void RemoveSortedRangeCache(ScSortedRangeCache &rCache)
Definition: documen2.cxx:1248
static bool needsDescending(const ScQueryParam &param)
Definition: rangecache.cxx:30
QueryItemsType & GetQueryItems()
Definition: queryentry.hxx:75
std::vector< size_t > mRowToIndex
Definition: rangecache.hxx:100
ScAddress aEnd
Definition: address.hxx:498
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:105
SfxHintId GetId() const
virtual void Notify(const SfxHint &rHint) override
Remove from document structure and delete (!) cache on modify hint.
Definition: rangecache.cxx:143
ScSortedRangeCache(ScDocument *pDoc, const ScRange &rRange, const ScQueryParam &param, ScInterpreterContext *context)
MUST be new'd because Notify() deletes.
Definition: rangecache.cxx:54
static bool isQueryByValue(const ScQueryEntry &rEntry, const ScQueryEntry::Item &rItem, const ScRefCellValue &rCell)
static HashKey makeHashKey(const ScRange &range, const ScQueryParam &param)
Definition: rangecache.cxx:157
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:116
SCTAB Tab() const
Definition: address.hxx:283
double d
ScRefCellValue GetRefCellValue(const ScAddress &rPos)
Definition: documen2.cxx:569
static bool isQueryByString(const ScQueryEntry &rEntry, const ScQueryEntry::Item &rItem, const ScRefCellValue &rCell)
int i
sal_Int16 SCCOL
Definition: types.hxx:21
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1035
SCCOL Col() const
Definition: address.hxx:279
bool IsInDtorClear() const
Definition: document.hxx:2447
sal_Int32 SCROW
Definition: types.hxx:17
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1055
void * p
Any value
static ScSortedRangeCache::ValueType toValueType(const ScQueryParam &param)
Definition: rangecache.cxx:42
ScQueryOp eOp
Definition: queryentry.hxx:62
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
B2DRange maRange
sal_Int16 SCTAB
Definition: types.hxx:22