Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/inc/lookupcache.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#pragma once
21
22
#include "address.hxx"
23
#include <svl/listener.hxx>
24
25
#include <memory>
26
#include <unordered_map>
27
28
class ScDocument;
29
struct ScLookupCacheMap;
30
struct ScQueryEntry;
31
enum class LookupSearchMode;
32
33
/** Lookup cache for one range used with interpreter functions such as VLOOKUP
34
    and MATCH. Caches query for a specific row and the resulting address looked
35
    up, in case other lookups of the same query in the same row are to be
36
    performed, which usually occur to obtain a different offset column of the
37
    same query.
38
 */
39
class ScLookupCache final : public SvtListener
40
{
41
public:
42
43
    enum Result
44
    {
45
        NOT_CACHED,         /// Query not found in cache.
46
        CRITERIA_DIFFERENT, /// Different criteria for same query position exists.
47
        NOT_AVAILABLE,      /// Criteria not available in lookup range.
48
        FOUND               /// Criteria found.
49
    };
50
51
    enum QueryOp
52
    {
53
        UNKNOWN,
54
        EQUAL,
55
        LESS_EQUAL,
56
        GREATER_EQUAL
57
    };
58
59
    class QueryCriteria
60
    {
61
        union
62
        {
63
            double          mfVal;
64
            const OUString *mpStr;
65
        };
66
        bool                mbAlloc;
67
        bool                mbString;
68
        QueryOp             meOp;
69
        LookupSearchMode    meSearchMode;
70
71
        void deleteString()
72
874
        {
73
874
            if (mbAlloc && mbString)
74
301
                delete mpStr;
75
874
        }
76
77
        QueryCriteria & operator=( const QueryCriteria & r ) = delete;
78
79
    public:
80
81
        explicit QueryCriteria( const ScQueryEntry & rEntry, LookupSearchMode nSearchMode );
82
        QueryCriteria( const QueryCriteria & r );
83
        ~QueryCriteria();
84
85
516
        QueryOp getQueryOp() const { return meOp; }
86
373
        LookupSearchMode getSearchMode() const { return meSearchMode; }
87
88
        void setDouble( double fVal )
89
124
        {
90
124
            deleteString();
91
124
            mbAlloc = mbString = false;
92
124
            mfVal = fVal;
93
124
        }
94
95
        void setString( const OUString & rStr )
96
106
        {
97
106
            deleteString();
98
106
            mbAlloc = mbString = true;
99
106
            mpStr = new OUString( rStr);
100
106
        }
101
102
        bool operator==( const QueryCriteria & r ) const
103
97
        {
104
97
            return meOp == r.meOp && meSearchMode == r.meSearchMode && mbString == r.mbString &&
105
97
                (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal));
106
97
        }
107
108
        bool isEmptyStringQuery() const
109
143
        {
110
143
            return (getQueryOp() == QueryOp::EQUAL) && mbString && mpStr && mpStr->isEmpty();
111
143
        }
112
    };
113
114
    /// MUST be new'd because Notify() deletes.
115
                            ScLookupCache( ScDocument * pDoc, const ScRange & rRange, ScLookupCacheMap & cacheMap )
116
79
                                : maRange( rRange), mpDoc( pDoc), mCacheMap(cacheMap) {}
117
    /// Remove from document structure and delete (!) cache on modify hint.
118
    virtual void Notify( const SfxHint& rHint ) override;
119
120
    /// @returns document address in o_rResultAddress if Result==FOUND
121
            Result          lookup( ScAddress & o_rResultAddress,
122
                                    const QueryCriteria & rCriteria,
123
                                    const ScAddress & rQueryAddress ) const;
124
125
            SCROW           lookup( const QueryCriteria & rCriteria ) const;
126
127
    /** Insert query and result.
128
        @param bAvailable
129
            Pass sal_False if the search didn't deliver a result. A subsequent
130
            lookup() then will return Result::NOT_AVAILABLE.
131
        @returns successful insertion.
132
      */
133
            bool            insert( const ScAddress & rResultAddress,
134
                                    const QueryCriteria & rCriteria,
135
                                    const ScAddress & rQueryAddress,
136
                                    const bool bAvailable );
137
138
0
    const ScRange&  getRange() const { return maRange; }
139
140
0
    ScLookupCacheMap & getCacheMap() const { return mCacheMap; }
141
142
    struct Hash
143
    {
144
        size_t operator()( const ScRange & rRange ) const
145
230
        {
146
            // Lookups are performed on the first column.
147
230
            return rRange.hashStartColumn();
148
230
        }
149
    };
150
151
private:
152
153
    struct QueryKey
154
    {
155
        SCROW           mnRow;
156
        SCTAB           mnTab;
157
        QueryOp         meOp;
158
        LookupSearchMode meSearchMode;
159
160
        QueryKey( const ScAddress & rAddress, const QueryOp eOp, LookupSearchMode eSearchMode ) :
161
373
            mnRow( rAddress.Row()),
162
373
            mnTab( rAddress.Tab()),
163
373
            meOp( eOp),
164
373
            meSearchMode( eSearchMode)
165
373
        {
166
373
        }
167
168
        bool operator==( const QueryKey & r ) const
169
92
        {
170
92
            return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN &&
171
92
                meSearchMode == r.meSearchMode;
172
92
        }
173
174
        struct Hash
175
        {
176
            size_t operator()( const QueryKey & r ) const
177
294
            {
178
294
                return (static_cast<size_t>(r.mnTab) << 24) ^
179
294
                    (static_cast<size_t>(r.meOp) << 22) ^
180
294
                    (static_cast<size_t>(r.meSearchMode) << 20) ^
181
294
                    static_cast<size_t>(r.mnRow);
182
294
            }
183
        };
184
    };
185
186
    struct QueryCriteriaAndResult
187
    {
188
        QueryCriteria   maCriteria;
189
        ScAddress       maAddress;
190
191
        QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) :
192
138
            maCriteria( rCriteria),
193
138
            maAddress( rAddress)
194
138
        {
195
138
        }
196
    };
197
198
    typedef std::unordered_map<QueryKey, QueryCriteriaAndResult, QueryKey::Hash> QueryMap;
199
    QueryMap maQueryMap;
200
    ScRange         maRange;
201
    ScDocument *    mpDoc;
202
    ScLookupCacheMap & mCacheMap;
203
204
    ScLookupCache( const ScLookupCache & ) = delete;
205
    ScLookupCache & operator=( const ScLookupCache & ) = delete;
206
207
};
208
209
// Struct because including lookupcache.hxx in document.hxx isn't wanted.
210
struct ScLookupCacheMap
211
{
212
    std::unordered_map< ScRange, std::unique_ptr<ScLookupCache>, ScLookupCache::Hash > aCacheMap;
213
};
214
215
216
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */