Coverage Report

Created: 2026-07-10 11:04

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
1.17k
        {
73
1.17k
            if (mbAlloc && mbString)
74
485
                delete mpStr;
75
1.17k
        }
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
710
        QueryOp getQueryOp() const { return meOp; }
86
509
        LookupSearchMode getSearchMode() const { return meSearchMode; }
87
88
        void setDouble( double fVal )
89
132
        {
90
132
            deleteString();
91
132
            mbAlloc = mbString = false;
92
132
            mfVal = fVal;
93
132
        }
94
95
        void setString( const OUString & rStr )
96
176
        {
97
176
            deleteString();
98
176
            mbAlloc = mbString = true;
99
176
            mpStr = new OUString( rStr);
100
176
        }
101
102
        bool operator==( const QueryCriteria & r ) const
103
135
        {
104
135
            return meOp == r.meOp && meSearchMode == r.meSearchMode && mbString == r.mbString &&
105
135
                (mbString ? (*mpStr == *r.mpStr) : (mfVal == r.mfVal));
106
135
        }
107
108
        bool isEmptyStringQuery() const
109
201
        {
110
201
            return (getQueryOp() == QueryOp::EQUAL) && mbString && mpStr && mpStr->isEmpty();
111
201
        }
112
    };
113
114
    /// MUST be new'd because Notify() deletes.
115
                            ScLookupCache( ScDocument * pDoc, const ScRange & rRange, ScLookupCacheMap & cacheMap )
116
94
                                : 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
308
        {
146
            // Lookups are performed on the first column.
147
308
            return rRange.hashStartColumn();
148
308
        }
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
509
            mnRow( rAddress.Row()),
162
509
            mnTab( rAddress.Tab()),
163
509
            meOp( eOp),
164
509
            meSearchMode( eSearchMode)
165
509
        {
166
509
        }
167
168
        bool operator==( const QueryKey & r ) const
169
121
        {
170
121
            return mnRow == r.mnRow && mnTab == r.mnTab && meOp == r.meOp && meOp != UNKNOWN &&
171
121
                meSearchMode == r.meSearchMode;
172
121
        }
173
174
        struct Hash
175
        {
176
            size_t operator()( const QueryKey & r ) const
177
415
            {
178
415
                return (static_cast<size_t>(r.mnTab) << 24) ^
179
415
                    (static_cast<size_t>(r.meOp) << 22) ^
180
415
                    (static_cast<size_t>(r.meSearchMode) << 20) ^
181
415
                    static_cast<size_t>(r.mnRow);
182
415
            }
183
        };
184
    };
185
186
    struct QueryCriteriaAndResult
187
    {
188
        QueryCriteria   maCriteria;
189
        ScAddress       maAddress;
190
191
        QueryCriteriaAndResult( const QueryCriteria & rCriteria, const ScAddress & rAddress ) :
192
187
            maCriteria( rCriteria),
193
187
            maAddress( rAddress)
194
187
        {
195
187
        }
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: */