Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/comphelper/singletonref.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
#pragma once
20
21
#include <sal/config.h>
22
#include <sal/log.hxx>
23
#include <mutex>
24
25
namespace comphelper
26
{
27
/** @short  Template for implementing singleton classes.
28
            This is a replacement for salhelper::SingletonRef, but which uses std::mutex instead of osl::Mutex.
29
30
            Such classes can be instantiated every time they
31
            are needed. But the internal wrapped object will
32
            be created one times only. Of course it's used
33
            resources are referenced one times only too.
34
            This template hold it alive till the last
35
            reference is gone. Further all operations
36
            on this reference are threadsafe. Only
37
            calls directly to the internal object (which modify
38
            its state) must be made threadsafe by the object itself
39
            or from outside.
40
41
    @attention  To prevent the code against race conditions, it's not
42
                allowed to start operations inside the ctor
43
                of the internal wrapped object - especially operations
44
                which needs a reference to the same singleton too.
45
46
                The only chance to suppress such strange constellations
47
                is a lazy-init mechanism.
48
49
                <ul>
50
                    <li>a) The singleton class can provide a special init()
51
                           method, which must be called as first after creation.</li>
52
                    <li>b) The singleton class can call a special impl_init()
53
                           method implicit for every called interface method.</li>
54
                </ul>
55
56
                Note further that this singleton pattern can work only, if
57
                all user of such singleton are located inside the same library!
58
                Because static values can't be exported - e.g. from windows libraries.
59
 */
60
template <class SingletonClass> class SingletonRef
61
{
62
    // member
63
64
private:
65
    /** @short  pointer to the internal wrapped singleton. */
66
    static SingletonClass* m_pInstance;
67
68
    /** @short  ref count, which regulate creation and removing of m_pInstance. */
69
    static sal_Int32 m_nRef;
70
71
    // interface
72
73
public:
74
    /** @short  standard ctor.
75
76
                    The internal wrapped object is created only,
77
                    if its ref count was 0. Otherwise this method
78
                    does nothing ... except increasing of the internal
79
                    ref count!
80
         */
81
    SingletonRef()
82
1.05M
    {
83
        // GLOBAL SAFE ->
84
1.05M
        std::unique_lock aLock(SingletonRef::ownStaticLock());
85
86
        // must be increased before(!) the check is done.
87
        // Otherwise this check can fail inside the same thread ...
88
1.05M
        ++m_nRef;
89
1.05M
        if (m_nRef == 1)
90
10.3k
            m_pInstance = new SingletonClass();
91
92
1.05M
        SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper",
93
1.05M
                    "Race? Ref count of singleton >0, but instance is NULL!");
94
        // <- GLOBAL SAFE
95
1.05M
    }
comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::SingletonRef()
Line
Count
Source
82
10.3k
    {
83
        // GLOBAL SAFE ->
84
10.3k
        std::unique_lock aLock(SingletonRef::ownStaticLock());
85
86
        // must be increased before(!) the check is done.
87
        // Otherwise this check can fail inside the same thread ...
88
10.3k
        ++m_nRef;
89
10.3k
        if (m_nRef == 1)
90
10.3k
            m_pInstance = new SingletonClass();
91
92
10.3k
        SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper",
93
10.3k
                    "Race? Ref count of singleton >0, but instance is NULL!");
94
        // <- GLOBAL SAFE
95
10.3k
    }
comphelper::SingletonRef<connectivity::DriversConfigImpl>::SingletonRef()
Line
Count
Source
82
1.04M
    {
83
        // GLOBAL SAFE ->
84
1.04M
        std::unique_lock aLock(SingletonRef::ownStaticLock());
85
86
        // must be increased before(!) the check is done.
87
        // Otherwise this check can fail inside the same thread ...
88
1.04M
        ++m_nRef;
89
1.04M
        if (m_nRef == 1)
90
1
            m_pInstance = new SingletonClass();
91
92
1.04M
        SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper",
93
1.04M
                    "Race? Ref count of singleton >0, but instance is NULL!");
94
        // <- GLOBAL SAFE
95
1.04M
    }
96
97
    /** @short  standard dtor.
98
99
                    The internal wrapped object is removed only,
100
                    if its ref count will be 0. Otherwise this method
101
                    does nothing ... except decreasing of the internal
102
                    ref count!
103
         */
104
    ~SingletonRef()
105
1.05M
    {
106
        // GLOBAL SAFE ->
107
1.05M
        std::unique_lock aLock(SingletonRef::ownStaticLock());
108
109
        // must be decreased before(!) the check is done.
110
        // Otherwise this check can fail inside the same thread ...
111
1.05M
        --m_nRef;
112
1.05M
        if (m_nRef == 0)
113
10.3k
        {
114
10.3k
            delete m_pInstance;
115
10.3k
            m_pInstance = nullptr;
116
10.3k
        }
117
        // <- GLOBAL SAFE
118
1.05M
    }
comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::~SingletonRef()
Line
Count
Source
105
10.3k
    {
106
        // GLOBAL SAFE ->
107
10.3k
        std::unique_lock aLock(SingletonRef::ownStaticLock());
108
109
        // must be decreased before(!) the check is done.
110
        // Otherwise this check can fail inside the same thread ...
111
10.3k
        --m_nRef;
112
10.3k
        if (m_nRef == 0)
113
10.3k
        {
114
10.3k
            delete m_pInstance;
115
10.3k
            m_pInstance = nullptr;
116
10.3k
        }
117
        // <- GLOBAL SAFE
118
10.3k
    }
comphelper::SingletonRef<connectivity::DriversConfigImpl>::~SingletonRef()
Line
Count
Source
105
1.04M
    {
106
        // GLOBAL SAFE ->
107
1.04M
        std::unique_lock aLock(SingletonRef::ownStaticLock());
108
109
        // must be decreased before(!) the check is done.
110
        // Otherwise this check can fail inside the same thread ...
111
1.04M
        --m_nRef;
112
1.04M
        if (m_nRef == 0)
113
0
        {
114
0
            delete m_pInstance;
115
0
            m_pInstance = nullptr;
116
0
        }
117
        // <- GLOBAL SAFE
118
1.04M
    }
119
120
    SingletonRef& operator=(SingletonRef const&) = default;
121
122
    /** @short  Allows rSingle->someBodyOp().
123
         */
124
    SingletonClass* operator->() const
125
3.04M
    {
126
        // GLOBAL SAFE ->
127
3.04M
        return m_pInstance;
128
        // <- GLOBAL SAFE
129
3.04M
    }
comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::operator->() const
Line
Count
Source
125
3.04M
    {
126
        // GLOBAL SAFE ->
127
3.04M
        return m_pInstance;
128
        // <- GLOBAL SAFE
129
3.04M
    }
Unexecuted instantiation: comphelper::SingletonRef<connectivity::DriversConfigImpl>::operator->() const
130
131
    /** @short  Allows (*rSingle).someBodyOp().
132
         */
133
    SingletonClass& operator*() const
134
    {
135
        // GLOBAL SAFE ->
136
        return *m_pInstance;
137
        // <- GLOBAL SAFE
138
    }
139
140
    // helper
141
142
private:
143
    SingletonRef(SingletonRef&) = delete;
144
145
    static std::mutex& ownStaticLock()
146
2.10M
    {
147
2.10M
        static std::mutex aInstance;
148
2.10M
        return aInstance;
149
2.10M
    }
comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::ownStaticLock()
Line
Count
Source
146
20.6k
    {
147
20.6k
        static std::mutex aInstance;
148
20.6k
        return aInstance;
149
20.6k
    }
comphelper::SingletonRef<connectivity::DriversConfigImpl>::ownStaticLock()
Line
Count
Source
146
2.08M
    {
147
2.08M
        static std::mutex aInstance;
148
2.08M
        return aInstance;
149
2.08M
    }
150
};
151
152
template <class SingletonClass> SingletonClass* SingletonRef<SingletonClass>::m_pInstance = nullptr;
153
154
template <class SingletonClass> sal_Int32 SingletonRef<SingletonClass>::m_nRef = 0;
155
156
} // namespace comphelper
157
158
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */