office-gobmx/cppuhelper/source/compbase.cxx
Noel Grandin 00f8f75f36 copy some comphelper code down into cppuhelper
Since I want to use them in the cppuhelper too, but comphelper is
"above" cppuhelper in the dependency tree.

And sharing the code between cppuhelper and the rest of LO
across the URE boundary appears to be nigh impossible.

Change-Id: I2ebf37746928dc820df43347dc1a2c158f00ec50
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151445
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2023-05-09 14:50:31 +02:00

231 lines
7.9 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <compbase2.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
namespace cppuhelper
{
WeakComponentImplHelperBase2::~WeakComponentImplHelperBase2() {}
// css::lang::XComponent
void SAL_CALL WeakComponentImplHelperBase2::dispose()
{
std::unique_lock aGuard(m_aMutex);
if (m_bDisposed)
return;
m_bDisposed = true;
disposing(aGuard);
if (!aGuard.owns_lock())
aGuard.lock();
css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
maEventListeners.disposeAndClear(aGuard, aEvt);
}
void WeakComponentImplHelperBase2::disposing(std::unique_lock<std::mutex>&) {}
void SAL_CALL WeakComponentImplHelperBase2::addEventListener(
css::uno::Reference<css::lang::XEventListener> const& rxListener)
{
std::unique_lock aGuard(m_aMutex);
if (m_bDisposed)
return;
maEventListeners.addInterface(aGuard, rxListener);
}
void SAL_CALL WeakComponentImplHelperBase2::removeEventListener(
css::uno::Reference<css::lang::XEventListener> const& rxListener)
{
std::unique_lock aGuard(m_aMutex);
maEventListeners.removeInterface(aGuard, rxListener);
}
css::uno::Any SAL_CALL WeakComponentImplHelperBase2::queryInterface(css::uno::Type const& rType)
{
css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
static_cast<css::lang::XComponent*>(this));
if (aReturn.hasValue())
return aReturn;
return OWeakObject::queryInterface(rType);
}
static void checkInterface(css::uno::Type const& rType)
{
if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
{
OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
SAL_WARN("cppuhelper", msg);
throw css::uno::RuntimeException(msg);
}
}
static bool isXInterface(rtl_uString* pStr)
{
return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
}
static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
typelib_TypeDescriptionReference const* pTDR2)
{
return ((pTDR1 == pTDR2)
|| OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
}
static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
{
cppu::type_entry* pEntries = cd->m_typeEntries;
if (!cd->m_storedTypeRefs) // not inited?
{
static std::mutex aMutex;
std::scoped_lock guard(aMutex);
if (!cd->m_storedTypeRefs) // not inited?
{
// get all types
for (sal_Int32 n = cd->m_nTypes; n--;)
{
cppu::type_entry* pEntry = &pEntries[n];
css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
"### wrong helper init: expected interface!");
OSL_ENSURE(
!isXInterface(rType.getTypeLibType()->pTypeName),
"### want to implement XInterface: template argument is XInterface?!?!?!");
if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
{
OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
SAL_WARN("cppuhelper", msg);
throw css::uno::RuntimeException(msg);
}
// ref is statically held by getCppuType()
pEntry->m_type.typeRef = rType.getTypeLibType();
}
OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
cd->m_storedTypeRefs = true;
}
}
else
{
OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
}
return pEntries;
}
static void* makeInterface(sal_IntPtr nOffset, void* that)
{
return (static_cast<char*>(that) + nOffset);
}
static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
{
// This code assumes that the vtables of a multiple-inheritance class (the
// offset amount by which to adjust the this pointer) follow one another in
// the object layout, and that they contain slots for the inherited classes
// in a specific order. In theory, that need not hold for any given
// platform; in practice, it seems to work well on all supported platforms:
next:
for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
{
if (i > 0)
{
*offset += sizeof(void*);
}
typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
// ignore XInterface:
if (base->nBaseTypes > 0)
{
if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
demandedType))
{
return true;
}
// Profiling showed that it is important to speed up the common case
// of only one base:
if (type->nBaseTypes == 1)
{
type = base;
goto next;
}
if (recursivelyFindType(demandedType, base, offset))
{
return true;
}
}
}
return false;
}
static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
cppu::class_data* cd, void* that)
{
cppu::type_entry* pEntries = getTypeEntries(cd);
sal_Int32 nTypes = cd->m_nTypes;
sal_Int32 n;
// try top interfaces without getting td
for (n = 0; n < nTypes; ++n)
{
if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
{
return makeInterface(pEntries[n].m_offset, that);
}
}
// query deep getting td
for (n = 0; n < nTypes; ++n)
{
typelib_TypeDescription* pTD = nullptr;
TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
if (pTD)
{
// exclude top (already tested) and bottom (XInterface) interface
OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
"### want to implement XInterface:"
" template argument is XInterface?!?!?!");
sal_IntPtr offset = pEntries[n].m_offset;
bool found = recursivelyFindType(
pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
TYPELIB_DANGER_RELEASE(pTD);
if (found)
{
return makeInterface(offset, that);
}
}
else
{
OUString msg("cannot get type description for type \""
+ OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
SAL_WARN("cppuhelper", msg);
throw css::uno::RuntimeException(msg);
}
}
return nullptr;
}
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
WeakComponentImplHelperBase2* pBase)
{
checkInterface(rType);
typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
// shortcut XInterface to WeakComponentImplHelperBase
if (!isXInterface(pTDR->pTypeName))
{
void* p = queryDeepNoXInterface(pTDR, cd, pBase);
if (p)
{
return css::uno::Any(&p, pTDR);
}
}
return pBase->cppuhelper::WeakComponentImplHelperBase2::queryInterface(rType);
}
} // namespace cppuextra
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */