1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #ifndef INCLUDED_SC_LOOKUPCACHE_HXX 29 #define INCLUDED_SC_LOOKUPCACHE_HXX 30 31 #include "address.hxx" 32 #include "global.hxx" 33 #include "formula/token.hxx" 34 #include <svl/listener.hxx> 35 #include <tools/string.hxx> 36 37 #include <hash_map> 38 39 class ScDocument; 40 41 42 /** Lookup cache for one range used with interpreter functions such as VLOOKUP 43 and MATCH. Caches query for a specific row and the resulting address looked 44 up, in case other lookups of the same query in the same row are to be 45 performed, which usually occur to obtain a different offset column of the 46 same query. 47 */ 48 49 class ScLookupCache : public SvtListener 50 { 51 public: 52 53 enum Result 54 { 55 NOT_CACHED, /// Query not found in cache. 56 CRITERIA_DIFFERENT, /// Different criteria for same query position exists. 57 NOT_AVAILABLE, /// Criteria not available in lookup range. 58 FOUND /// Criteria found. 59 }; 60 61 enum QueryOp 62 { 63 UNKNOWN, 64 EQUAL, 65 LESS_EQUAL, 66 GREATER_EQUAL 67 }; 68 69 class QueryCriteria 70 { 71 union 72 { 73 double mfVal; 74 const String * mpStr; 75 }; 76 bool mbAlloc : 1; 77 bool mbString : 1; 78 QueryOp meOp : 2; 79 80 void deleteString() 81 { 82 if (mbAlloc && mbString) 83 delete mpStr; 84 } 85 86 // prevent usage 87 QueryCriteria(); 88 QueryCriteria & operator=( const QueryCriteria & r ); 89 90 public: 91 92 explicit QueryCriteria( const ScQueryEntry & rEntry ) : 93 mfVal(0.0), mbAlloc(false), mbString(false) 94 { 95 switch (rEntry.eOp) 96 { 97 case SC_EQUAL : 98 meOp = EQUAL; 99 break; 100 case SC_LESS_EQUAL : 101 meOp = LESS_EQUAL; 102 break; 103 case SC_GREATER_EQUAL : 104 meOp = GREATER_EQUAL; 105 break; 106 default: 107 meOp = UNKNOWN; 108 DBG_ERRORFILE( "ScLookupCache::QueryCriteria not prepared for this ScQueryOp"); 109 } 110 if (rEntry.bQueryByString) 111 setString( rEntry.pStr); 112 else 113 setDouble( rEntry.nVal); 114 } 115 QueryCriteria( const QueryCriteria & r ) : 116 mfVal( r.mfVal), 117 mbAlloc( false), 118 mbString( false), 119 meOp( r.meOp) 120 { 121 if (r.mbString && r.mpStr) 122 { 123 mpStr = new String( *r.mpStr); 124 mbAlloc = mbString = true; 125 } 126 } 127 ~QueryCriteria() 128 { 129 deleteString(); 130 } 131 132 QueryOp getQueryOp() const { return meOp; } 133 134 void setDouble( double fVal ) 135 { 136 deleteString(); 137 mbAlloc = mbString = false; 138 mfVal = fVal; 139 } 140 141 void setString( const String * pStr ) 142 { 143 deleteString(); 144 mbAlloc = false; 145 mbString = true; 146 mpStr = pStr; 147 } 148 149 void setString( const String & rStr ) 150 { 151 deleteString(); 152 mbAlloc = mbString = true; 153 mpStr = new String( rStr); 154 } 155 156 bool operator==( const QueryCriteria & r ) const 157 { 158 return meOp == r.meOp && mbString == r.mbString && 159 (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal)); 160 } 161 162 }; 163 164 /// MUST be new'd because Notify() deletes. 165 ScLookupCache( ScDocument * pDoc, const ScRange & rRange ); 166 virtual ~ScLookupCache(); 167 /// Remove from document structure and delete (!) cache on modify hint. 168 virtual void Notify( SvtBroadcaster & rBC, const SfxHint & rHint ); 169 170 /// @returns document address in o_rAddress if Result==FOUND 171 Result lookup( ScAddress & o_rResultAddress, 172 const QueryCriteria & rCriteria, 173 const ScAddress & rQueryAddress ) const; 174 175 /** Insert query and result. 176 @param bAvailable 177 Pass sal_False if the search didn't deliver a result. A subsequent 178 lookup() then will return Result::NOT_AVAILABLE. 179 @returns successful insertion. 180 */ 181 bool insert( const ScAddress & rResultAddress, 182 const QueryCriteria & rCriteria, 183 const ScAddress & rQueryAddress, 184 const bool bAvailable ); 185 186 inline const ScRange& getRange() const { return maRange; } 187 188 struct Hash 189 { 190 size_t operator()( const ScRange & rRange ) const 191 { 192 // Lookups are performed on the first column. 193 return rRange.hashStartColumn(); 194 } 195 }; 196 197 private: 198 199 struct QueryKey 200 { 201 SCROW mnRow; 202 SCTAB mnTab; 203 QueryOp meOp : 2; 204 205 QueryKey( const ScAddress & rAddress, const QueryOp eOp ) : 206 mnRow( rAddress.Row()), 207 mnTab( rAddress.Tab()), 208 meOp( eOp) 209 { 210 } 211 212 bool operator==( const QueryKey & r ) const 213 { 214 return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN; 215 } 216 217 struct Hash 218 { 219 size_t operator()( const QueryKey & r ) const 220 { 221 return (static_cast<size_t>(r.mnTab) << 24) ^ 222 (static_cast<size_t>(r.meOp) << 22) ^ 223 static_cast<size_t>(r.mnRow); 224 } 225 }; 226 }; 227 228 struct QueryCriteriaAndResult 229 { 230 QueryCriteria maCriteria; 231 ScAddress maAddress; 232 233 QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) : 234 maCriteria( rCriteria), 235 maAddress( rAddress) 236 { 237 } 238 ~QueryCriteriaAndResult() 239 { 240 } 241 }; 242 243 typedef ::std::hash_map< QueryKey, QueryCriteriaAndResult, QueryKey::Hash, ::std::equal_to< QueryKey > > QueryMap; 244 QueryMap maQueryMap; 245 ScRange maRange; 246 ScDocument * mpDoc; 247 248 // prevent usage 249 ScLookupCache( const ScLookupCache & ); 250 ScLookupCache & operator=( const ScLookupCache & ); 251 252 }; 253 254 255 typedef ::std::hash_map< ScRange, ScLookupCache*, ScLookupCache::Hash, ::std::equal_to< ScRange > > ScLookupCacheMap; 256 257 #endif 258