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