xref: /trunk/main/sc/inc/lookupcache.hxx (revision 38d50f7b)
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