diff options
Diffstat (limited to 'cppuhelper')
-rw-r--r-- | cppuhelper/Library_cppuhelper.mk | 7 | ||||
-rw-r--r-- | cppuhelper/inc/compbase2.hxx | 128 | ||||
-rw-r--r-- | cppuhelper/inc/interfacecontainer4.hxx | 426 | ||||
-rw-r--r-- | cppuhelper/inc/unoimplbase.hxx | 37 | ||||
-rw-r--r-- | cppuhelper/source/compbase.cxx | 231 | ||||
-rw-r--r-- | cppuhelper/source/component_context.cxx | 49 | ||||
-rw-r--r-- | cppuhelper/source/unoimplbase.cxx | 27 |
7 files changed, 882 insertions, 23 deletions
diff --git a/cppuhelper/Library_cppuhelper.mk b/cppuhelper/Library_cppuhelper.mk index dbbfa55d542e..3a1b4b776f66 100644 --- a/cppuhelper/Library_cppuhelper.mk +++ b/cppuhelper/Library_cppuhelper.mk @@ -45,10 +45,16 @@ $(eval $(call gb_Library_add_cxxflags,cppuhelper,\ )) endif +$(eval $(call gb_Library_set_include,cppuhelper,\ + -I$(SRCDIR)/cppuhelper/inc \ + $$(INCLUDE) \ +)) + $(eval $(call gb_Library_add_exception_objects,cppuhelper,\ cppuhelper/source/access_control \ cppuhelper/source/bootstrap \ cppuhelper/source/compat \ + cppuhelper/source/compbase \ cppuhelper/source/component_context \ cppuhelper/source/component \ cppuhelper/source/defaultbootstrap \ @@ -68,6 +74,7 @@ $(eval $(call gb_Library_add_exception_objects,cppuhelper,\ cppuhelper/source/tdmgr \ cppuhelper/source/typemanager \ cppuhelper/source/typeprovider \ + cppuhelper/source/unoimplbase \ cppuhelper/source/unourl \ cppuhelper/source/weak \ )) diff --git a/cppuhelper/inc/compbase2.hxx b/cppuhelper/inc/compbase2.hxx new file mode 100644 index 000000000000..6e1486d9fabe --- /dev/null +++ b/cppuhelper/inc/compbase2.hxx @@ -0,0 +1,128 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sal/config.h> + +#include <cppuhelper/cppuhelperdllapi.h> +#include "interfacecontainer4.hxx" +#include "unoimplbase.hxx" +#include <cppuhelper/weak.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <mutex> + +/** +This is a straight copy of the include/comphelper/compbase.hxx file, copied here +because it is nigh impossible to move shared code down into the URE layer. +*/ + +namespace cppuhelper +{ +/** + Serves two purposes + (1) extracts code that doesn't need to be templated + (2) helps to handle the custom where we have conflicting interfaces + e.g. multiple UNO interfaces that extend css::lang::XComponent +*/ +class CPPUHELPER_DLLPUBLIC WeakComponentImplHelperBase2 : public virtual UnoImplBase, + public cppu::OWeakObject, + public css::lang::XComponent +{ +public: + virtual ~WeakComponentImplHelperBase2() override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL + addEventListener(css::uno::Reference<css::lang::XEventListener> const& rxListener) override; + virtual void SAL_CALL + removeEventListener(css::uno::Reference<css::lang::XEventListener> const& rxListener) override; + + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) override; + + /** + Called by dispose for subclasses to do dispose() work. + The mutex is held when called, and subclasses can unlock() the guard if necessary. + */ + virtual void disposing(std::unique_lock<std::mutex>&); + +protected: + void throwIfDisposed(std::unique_lock<std::mutex>&) + { + if (m_bDisposed) + throw css::lang::DisposedException(OUString(), static_cast<cppu::OWeakObject*>(this)); + } + OInterfaceContainerHelper4<css::lang::XEventListener> maEventListeners; +}; + +/** WeakComponentImplHelper +*/ +CPPUHELPER_DLLPUBLIC css::uno::Any +WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd, + WeakComponentImplHelperBase2* pBase); + +template <typename... Ifc> +class SAL_DLLPUBLIC_TEMPLATE WeakComponentImplHelper2 : public WeakComponentImplHelperBase2, + public css::lang::XTypeProvider, + public Ifc... +{ +public: + virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); } + + virtual void SAL_CALL release() noexcept override { OWeakObject::release(); } + + // css::lang::XComponent + virtual void SAL_CALL dispose() noexcept final override + { + WeakComponentImplHelperBase2::dispose(); + } + virtual void SAL_CALL addEventListener( + css::uno::Reference<css::lang::XEventListener> const& rxListener) final override + { + WeakComponentImplHelperBase2::addEventListener(rxListener); + } + virtual void SAL_CALL removeEventListener( + css::uno::Reference<css::lang::XEventListener> const& rxListener) final override + { + WeakComponentImplHelperBase2::removeEventListener(rxListener); + } + + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) override + { + return WeakComponentImplHelper_query(rType, class_data_get(), this); + } + + // css::lang::XTypeProvider + virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override + { + static const css::uno::Sequence<css::uno::Type> aTypeList{ + cppu::UnoType<css::uno::XWeak>::get(), cppu::UnoType<css::lang::XComponent>::get(), + cppu::UnoType<css::lang::XTypeProvider>::get(), cppu::UnoType<Ifc>::get()... + }; + return aTypeList; + } + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override + { + return css::uno::Sequence<sal_Int8>(); + } + +private: + static cppu::class_data* class_data_get() + { + return cppu::detail::ImplClassData<WeakComponentImplHelper2, Ifc...>{}(); + } +}; + +} // namespace cppuextra + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cppuhelper/inc/interfacecontainer4.hxx b/cppuhelper/inc/interfacecontainer4.hxx new file mode 100644 index 000000000000..5111ae7e5170 --- /dev/null +++ b/cppuhelper/inc/interfacecontainer4.hxx @@ -0,0 +1,426 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <sal/config.h> + +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <o3tl/cow_wrapper.hxx> +#include <cassert> +#include <mutex> +#include <vector> + +namespace com::sun::star::uno +{ +class XInterface; +} + +/** +This is a straight copy of the include/comphelper/interfacecontainer4.hxx file, copied here +because it is nigh impossible to move shared code down into the URE layer. +*/ + +namespace cppuhelper +{ +template <class ListenerT> class OInterfaceContainerHelper4; +/** + This is the iterator of an OInterfaceContainerHelper4. Typically + one constructs an instance on the stack for one firing session. + It is not allowed to assign or copy an instance of this class. + + @tparam ListenerT UNO event listener type + @see OInterfaceContainerHelper4 + */ +template <class ListenerT> class OInterfaceIteratorHelper4 +{ +public: + /** + Create an iterator over the elements of the container. The iterator + copies the elements of the container. A change to the container + during the lifetime of an iterator is allowed and does not + affect the iterator-instance. The iterator and the container take cares + themself for concurrent access, no additional guarding is necessary. + + Remark: The copy is on demand. The iterator copy the elements only if the container + change the contents... + + @param rCont the container of the elements. + @param rGuard + this parameter only here to make that this container is accessed while locked + */ + OInterfaceIteratorHelper4(std::unique_lock<std::mutex>& rGuard, + OInterfaceContainerHelper4<ListenerT>& rCont_) + : rCont(rCont_) + , maData(rCont.maData) + // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator-> + , nRemain(std::as_const(maData)->size()) + { + assert(rGuard.owns_lock()); + (void)rGuard; + } + + /** Return true, if there are more elements in the iterator. */ + bool hasMoreElements() const { return nRemain != 0; } + /** Return the next element of the iterator. Calling this method if + hasMoreElements() has returned false, is an error. + */ + css::uno::Reference<ListenerT> const& next(); + + /** Removes the current element (the last one returned by next()) + from the underlying container. Calling this method before + next() has been called or calling it twice with no next() + in between is an error. + @param rGuard + this parameter only here to make that this container is accessed while locked + */ + void remove(::std::unique_lock<::std::mutex>& rGuard); + +private: + OInterfaceContainerHelper4<ListenerT>& rCont; + o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>, + o3tl::ThreadSafeRefCountingPolicy> + maData; + sal_Int32 nRemain; + + OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4&) = delete; + OInterfaceIteratorHelper4& operator=(const OInterfaceIteratorHelper4&) = delete; +}; + +template <class ListenerT> +const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper4<ListenerT>::next() +{ + nRemain--; + return (*std::as_const(maData))[nRemain]; +} + +template <class ListenerT> +void OInterfaceIteratorHelper4<ListenerT>::remove(::std::unique_lock<::std::mutex>& rGuard) +{ + rCont.removeInterface(rGuard, (*std::as_const(maData))[nRemain]); +} + +/** + A container of interfaces. To access the elements use an iterator. + This implementation is thread-safe. + + This is a copy of the code at include/comphelper/interfacecontainer3.hxx, + except that it (a) uses std::mutex instead of osl::Mutex and (b) does not + store a reference to the mutex, but relies on the calling class to take + a lock around using it. + + @tparam ListenerT UNO event listener type + @see OInterfaceIteratorHelper + */ +template <class ListenerT> class OInterfaceContainerHelper4 +{ +public: + OInterfaceContainerHelper4(); + + /** + Return the number of Elements in the container. Only useful if you have acquired + the mutex. + @param rGuard + this parameter only here to make that this container is accessed while locked + */ + sal_Int32 getLength(std::unique_lock<std::mutex>& rGuard) const; + + /** + Return all interfaces added to this container. + @param rGuard + this parameter only here to make that this container is accessed while locked + **/ + std::vector<css::uno::Reference<ListenerT>> + getElements(std::unique_lock<std::mutex>& rGuard) const; + + /** Inserts an element into the container. The position is not specified, thus it is not + specified in which order events are fired. + + @attention + If you add the same interface more than once, then it will be added to the elements list + more than once and thus if you want to remove that interface from the list, you have to call + removeInterface() the same number of times. + In the latter case, you will also get events fired more than once (if the interface is a + listener interface). + + @param rxIFace + interface to be added; it is allowed to insert + the same interface more than once + @param rGuard + this parameter only here to make that this container is accessed while locked + @return + the new count of elements in the container + */ + sal_Int32 addInterface(std::unique_lock<std::mutex>& rGuard, + const css::uno::Reference<ListenerT>& rxIFace); + /** Removes an element from the container. It uses interface equality to remove the interface. + + @param rxIFace + interface to be removed + @param rGuard + this parameter only here to make that this container is accessed while locked + @return + the new count of elements in the container + */ + sal_Int32 removeInterface(std::unique_lock<std::mutex>& rGuard, + const css::uno::Reference<ListenerT>& rxIFace); + /** + Call disposing on all object in the container that + support XEventListener. Then clear the container. + The guard is unlock()'ed before calling the listeners. + */ + void disposeAndClear(::std::unique_lock<::std::mutex>& rGuard, + const css::lang::EventObject& rEvt); + /** + Clears the container without calling disposing(). + @param rGuard + this parameter only here to make that this container is accessed while locked + */ + void clear(::std::unique_lock<::std::mutex>& rGuard); + + /** Executes a functor for each contained listener of specified type, e.g. + <code>forEach<awt::XPaintListener>(...</code>. + + If a css::lang::DisposedException occurs which relates to + the called listener, then that listener is removed from the container. + + @tparam FuncT unary functor type, let your compiler deduce this for you + @param func unary functor object expecting an argument of type + css::uno::Reference<ListenerT> + @param rGuard + this parameter only here to make that this container is accessed while locked + */ + template <typename FuncT> + inline void forEach(std::unique_lock<std::mutex>& rGuard, FuncT const& func) const; + + /** Calls a UNO listener method for each contained listener. + + The listener method must take a single argument of type EventT, + and return <code>void</code>. + + If a css::lang::DisposedException occurs which relates to + the called listener, then that listener is removed from the container. + + @tparam EventT event type, let your compiler deduce this for you + @param NotificationMethod + Pointer to a method of a ListenerT interface. + @param Event + Event to notify to all contained listeners + @param rGuard + this parameter only here to make that this container is accessed while locked + + Example: +@code + awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... ); + listeners.notifyEach( &XPaintListener::windowPaint, aEvent ); +@endcode + */ + template <typename EventT> + inline void notifyEach(std::unique_lock<std::mutex>& rGuard, + void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), + const EventT& Event) const; + + // this is moveable, but not copyable + OInterfaceContainerHelper4(OInterfaceContainerHelper4&&) = default; + OInterfaceContainerHelper4& operator=(OInterfaceContainerHelper4&&) = default; + +private: + friend class OInterfaceIteratorHelper4<ListenerT>; + o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>, + o3tl::ThreadSafeRefCountingPolicy> + maData; + OInterfaceContainerHelper4(const OInterfaceContainerHelper4&) = delete; + OInterfaceContainerHelper4& operator=(const OInterfaceContainerHelper4&) = delete; + + static o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>, + o3tl::ThreadSafeRefCountingPolicy>& + DEFAULT() + { + static o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>, + o3tl::ThreadSafeRefCountingPolicy> + SINGLETON; + return SINGLETON; + } + +private: + template <typename EventT> class NotifySingleListener + { + private: + typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&); + NotificationMethod const m_pMethod; + const EventT& m_rEvent; + + public: + NotifySingleListener(NotificationMethod method, const EventT& event) + : m_pMethod(method) + , m_rEvent(event) + { + assert(m_pMethod); + } + + void operator()(const css::uno::Reference<ListenerT>& listener) const + { + (listener.get()->*m_pMethod)(m_rEvent); + } + }; +}; + +template <class T> +inline OInterfaceContainerHelper4<T>::OInterfaceContainerHelper4() + : maData(OInterfaceContainerHelper4<T>::DEFAULT()) +{ +} + +template <class T> +template <typename FuncT> +inline void OInterfaceContainerHelper4<T>::forEach(std::unique_lock<std::mutex>& rGuard, + FuncT const& func) const +{ + assert(rGuard.owns_lock()); + if (std::as_const(maData)->size() == 0) + { + return; + } + const_cast<OInterfaceContainerHelper4&>(*this) + .maData.make_unique(); // so we can iterate over the data without holding the lock + OInterfaceIteratorHelper4<T> iter(rGuard, const_cast<OInterfaceContainerHelper4&>(*this)); + rGuard.unlock(); + while (iter.hasMoreElements()) + { + auto xListener = iter.next(); + try + { + func(xListener); + } + catch (css::lang::DisposedException const& exc) + { + if (exc.Context == xListener) + { + rGuard.lock(); + iter.remove(rGuard); + rGuard.unlock(); + } + } + } + rGuard.lock(); +} + +template <class ListenerT> +template <typename EventT> +inline void OInterfaceContainerHelper4<ListenerT>::notifyEach( + std::unique_lock<std::mutex>& rGuard, + void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event) const +{ + forEach<NotifySingleListener<EventT>>(rGuard, + NotifySingleListener<EventT>(NotificationMethod, Event)); +} + +template <class ListenerT> +sal_Int32 +OInterfaceContainerHelper4<ListenerT>::getLength(std::unique_lock<std::mutex>& rGuard) const +{ + assert(rGuard.owns_lock()); + (void)rGuard; + return maData->size(); +} + +template <class ListenerT> +std::vector<css::uno::Reference<ListenerT>> +OInterfaceContainerHelper4<ListenerT>::getElements(std::unique_lock<std::mutex>& rGuard) const +{ + assert(rGuard.owns_lock()); + (void)rGuard; + return *maData; +} + +template <class ListenerT> +sal_Int32 +OInterfaceContainerHelper4<ListenerT>::addInterface(std::unique_lock<std::mutex>& rGuard, + const css::uno::Reference<ListenerT>& rListener) +{ + assert(rGuard.owns_lock()); + (void)rGuard; + assert(rListener.is()); + maData->push_back(rListener); + return maData->size(); +} + +template <class ListenerT> +sal_Int32 OInterfaceContainerHelper4<ListenerT>::removeInterface( + std::unique_lock<std::mutex>& rGuard, const css::uno::Reference<ListenerT>& rListener) +{ + assert(rGuard.owns_lock()); + (void)rGuard; + assert(rListener.is()); + + // It is not valid to compare the pointer directly, but it's faster. + auto it = std::find_if(maData->begin(), maData->end(), + [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) { + return rItem.get() == rListener.get(); + }); + + // interface not found, use the correct compare method + if (it == maData->end()) + it = std::find(maData->begin(), maData->end(), rListener); + + if (it != maData->end()) + maData->erase(it); + + return maData->size(); +} + +template <class ListenerT> +void OInterfaceContainerHelper4<ListenerT>::disposeAndClear(std::unique_lock<std::mutex>& rGuard, + const css::lang::EventObject& rEvt) +{ + { + OInterfaceIteratorHelper4<ListenerT> aIt(rGuard, *this); + maData + = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector + rGuard.unlock(); + // unlock followed by iterating is only safe because we are not going to call remove() on the iterator + while (aIt.hasMoreElements()) + { + try + { + aIt.next()->disposing(rEvt); + } + catch (css::uno::RuntimeException&) + { + // be robust, if e.g. a remote bridge has disposed already. + // there is no way to delegate the error to the caller :o(. + } + } + } + // tdf#152077 need to destruct the OInterfaceIteratorHelper4 before we take the lock again + // because there is a vague chance that destructing it will trigger a call back into something + // that wants to take the lock. + rGuard.lock(); +} + +template <class ListenerT> +void OInterfaceContainerHelper4<ListenerT>::clear(::std::unique_lock<::std::mutex>& rGuard) +{ + assert(rGuard.owns_lock()); + (void)rGuard; + maData->clear(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/inc/unoimplbase.hxx b/cppuhelper/inc/unoimplbase.hxx new file mode 100644 index 000000000000..fe38acb7a423 --- /dev/null +++ b/cppuhelper/inc/unoimplbase.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ +#pragma once + +#include <cppuhelper/cppuhelperdllapi.h> +#include <mutex> + +namespace cppuhelper +{ +/** +This is a straight copy of the include/comphelper/unoimplbase.hxx file, copied here +because it is nigh impossible to move shared code down into the URE layer. +<br/> +This class is meant to be used as a base class for UNO object implementations that +want to use std::mutex for locking. +It meant to be virtually inherited, so the base class is shared between +the UNO object and helper classes like comphelper::OPropertySetHelper +*/ +class CPPUHELPER_DLLPUBLIC UnoImplBase +{ +public: + virtual ~UnoImplBase(); + +protected: + mutable std::mutex m_aMutex; + bool m_bDisposed = false; +}; + +} // namespace comphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cppuhelper/source/compbase.cxx b/cppuhelper/source/compbase.cxx new file mode 100644 index 000000000000..ed4909b71106 --- /dev/null +++ b/cppuhelper/source/compbase.cxx @@ -0,0 +1,231 @@ +/* -*- 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: */ diff --git a/cppuhelper/source/component_context.cxx b/cppuhelper/source/component_context.cxx index 81c7d306fae3..21604a6bcd1b 100644 --- a/cppuhelper/source/component_context.cxx +++ b/cppuhelper/source/component_context.cxx @@ -31,6 +31,7 @@ #include <cppuhelper/compbase.hxx> #include <cppuhelper/component_context.hxx> #include <cppuhelper/implbase.hxx> +#include <compbase2.hxx> #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/lang/XSingleServiceFactory.hpp> @@ -57,20 +58,24 @@ using namespace ::com::sun::star; namespace cppu { -static void try_dispose( Reference< XInterface > const & xInstance ) +static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< XInterface > const & xInstance ) { Reference< lang::XComponent > xComp( xInstance, UNO_QUERY ); if (xComp.is()) { + rGuard.unlock(); xComp->dispose(); + rGuard.lock(); } } -static void try_dispose( Reference< lang::XComponent > const & xComp ) +static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< lang::XComponent > const & xComp ) { if (xComp.is()) { + rGuard.unlock(); xComp->dispose(); + rGuard.lock(); } } @@ -116,8 +121,7 @@ void DisposingForwarder::disposing( lang::EventObject const & ) namespace { class ComponentContext - : private cppu::BaseMutex - , public WeakComponentImplHelper< XComponentContext, + : public cppuhelper::WeakComponentImplHelper2< XComponentContext, container::XNameContainer > { protected: @@ -141,7 +145,7 @@ protected: protected: Any lookupMap( OUString const & rName ); - virtual void SAL_CALL disposing() override; + virtual void disposing(std::unique_lock<std::mutex>&) override; public: ComponentContext( ContextEntry_Init const * pEntries, sal_Int32 nEntries, @@ -179,7 +183,7 @@ void ComponentContext::insertByName( /* lateInit_: */ name.startsWith( "/singletons/" ) && !element.hasValue() ); - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); std::pair<t_map::iterator, bool> insertion( m_map.emplace( name, entry ) ); if (! insertion.second) @@ -191,7 +195,7 @@ void ComponentContext::insertByName( void ComponentContext::removeByName( OUString const & name ) { - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); t_map::iterator iFind( m_map.find( name ) ); if (iFind == m_map.end()) throw container::NoSuchElementException( @@ -206,7 +210,7 @@ void ComponentContext::removeByName( OUString const & name ) void ComponentContext::replaceByName( OUString const & name, Any const & element ) { - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); t_map::iterator iFind( m_map.find( name ) ); if (iFind == m_map.end()) throw container::NoSuchElementException( @@ -235,14 +239,14 @@ Any ComponentContext::getByName( OUString const & name ) Sequence<OUString> ComponentContext::getElementNames() { - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); return comphelper::mapKeysToSequence(m_map); } sal_Bool ComponentContext::hasByName( OUString const & name ) { - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); return m_map.find( name ) != m_map.end(); } @@ -256,14 +260,14 @@ Type ComponentContext::getElementType() sal_Bool ComponentContext::hasElements() { - MutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); return ! m_map.empty(); } Any ComponentContext::lookupMap( OUString const & rName ) { - ResettableMutexGuard guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); t_map::iterator iFind( m_map.find( rName ) ); if (iFind == m_map.end()) return Any(); @@ -274,7 +278,7 @@ Any ComponentContext::lookupMap( OUString const & rName ) // late init singleton entry Reference< XInterface > xInstance; - guard.clear(); + guard.unlock(); try { @@ -334,7 +338,7 @@ Any ComponentContext::lookupMap( OUString const & rName ) "cppuhelper", "no service object raising singleton " << rName); Any ret; - guard.reset(); + guard.lock(); iFind = m_map.find( rName ); if (iFind != m_map.end()) { @@ -347,9 +351,8 @@ Any ComponentContext::lookupMap( OUString const & rName ) } ret = rEntry.value; } - guard.clear(); if (ret != xInstance) { - try_dispose( xInstance ); + try_dispose( guard, xInstance ); } return ret; } @@ -384,7 +387,7 @@ Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager() return m_xSMgr; } -void ComponentContext::disposing() +void ComponentContext::disposing(std::unique_lock<std::mutex>& rGuard) { Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately @@ -398,7 +401,6 @@ void ComponentContext::disposing() if (rEntry.lateInit) { // late init - MutexGuard guard( m_aMutex ); if (rEntry.lateInit) { rEntry.value.clear(); // release factory @@ -421,19 +423,21 @@ void ComponentContext::disposing() } else // dispose immediately { + rGuard.unlock(); xComp->dispose(); + rGuard.lock(); } } } } // dispose service manager - try_dispose( m_xSMgr ); + try_dispose( rGuard, m_xSMgr ); m_xSMgr.clear(); // dispose ac - try_dispose( xAC ); + try_dispose( rGuard, xAC ); // dispose tdmgr; revokes callback from cppu runtime - try_dispose( xTDMgr ); + try_dispose( rGuard, xTDMgr ); m_map.clear(); @@ -459,8 +463,7 @@ void ComponentContext::disposing() ComponentContext::ComponentContext( ContextEntry_Init const * pEntries, sal_Int32 nEntries, Reference< XComponentContext > const & xDelegate ) - : WeakComponentImplHelper( m_aMutex ), - m_xDelegate( xDelegate ) + : m_xDelegate( xDelegate ) { for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos ) { diff --git a/cppuhelper/source/unoimplbase.cxx b/cppuhelper/source/unoimplbase.cxx new file mode 100644 index 000000000000..be3d423d24c2 --- /dev/null +++ b/cppuhelper/source/unoimplbase.cxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <unoimplbase.hxx> + +namespace cppuhelper +{ +UnoImplBase::~UnoImplBase() {} + +} // end namespace cppuextra + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |