/src/libreoffice/sc/inc/lookupcache.hxx
Line | Count | Source |
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 | | #pragma once |
21 | | |
22 | | #include "address.hxx" |
23 | | #include <svl/listener.hxx> |
24 | | |
25 | | #include <memory> |
26 | | #include <unordered_map> |
27 | | |
28 | | class ScDocument; |
29 | | struct ScLookupCacheMap; |
30 | | struct ScQueryEntry; |
31 | | enum class LookupSearchMode; |
32 | | |
33 | | /** Lookup cache for one range used with interpreter functions such as VLOOKUP |
34 | | and MATCH. Caches query for a specific row and the resulting address looked |
35 | | up, in case other lookups of the same query in the same row are to be |
36 | | performed, which usually occur to obtain a different offset column of the |
37 | | same query. |
38 | | */ |
39 | | class ScLookupCache final : public SvtListener |
40 | | { |
41 | | public: |
42 | | |
43 | | enum Result |
44 | | { |
45 | | NOT_CACHED, /// Query not found in cache. |
46 | | CRITERIA_DIFFERENT, /// Different criteria for same query position exists. |
47 | | NOT_AVAILABLE, /// Criteria not available in lookup range. |
48 | | FOUND /// Criteria found. |
49 | | }; |
50 | | |
51 | | enum QueryOp |
52 | | { |
53 | | UNKNOWN, |
54 | | EQUAL, |
55 | | LESS_EQUAL, |
56 | | GREATER_EQUAL |
57 | | }; |
58 | | |
59 | | class QueryCriteria |
60 | | { |
61 | | union |
62 | | { |
63 | | double mfVal; |
64 | | const OUString *mpStr; |
65 | | }; |
66 | | bool mbAlloc; |
67 | | bool mbString; |
68 | | QueryOp meOp; |
69 | | LookupSearchMode meSearchMode; |
70 | | |
71 | | void deleteString() |
72 | 874 | { |
73 | 874 | if (mbAlloc && mbString) |
74 | 301 | delete mpStr; |
75 | 874 | } |
76 | | |
77 | | QueryCriteria & operator=( const QueryCriteria & r ) = delete; |
78 | | |
79 | | public: |
80 | | |
81 | | explicit QueryCriteria( const ScQueryEntry & rEntry, LookupSearchMode nSearchMode ); |
82 | | QueryCriteria( const QueryCriteria & r ); |
83 | | ~QueryCriteria(); |
84 | | |
85 | 516 | QueryOp getQueryOp() const { return meOp; } |
86 | 373 | LookupSearchMode getSearchMode() const { return meSearchMode; } |
87 | | |
88 | | void setDouble( double fVal ) |
89 | 124 | { |
90 | 124 | deleteString(); |
91 | 124 | mbAlloc = mbString = false; |
92 | 124 | mfVal = fVal; |
93 | 124 | } |
94 | | |
95 | | void setString( const OUString & rStr ) |
96 | 106 | { |
97 | 106 | deleteString(); |
98 | 106 | mbAlloc = mbString = true; |
99 | 106 | mpStr = new OUString( rStr); |
100 | 106 | } |
101 | | |
102 | | bool operator==( const QueryCriteria & r ) const |
103 | 97 | { |
104 | 97 | return meOp == r.meOp && meSearchMode == r.meSearchMode && mbString == r.mbString && |
105 | 97 | (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal)); |
106 | 97 | } |
107 | | |
108 | | bool isEmptyStringQuery() const |
109 | 143 | { |
110 | 143 | return (getQueryOp() == QueryOp::EQUAL) && mbString && mpStr && mpStr->isEmpty(); |
111 | 143 | } |
112 | | }; |
113 | | |
114 | | /// MUST be new'd because Notify() deletes. |
115 | | ScLookupCache( ScDocument * pDoc, const ScRange & rRange, ScLookupCacheMap & cacheMap ) |
116 | 79 | : maRange( rRange), mpDoc( pDoc), mCacheMap(cacheMap) {} |
117 | | /// Remove from document structure and delete (!) cache on modify hint. |
118 | | virtual void Notify( const SfxHint& rHint ) override; |
119 | | |
120 | | /// @returns document address in o_rResultAddress if Result==FOUND |
121 | | Result lookup( ScAddress & o_rResultAddress, |
122 | | const QueryCriteria & rCriteria, |
123 | | const ScAddress & rQueryAddress ) const; |
124 | | |
125 | | SCROW lookup( const QueryCriteria & rCriteria ) const; |
126 | | |
127 | | /** Insert query and result. |
128 | | @param bAvailable |
129 | | Pass sal_False if the search didn't deliver a result. A subsequent |
130 | | lookup() then will return Result::NOT_AVAILABLE. |
131 | | @returns successful insertion. |
132 | | */ |
133 | | bool insert( const ScAddress & rResultAddress, |
134 | | const QueryCriteria & rCriteria, |
135 | | const ScAddress & rQueryAddress, |
136 | | const bool bAvailable ); |
137 | | |
138 | 0 | const ScRange& getRange() const { return maRange; } |
139 | | |
140 | 0 | ScLookupCacheMap & getCacheMap() const { return mCacheMap; } |
141 | | |
142 | | struct Hash |
143 | | { |
144 | | size_t operator()( const ScRange & rRange ) const |
145 | 230 | { |
146 | | // Lookups are performed on the first column. |
147 | 230 | return rRange.hashStartColumn(); |
148 | 230 | } |
149 | | }; |
150 | | |
151 | | private: |
152 | | |
153 | | struct QueryKey |
154 | | { |
155 | | SCROW mnRow; |
156 | | SCTAB mnTab; |
157 | | QueryOp meOp; |
158 | | LookupSearchMode meSearchMode; |
159 | | |
160 | | QueryKey( const ScAddress & rAddress, const QueryOp eOp, LookupSearchMode eSearchMode ) : |
161 | 373 | mnRow( rAddress.Row()), |
162 | 373 | mnTab( rAddress.Tab()), |
163 | 373 | meOp( eOp), |
164 | 373 | meSearchMode( eSearchMode) |
165 | 373 | { |
166 | 373 | } |
167 | | |
168 | | bool operator==( const QueryKey & r ) const |
169 | 92 | { |
170 | 92 | return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN && |
171 | 92 | meSearchMode == r.meSearchMode; |
172 | 92 | } |
173 | | |
174 | | struct Hash |
175 | | { |
176 | | size_t operator()( const QueryKey & r ) const |
177 | 294 | { |
178 | 294 | return (static_cast<size_t>(r.mnTab) << 24) ^ |
179 | 294 | (static_cast<size_t>(r.meOp) << 22) ^ |
180 | 294 | (static_cast<size_t>(r.meSearchMode) << 20) ^ |
181 | 294 | static_cast<size_t>(r.mnRow); |
182 | 294 | } |
183 | | }; |
184 | | }; |
185 | | |
186 | | struct QueryCriteriaAndResult |
187 | | { |
188 | | QueryCriteria maCriteria; |
189 | | ScAddress maAddress; |
190 | | |
191 | | QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) : |
192 | 138 | maCriteria( rCriteria), |
193 | 138 | maAddress( rAddress) |
194 | 138 | { |
195 | 138 | } |
196 | | }; |
197 | | |
198 | | typedef std::unordered_map<QueryKey, QueryCriteriaAndResult, QueryKey::Hash> QueryMap; |
199 | | QueryMap maQueryMap; |
200 | | ScRange maRange; |
201 | | ScDocument * mpDoc; |
202 | | ScLookupCacheMap & mCacheMap; |
203 | | |
204 | | ScLookupCache( const ScLookupCache & ) = delete; |
205 | | ScLookupCache & operator=( const ScLookupCache & ) = delete; |
206 | | |
207 | | }; |
208 | | |
209 | | // Struct because including lookupcache.hxx in document.hxx isn't wanted. |
210 | | struct ScLookupCacheMap |
211 | | { |
212 | | std::unordered_map< ScRange, std::unique_ptr<ScLookupCache>, ScLookupCache::Hash > aCacheMap; |
213 | | }; |
214 | | |
215 | | |
216 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |