summaryrefslogtreecommitdiff
path: root/cppuhelper
diff options
context:
space:
mode:
Diffstat (limited to 'cppuhelper')
-rw-r--r--cppuhelper/Library_cppuhelper.mk7
-rw-r--r--cppuhelper/inc/compbase2.hxx128
-rw-r--r--cppuhelper/inc/interfacecontainer4.hxx426
-rw-r--r--cppuhelper/inc/unoimplbase.hxx37
-rw-r--r--cppuhelper/source/compbase.cxx231
-rw-r--r--cppuhelper/source/component_context.cxx49
-rw-r--r--cppuhelper/source/unoimplbase.cxx27
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: */