LibreOffice Module comphelper (master) 1
compbase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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
11#include <sal/log.hxx>
12#include <osl/diagnose.h>
13
14namespace comphelper
15{
17
18// css::lang::XComponent
20{
21 std::unique_lock aGuard(m_aMutex);
22 if (m_bDisposed)
23 return;
24 m_bDisposed = true;
25 disposing(aGuard);
26 if (!aGuard.owns_lock())
27 aGuard.lock();
28 css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
30}
31
32void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {}
33
35 css::uno::Reference<css::lang::XEventListener> const& rxListener)
36{
37 std::unique_lock aGuard(m_aMutex);
38 if (m_bDisposed)
39 return;
40 maEventListeners.addInterface(aGuard, rxListener);
41}
42
44 css::uno::Reference<css::lang::XEventListener> const& rxListener)
45{
46 std::unique_lock aGuard(m_aMutex);
47 maEventListeners.removeInterface(aGuard, rxListener);
48}
49
50css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
51{
52 css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
53 static_cast<css::lang::XComponent*>(this));
54 if (aReturn.hasValue())
55 return aReturn;
56 return OWeakObject::queryInterface(rType);
57}
58
59static void checkInterface(css::uno::Type const& rType)
60{
61 if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
62 {
63 OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
64 SAL_WARN("cppuhelper", msg);
65 throw css::uno::RuntimeException(msg);
66 }
67}
68
69static bool isXInterface(rtl_uString* pStr)
70{
71 return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
72}
73
74static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
75 typelib_TypeDescriptionReference const* pTDR2)
76{
77 return ((pTDR1 == pTDR2)
78 || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
79}
80
81static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
82{
83 cppu::type_entry* pEntries = cd->m_typeEntries;
84 if (!cd->m_storedTypeRefs) // not inited?
85 {
86 static std::mutex aMutex;
87 std::scoped_lock guard(aMutex);
88 if (!cd->m_storedTypeRefs) // not inited?
89 {
90 // get all types
91 for (sal_Int32 n = cd->m_nTypes; n--;)
92 {
93 cppu::type_entry* pEntry = &pEntries[n];
94 css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
95 OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
96 "### wrong helper init: expected interface!");
97 OSL_ENSURE(
98 !isXInterface(rType.getTypeLibType()->pTypeName),
99 "### want to implement XInterface: template argument is XInterface?!?!?!");
100 if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
101 {
102 OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
103 SAL_WARN("cppuhelper", msg);
104 throw css::uno::RuntimeException(msg);
105 }
106 // ref is statically held by getCppuType()
107 pEntry->m_type.typeRef = rType.getTypeLibType();
108 }
109 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
110 cd->m_storedTypeRefs = true;
111 }
112 }
113 else
114 {
115 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
116 }
117 return pEntries;
118}
119
120static void* makeInterface(sal_IntPtr nOffset, void* that)
121{
122 return (static_cast<char*>(that) + nOffset);
123}
124
125static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
126 typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
127{
128 // This code assumes that the vtables of a multiple-inheritance class (the
129 // offset amount by which to adjust the this pointer) follow one another in
130 // the object layout, and that they contain slots for the inherited classes
131 // in a specific order. In theory, that need not hold for any given
132 // platform; in practice, it seems to work well on all supported platforms:
133next:
134 for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
135 {
136 if (i > 0)
137 {
138 *offset += sizeof(void*);
139 }
140 typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
141 // ignore XInterface:
142 if (base->nBaseTypes > 0)
143 {
144 if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
145 demandedType))
146 {
147 return true;
148 }
149 // Profiling showed that it is important to speed up the common case
150 // of only one base:
151 if (type->nBaseTypes == 1)
152 {
153 type = base;
154 goto next;
155 }
156 if (recursivelyFindType(demandedType, base, offset))
157 {
158 return true;
159 }
160 }
161 }
162 return false;
163}
164
165static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
166 cppu::class_data* cd, void* that)
167{
168 cppu::type_entry* pEntries = getTypeEntries(cd);
169 sal_Int32 nTypes = cd->m_nTypes;
170 sal_Int32 n;
171
172 // try top interfaces without getting td
173 for (n = 0; n < nTypes; ++n)
174 {
175 if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
176 {
177 return makeInterface(pEntries[n].m_offset, that);
178 }
179 }
180 // query deep getting td
181 for (n = 0; n < nTypes; ++n)
182 {
183 typelib_TypeDescription* pTD = nullptr;
184 TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
185 if (pTD)
186 {
187 // exclude top (already tested) and bottom (XInterface) interface
188 OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
189 "### want to implement XInterface:"
190 " template argument is XInterface?!?!?!");
191 sal_IntPtr offset = pEntries[n].m_offset;
192 bool found = recursivelyFindType(
193 pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
194 TYPELIB_DANGER_RELEASE(pTD);
195 if (found)
196 {
197 return makeInterface(offset, that);
198 }
199 }
200 else
201 {
202 OUString msg("cannot get type description for type \""
203 + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
204 SAL_WARN("cppuhelper", msg);
205 throw css::uno::RuntimeException(msg);
206 }
207 }
208 return nullptr;
209}
210
211css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
213{
214 checkInterface(rType);
215 typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
216
217 // shortcut XInterface to WeakComponentImplHelperBase
218 if (!isXInterface(pTDR->pTypeName))
219 {
220 void* p = queryDeepNoXInterface(pTDR, cd, pBase);
221 if (p)
222 {
223 return css::uno::Any(&p, pTDR);
224 }
225 }
226 return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
227}
228
229} // namespace comphelper
230
231/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Inserts an element into the container.
void disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Removes an element from the container.
Serves two purposes (1) extracts code that doesn't need to be templated (2) helps to handle the custo...
Definition: compbase.hxx:33
virtual void SAL_CALL dispose() override
Definition: compbase.cxx:19
comphelper::OInterfaceContainerHelper4< css::lang::XEventListener > maEventListeners
Definition: compbase.hxx:53
virtual void disposing(std::unique_lock< std::mutex > &)
Called by dispose for subclasses to do dispose() work.
Definition: compbase.cxx:32
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const &rType) override
Definition: compbase.cxx:50
virtual ~WeakComponentImplHelperBase() override
Definition: compbase.cxx:16
virtual void SAL_CALL removeEventListener(css::uno::Reference< css::lang::XEventListener > const &rxListener) override
Definition: compbase.cxx:43
virtual void SAL_CALL addEventListener(css::uno::Reference< css::lang::XEventListener > const &rxListener) override
Definition: compbase.cxx:34
const Type m_type
Mutex aMutex
void const * base
void * p
sal_Int64 n
#define SAL_WARN(area, stream)
struct _typelib_TypeDescription typelib_TypeDescription
static void * makeInterface(sal_IntPtr nOffset, void *that)
Definition: compbase.cxx:120
static bool recursivelyFindType(typelib_TypeDescriptionReference const *demandedType, typelib_InterfaceTypeDescription const *type, sal_IntPtr *offset)
Definition: compbase.cxx:125
static cppu::type_entry * getTypeEntries(cppu::class_data *cd)
Definition: compbase.cxx:81
static bool isXInterface(rtl_uString *pStr)
Definition: compbase.cxx:69
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const &rType, cppu::class_data *cd, WeakComponentImplHelperBase *pBase)
WeakComponentImplHelper.
Definition: compbase.cxx:211
static void * queryDeepNoXInterface(typelib_TypeDescriptionReference const *pDemandedTDR, cppu::class_data *cd, void *that)
Definition: compbase.cxx:165
static void checkInterface(css::uno::Type const &rType)
Definition: compbase.cxx:59
static bool td_equals(typelib_TypeDescriptionReference const *pTDR1, typelib_TypeDescriptionReference const *pTDR2)
Definition: compbase.cxx:74
int i
std::mutex mutex
Definition: random.cxx:41
ResultType type