Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / inc / lookupcache.hxx
blobca1d333880fa68f14a156da14372a8adf13332e0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #pragma once
22 #include "address.hxx"
23 #include <svl/listener.hxx>
25 #include <memory>
26 #include <unordered_map>
28 class ScDocument;
29 struct ScLookupCacheMap;
30 struct ScQueryEntry;
32 /** Lookup cache for one range used with interpreter functions such as VLOOKUP
33 and MATCH. Caches query for a specific row and the resulting address looked
34 up, in case other lookups of the same query in the same row are to be
35 performed, which usually occur to obtain a different offset column of the
36 same query.
39 class ScLookupCache final : public SvtListener
41 public:
43 enum Result
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.
51 enum QueryOp
53 UNKNOWN,
54 EQUAL,
55 LESS_EQUAL,
56 GREATER_EQUAL
59 class QueryCriteria
61 union
63 double mfVal;
64 const OUString *mpStr;
66 bool mbAlloc;
67 bool mbString;
68 QueryOp meOp;
70 void deleteString()
72 if (mbAlloc && mbString)
73 delete mpStr;
76 QueryCriteria & operator=( const QueryCriteria & r ) = delete;
78 public:
80 explicit QueryCriteria( const ScQueryEntry & rEntry );
81 QueryCriteria( const QueryCriteria & r );
82 ~QueryCriteria();
84 QueryOp getQueryOp() const { return meOp; }
86 void setDouble( double fVal )
88 deleteString();
89 mbAlloc = mbString = false;
90 mfVal = fVal;
93 void setString( const OUString & rStr )
95 deleteString();
96 mbAlloc = mbString = true;
97 mpStr = new OUString( rStr);
100 bool operator==( const QueryCriteria & r ) const
102 return meOp == r.meOp && mbString == r.mbString &&
103 (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal));
106 bool isEmptyStringQuery() const
108 return (getQueryOp() == QueryOp::EQUAL) && mbString && mpStr && mpStr->isEmpty();
112 /// MUST be new'd because Notify() deletes.
113 ScLookupCache( ScDocument * pDoc, const ScRange & rRange, ScLookupCacheMap & cacheMap )
114 : maRange( rRange), mpDoc( pDoc), mCacheMap(cacheMap) {}
115 /// Remove from document structure and delete (!) cache on modify hint.
116 virtual void Notify( const SfxHint& rHint ) override;
118 /// @returns document address in o_rResultAddress if Result==FOUND
119 Result lookup( ScAddress & o_rResultAddress,
120 const QueryCriteria & rCriteria,
121 const ScAddress & rQueryAddress ) const;
123 SCROW lookup( const QueryCriteria & rCriteria ) const;
125 /** Insert query and result.
126 @param bAvailable
127 Pass sal_False if the search didn't deliver a result. A subsequent
128 lookup() then will return Result::NOT_AVAILABLE.
129 @returns successful insertion.
131 bool insert( const ScAddress & rResultAddress,
132 const QueryCriteria & rCriteria,
133 const ScAddress & rQueryAddress,
134 const bool bAvailable );
136 const ScRange& getRange() const { return maRange; }
138 ScLookupCacheMap & getCacheMap() const { return mCacheMap; }
140 struct Hash
142 size_t operator()( const ScRange & rRange ) const
144 // Lookups are performed on the first column.
145 return rRange.hashStartColumn();
149 private:
151 struct QueryKey
153 SCROW mnRow;
154 SCTAB mnTab;
155 QueryOp meOp;
157 QueryKey( const ScAddress & rAddress, const QueryOp eOp ) :
158 mnRow( rAddress.Row()),
159 mnTab( rAddress.Tab()),
160 meOp( eOp)
164 bool operator==( const QueryKey & r ) const
166 return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN;
169 struct Hash
171 size_t operator()( const QueryKey & r ) const
173 return (static_cast<size_t>(r.mnTab) << 24) ^
174 (static_cast<size_t>(r.meOp) << 22) ^
175 static_cast<size_t>(r.mnRow);
180 struct QueryCriteriaAndResult
182 QueryCriteria maCriteria;
183 ScAddress maAddress;
185 QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) :
186 maCriteria( rCriteria),
187 maAddress( rAddress)
192 std::unordered_map< QueryKey, QueryCriteriaAndResult, QueryKey::Hash > maQueryMap;
193 ScRange maRange;
194 ScDocument * mpDoc;
195 ScLookupCacheMap & mCacheMap;
197 ScLookupCache( const ScLookupCache & ) = delete;
198 ScLookupCache & operator=( const ScLookupCache & ) = delete;
202 // Struct because including lookupcache.hxx in document.hxx isn't wanted.
203 struct ScLookupCacheMap
205 std::unordered_map< ScRange, std::unique_ptr<ScLookupCache>, ScLookupCache::Hash > aCacheMap;
209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */