1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #ifndef INCLUDED_SC_LOOKUPCACHE_HXX 25 #define INCLUDED_SC_LOOKUPCACHE_HXX 26 27 #include "address.hxx" 28 #include "global.hxx" 29 #include "formula/token.hxx" 30 #include <svl/listener.hxx> 31 #include <tools/string.hxx> 32 33 #include <hash_map> 34 35 class ScDocument; 36 37 38 /** Lookup cache for one range used with interpreter functions such as VLOOKUP 39 and MATCH. Caches query for a specific row and the resulting address looked 40 up, in case other lookups of the same query in the same row are to be 41 performed, which usually occur to obtain a different offset column of the 42 same query. 43 */ 44 45 class ScLookupCache : public SvtListener 46 { 47 public: 48 49 enum Result 50 { 51 NOT_CACHED, /// Query not found in cache. 52 CRITERIA_DIFFERENT, /// Different criteria for same query position exists. 53 NOT_AVAILABLE, /// Criteria not available in lookup range. 54 FOUND /// Criteria found. 55 }; 56 57 enum QueryOp 58 { 59 UNKNOWN, 60 EQUAL, 61 LESS_EQUAL, 62 GREATER_EQUAL 63 }; 64 65 class QueryCriteria 66 { 67 union 68 { 69 double mfVal; 70 const String * mpStr; 71 }; 72 bool mbAlloc : 1; 73 bool mbString : 1; 74 QueryOp meOp : 2; 75 deleteString()76 void deleteString() 77 { 78 if (mbAlloc && mbString) 79 delete mpStr; 80 } 81 82 // prevent usage 83 QueryCriteria(); 84 QueryCriteria & operator=( const QueryCriteria & r ); 85 86 public: 87 QueryCriteria(const ScQueryEntry & rEntry)88 explicit QueryCriteria( const ScQueryEntry & rEntry ) : 89 mfVal(0.0), mbAlloc(false), mbString(false) 90 { 91 switch (rEntry.eOp) 92 { 93 case SC_EQUAL : 94 meOp = EQUAL; 95 break; 96 case SC_LESS_EQUAL : 97 meOp = LESS_EQUAL; 98 break; 99 case SC_GREATER_EQUAL : 100 meOp = GREATER_EQUAL; 101 break; 102 default: 103 meOp = UNKNOWN; 104 DBG_ERRORFILE( "ScLookupCache::QueryCriteria not prepared for this ScQueryOp"); 105 } 106 if (rEntry.bQueryByString) 107 setString( rEntry.pStr); 108 else 109 setDouble( rEntry.nVal); 110 } QueryCriteria(const QueryCriteria & r)111 QueryCriteria( const QueryCriteria & r ) : 112 mfVal( r.mfVal), 113 mbAlloc( false), 114 mbString( false), 115 meOp( r.meOp) 116 { 117 if (r.mbString && r.mpStr) 118 { 119 mpStr = new String( *r.mpStr); 120 mbAlloc = mbString = true; 121 } 122 } ~QueryCriteria()123 ~QueryCriteria() 124 { 125 deleteString(); 126 } 127 getQueryOp() const128 QueryOp getQueryOp() const { return meOp; } 129 setDouble(double fVal)130 void setDouble( double fVal ) 131 { 132 deleteString(); 133 mbAlloc = mbString = false; 134 mfVal = fVal; 135 } 136 setString(const String * pStr)137 void setString( const String * pStr ) 138 { 139 deleteString(); 140 mbAlloc = false; 141 mbString = true; 142 mpStr = pStr; 143 } 144 setString(const String & rStr)145 void setString( const String & rStr ) 146 { 147 deleteString(); 148 mbAlloc = mbString = true; 149 mpStr = new String( rStr); 150 } 151 operator ==(const QueryCriteria & r) const152 bool operator==( const QueryCriteria & r ) const 153 { 154 return meOp == r.meOp && mbString == r.mbString && 155 (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal)); 156 } 157 158 }; 159 160 /// MUST be new'd because Notify() deletes. 161 ScLookupCache( ScDocument * pDoc, const ScRange & rRange ); 162 virtual ~ScLookupCache(); 163 /// Remove from document structure and delete (!) cache on modify hint. 164 virtual void Notify( SvtBroadcaster & rBC, const SfxHint & rHint ); 165 166 /// @returns document address in o_rAddress if Result==FOUND 167 Result lookup( ScAddress & o_rResultAddress, 168 const QueryCriteria & rCriteria, 169 const ScAddress & rQueryAddress ) const; 170 171 /** Insert query and result. 172 @param bAvailable 173 Pass sal_False if the search didn't deliver a result. A subsequent 174 lookup() then will return Result::NOT_AVAILABLE. 175 @returns successful insertion. 176 */ 177 bool insert( const ScAddress & rResultAddress, 178 const QueryCriteria & rCriteria, 179 const ScAddress & rQueryAddress, 180 const bool bAvailable ); 181 getRange() const182 inline const ScRange& getRange() const { return maRange; } 183 184 struct Hash 185 { operator ()ScLookupCache::Hash186 size_t operator()( const ScRange & rRange ) const 187 { 188 // Lookups are performed on the first column. 189 return rRange.hashStartColumn(); 190 } 191 }; 192 193 private: 194 195 struct QueryKey 196 { 197 SCROW mnRow; 198 SCTAB mnTab; 199 QueryOp meOp : 2; 200 QueryKeyScLookupCache::QueryKey201 QueryKey( const ScAddress & rAddress, const QueryOp eOp ) : 202 mnRow( rAddress.Row()), 203 mnTab( rAddress.Tab()), 204 meOp( eOp) 205 { 206 } 207 operator ==ScLookupCache::QueryKey208 bool operator==( const QueryKey & r ) const 209 { 210 return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN; 211 } 212 213 struct Hash 214 { operator ()ScLookupCache::QueryKey::Hash215 size_t operator()( const QueryKey & r ) const 216 { 217 return (static_cast<size_t>(r.mnTab) << 24) ^ 218 (static_cast<size_t>(r.meOp) << 22) ^ 219 static_cast<size_t>(r.mnRow); 220 } 221 }; 222 }; 223 224 struct QueryCriteriaAndResult 225 { 226 QueryCriteria maCriteria; 227 ScAddress maAddress; 228 QueryCriteriaAndResultScLookupCache::QueryCriteriaAndResult229 QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) : 230 maCriteria( rCriteria), 231 maAddress( rAddress) 232 { 233 } ~QueryCriteriaAndResultScLookupCache::QueryCriteriaAndResult234 ~QueryCriteriaAndResult() 235 { 236 } 237 }; 238 239 typedef ::std::hash_map< QueryKey, QueryCriteriaAndResult, QueryKey::Hash, ::std::equal_to< QueryKey > > QueryMap; 240 QueryMap maQueryMap; 241 ScRange maRange; 242 ScDocument * mpDoc; 243 244 // prevent usage 245 ScLookupCache( const ScLookupCache & ); 246 ScLookupCache & operator=( const ScLookupCache & ); 247 248 }; 249 250 251 typedef ::std::hash_map< ScRange, ScLookupCache*, ScLookupCache::Hash, ::std::equal_to< ScRange > > ScLookupCacheMap; 252 253 #endif 254