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