Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / comphelper / source / misc / compbase.cxx
blob02efae8b71c45aad4a68f28fb3f2aeb50d7b9ecb
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.
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 */
10 #include <comphelper/compbase.hxx>
11 #include <cppuhelper/queryinterface.hxx>
12 #include <sal/log.hxx>
13 #include <osl/diagnose.h>
15 namespace comphelper
17 WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {}
19 // css::lang::XComponent
20 void SAL_CALL WeakComponentImplHelperBase::dispose()
22 std::unique_lock aGuard(m_aMutex);
23 if (m_bDisposed)
24 return;
25 m_bDisposed = true;
26 disposing(aGuard);
27 if (!aGuard.owns_lock())
28 aGuard.lock();
29 css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
30 maEventListeners.disposeAndClear(aGuard, aEvt);
33 // This is only called from the destructor to do cleanup that
34 // might not have occurred
35 void WeakComponentImplHelperBase::disposeOnDestruct()
37 std::unique_lock aGuard(m_aMutex);
38 assert(m_refCount == 0 && "only supposed to be called from the destructor");
39 if (m_bDisposed)
40 return;
41 m_bDisposed = true;
42 // bump the ref-count so we don't accidentally do a double delete
43 // if something else increases and then decreases our ref-count
44 cppu::OWeakObject::acquire();
45 disposing(aGuard);
48 void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {}
50 void SAL_CALL WeakComponentImplHelperBase::addEventListener(
51 css::uno::Reference<css::lang::XEventListener> const& rxListener)
53 std::unique_lock aGuard(m_aMutex);
54 if (m_bDisposed)
55 return;
56 maEventListeners.addInterface(aGuard, rxListener);
59 void SAL_CALL WeakComponentImplHelperBase::removeEventListener(
60 css::uno::Reference<css::lang::XEventListener> const& rxListener)
62 std::unique_lock aGuard(m_aMutex);
63 maEventListeners.removeInterface(aGuard, rxListener);
66 css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
68 css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
69 static_cast<css::lang::XComponent*>(this));
70 if (aReturn.hasValue())
71 return aReturn;
72 return OWeakObject::queryInterface(rType);
75 static void checkInterface(css::uno::Type const& rType)
77 if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
79 OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
80 SAL_WARN("cppuhelper", msg);
81 throw css::uno::RuntimeException(msg);
85 static bool isXInterface(rtl_uString* pStr)
87 return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
90 static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
91 typelib_TypeDescriptionReference const* pTDR2)
93 return ((pTDR1 == pTDR2)
94 || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
97 static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
99 cppu::type_entry* pEntries = cd->m_typeEntries;
101 static std::mutex aMutex;
102 std::scoped_lock guard(aMutex);
103 if (!cd->m_storedTypeRefs) // not inited?
105 // get all types
106 for (sal_Int32 n = cd->m_nTypes; n--;)
108 cppu::type_entry* pEntry = &pEntries[n];
109 css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
110 OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
111 "### wrong helper init: expected interface!");
112 OSL_ENSURE(
113 !isXInterface(rType.getTypeLibType()->pTypeName),
114 "### want to implement XInterface: template argument is XInterface?!?!?!");
115 if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
117 OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
118 SAL_WARN("cppuhelper", msg);
119 throw css::uno::RuntimeException(msg);
121 // ref is statically held by getCppuType()
122 pEntry->m_type.typeRef = rType.getTypeLibType();
124 cd->m_storedTypeRefs = true;
127 return pEntries;
130 static void* makeInterface(sal_IntPtr nOffset, void* that)
132 return (static_cast<char*>(that) + nOffset);
135 static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
136 typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
138 // This code assumes that the vtables of a multiple-inheritance class (the
139 // offset amount by which to adjust the this pointer) follow one another in
140 // the object layout, and that they contain slots for the inherited classes
141 // in a specific order. In theory, that need not hold for any given
142 // platform; in practice, it seems to work well on all supported platforms:
143 next:
144 for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
146 if (i > 0)
148 *offset += sizeof(void*);
150 typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
151 // ignore XInterface:
152 if (base->nBaseTypes > 0)
154 if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
155 demandedType))
157 return true;
159 // Profiling showed that it is important to speed up the common case
160 // of only one base:
161 if (type->nBaseTypes == 1)
163 type = base;
164 goto next;
166 if (recursivelyFindType(demandedType, base, offset))
168 return true;
172 return false;
175 static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
176 cppu::class_data* cd, void* that)
178 cppu::type_entry* pEntries = getTypeEntries(cd);
179 sal_Int32 nTypes = cd->m_nTypes;
180 sal_Int32 n;
182 // try top interfaces without getting td
183 for (n = 0; n < nTypes; ++n)
185 if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
187 return makeInterface(pEntries[n].m_offset, that);
190 // query deep getting td
191 for (n = 0; n < nTypes; ++n)
193 typelib_TypeDescription* pTD = nullptr;
194 TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
195 if (pTD)
197 // exclude top (already tested) and bottom (XInterface) interface
198 OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
199 "### want to implement XInterface:"
200 " template argument is XInterface?!?!?!");
201 sal_IntPtr offset = pEntries[n].m_offset;
202 bool found = recursivelyFindType(
203 pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
204 TYPELIB_DANGER_RELEASE(pTD);
205 if (found)
207 return makeInterface(offset, that);
210 else
212 OUString msg("cannot get type description for type \""
213 + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
214 SAL_WARN("cppuhelper", msg);
215 throw css::uno::RuntimeException(msg);
218 return nullptr;
221 css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
222 WeakComponentImplHelperBase* pBase)
224 checkInterface(rType);
225 typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
227 // shortcut XInterface to WeakComponentImplHelperBase
228 if (!isXInterface(pTDR->pTypeName))
230 void* p = queryDeepNoXInterface(pTDR, cd, pBase);
231 if (p)
233 return css::uno::Any(&p, pTDR);
236 return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
239 WeakImplHelperBase::~WeakImplHelperBase() {}
241 css::uno::Any SAL_CALL WeakImplHelperBase::queryInterface(css::uno::Type const& rType)
243 css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this));
244 if (aReturn.hasValue())
245 return aReturn;
246 return OWeakObject::queryInterface(rType);
249 css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
250 WeakImplHelperBase* pBase)
252 checkInterface(rType);
253 typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
255 // shortcut XInterface to WeakComponentImplHelperBase
256 if (!isXInterface(pTDR->pTypeName))
258 void* p = queryDeepNoXInterface(pTDR, cd, pBase);
259 if (p)
261 return css::uno::Any(&p, pTDR);
264 return pBase->comphelper::WeakImplHelperBase::queryInterface(rType);
267 } // namespace comphelper
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */