1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
23 #include <com/sun/star/lang/EventObject.hpp>
24 #include <com/sun/star/lang/DisposedException.hpp>
25 #include <o3tl/cow_wrapper.hxx>
30 namespace com::sun::star::uno
37 template <class ListenerT
> class OInterfaceContainerHelper4
;
39 This is the iterator of an OInterfaceContainerHelper4. Typically
40 one constructs an instance on the stack for one firing session.
41 It is not allowed to assign or copy an instance of this class.
43 @tparam ListenerT UNO event listener type
44 @see OInterfaceContainerHelper4
46 template <class ListenerT
> class OInterfaceIteratorHelper4
50 Create an iterator over the elements of the container. The iterator
51 copies the elements of the container. A change to the container
52 during the lifetime of an iterator is allowed and does not
53 affect the iterator-instance. The iterator and the container take cares
54 themself for concurrent access, no additional guarding is necessary.
56 Remark: The copy is on demand. The iterator copy the elements only if the container
57 change the contents...
59 @param rCont the container of the elements.
61 this parameter only here to make that this container is accessed while locked
63 OInterfaceIteratorHelper4(std::unique_lock
<std::mutex
>& rGuard
,
64 OInterfaceContainerHelper4
<ListenerT
>& rCont_
)
66 , maData(rCont
.maData
)
67 // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator->
68 , nRemain(std::as_const(maData
)->size())
70 assert(rGuard
.owns_lock());
74 /** Return true, if there are more elements in the iterator. */
75 bool hasMoreElements() const { return nRemain
!= 0; }
76 /** Return the next element of the iterator. Calling this method if
77 hasMoreElements() has returned false, is an error.
79 css::uno::Reference
<ListenerT
> const& next();
81 /** Removes the current element (the last one returned by next())
82 from the underlying container. Calling this method before
83 next() has been called or calling it twice with no next()
84 in between is an error.
86 this parameter only here to make that this container is accessed while locked
88 void remove(::std::unique_lock
<::std::mutex
>& rGuard
);
91 OInterfaceContainerHelper4
<ListenerT
>& rCont
;
92 o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
93 o3tl::ThreadSafeRefCountingPolicy
>
97 OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4
&) = delete;
98 OInterfaceIteratorHelper4
& operator=(const OInterfaceIteratorHelper4
&) = delete;
101 template <class ListenerT
>
102 const css::uno::Reference
<ListenerT
>& OInterfaceIteratorHelper4
<ListenerT
>::next()
105 return (*std::as_const(maData
))[nRemain
];
108 template <class ListenerT
>
109 void OInterfaceIteratorHelper4
<ListenerT
>::remove(::std::unique_lock
<::std::mutex
>& rGuard
)
111 rCont
.removeInterface(rGuard
, (*std::as_const(maData
))[nRemain
]);
115 A container of interfaces. To access the elements use an iterator.
116 This implementation is thread-safe.
118 This is a copy of the code at include/comphelper/interfacecontainer3.hxx,
119 except that it (a) uses std::mutex instead of osl::Mutex and (b) does not
120 store a reference to the mutex, but relies on the calling class to take
121 a lock around using it.
123 @tparam ListenerT UNO event listener type
124 @see OInterfaceIteratorHelper
126 template <class ListenerT
> class OInterfaceContainerHelper4
129 OInterfaceContainerHelper4();
132 Return the number of Elements in the container. Only useful if you have acquired
135 this parameter only here to make that this container is accessed while locked
137 sal_Int32
getLength(std::unique_lock
<std::mutex
>& rGuard
) const;
140 Return all interfaces added to this container.
142 this parameter only here to make that this container is accessed while locked
144 std::vector
<css::uno::Reference
<ListenerT
>>
145 getElements(std::unique_lock
<std::mutex
>& rGuard
) const;
147 /** Inserts an element into the container. The position is not specified, thus it is not
148 specified in which order events are fired.
151 If you add the same interface more than once, then it will be added to the elements list
152 more than once and thus if you want to remove that interface from the list, you have to call
153 removeInterface() the same number of times.
154 In the latter case, you will also get events fired more than once (if the interface is a
158 interface to be added; it is allowed to insert
159 the same interface more than once
161 this parameter only here to make that this container is accessed while locked
163 the new count of elements in the container
165 sal_Int32
addInterface(std::unique_lock
<std::mutex
>& rGuard
,
166 const css::uno::Reference
<ListenerT
>& rxIFace
);
167 /** Removes an element from the container. It uses interface equality to remove the interface.
170 interface to be removed
172 this parameter only here to make that this container is accessed while locked
174 the new count of elements in the container
176 sal_Int32
removeInterface(std::unique_lock
<std::mutex
>& rGuard
,
177 const css::uno::Reference
<ListenerT
>& rxIFace
);
179 Call disposing on all object in the container that
180 support XEventListener. Then clear the container.
181 The guard is unlock()'ed before calling the listeners.
183 void disposeAndClear(::std::unique_lock
<::std::mutex
>& rGuard
,
184 const css::lang::EventObject
& rEvt
);
186 Clears the container without calling disposing().
188 this parameter only here to make that this container is accessed while locked
190 void clear(::std::unique_lock
<::std::mutex
>& rGuard
);
192 /** Executes a functor for each contained listener of specified type, e.g.
193 <code>forEach<awt::XPaintListener>(...</code>.
195 If a css::lang::DisposedException occurs which relates to
196 the called listener, then that listener is removed from the container.
198 @tparam FuncT unary functor type, let your compiler deduce this for you
199 @param func unary functor object expecting an argument of type
200 css::uno::Reference<ListenerT>
202 this parameter only here to make that this container is accessed while locked
204 template <typename FuncT
>
205 inline void forEach(std::unique_lock
<std::mutex
>& rGuard
, FuncT
const& func
) const;
207 /** Executes a functor for each contained listener of specified type, e.g.
208 <code>forEach<awt::XPaintListener>(...</code>.
210 If a css::lang::DisposedException occurs which relates to
211 the called listener, then that listener is removed from the container.
213 If any other UNO exception occurs, the exceptionFunc is called.
215 @tparam FuncT unary functor type, let your compiler deduce this for you
216 @tparam ExceptionFuncT nullary functor type, let your compiler deduce this for you
217 @param func unary functor object expecting an argument of type
218 css::uno::Reference<ListenerT>
219 @param exceptionFunc nullary functor object
221 this parameter only here to make that this container is accessed while locked
223 template <typename FuncT
, typename ExceptionFuncT
>
224 inline void forEach(std::unique_lock
<std::mutex
>& rGuard
, FuncT
const& func
,
225 ExceptionFuncT
const& exceptionFunc
) const;
227 /** Calls a UNO listener method for each contained listener.
229 The listener method must take a single argument of type EventT,
230 and return <code>void</code>.
232 If a css::lang::DisposedException occurs which relates to
233 the called listener, then that listener is removed from the container.
235 @tparam EventT event type, let your compiler deduce this for you
236 @param NotificationMethod
237 Pointer to a method of a ListenerT interface.
239 Event to notify to all contained listeners
241 this parameter only here to make that this container is accessed while locked
245 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
246 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
249 template <typename EventT
>
250 inline void notifyEach(std::unique_lock
<std::mutex
>& rGuard
,
251 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&),
252 const EventT
& Event
) const;
254 /** Calls a UNO listener method for each contained listener.
256 The listener method must take a single argument of type EventT,
257 and return <code>void</code>.
259 If a css::lang::DisposedException occurs which relates to
260 the called listener, then that listener is removed from the container.
262 If any other UNO exception occurs, the exceptionFunc is called.
264 @tparam EventT event type, let your compiler deduce this for you
265 @tparam ExceptionFuncT nullary functor type, let your compiler deduce this for you
266 @param NotificationMethod
267 Pointer to a method of a ListenerT interface.
269 Event to notify to all contained listeners
270 @param exceptionFunc nullary functor object
272 this parameter only here to make that this container is accessed while locked
274 template <typename EventT
, typename ExceptionFuncT
>
275 inline void notifyEach(std::unique_lock
<std::mutex
>& rGuard
,
276 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&),
277 const EventT
& Event
, const ExceptionFuncT
& exceptionFunc
) const;
279 // this is moveable, but not copyable
280 OInterfaceContainerHelper4(OInterfaceContainerHelper4
&&) = default;
281 OInterfaceContainerHelper4
& operator=(OInterfaceContainerHelper4
&&) = default;
284 friend class OInterfaceIteratorHelper4
<ListenerT
>;
285 o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
286 o3tl::ThreadSafeRefCountingPolicy
>
288 OInterfaceContainerHelper4(const OInterfaceContainerHelper4
&) = delete;
289 OInterfaceContainerHelper4
& operator=(const OInterfaceContainerHelper4
&) = delete;
291 static o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
292 o3tl::ThreadSafeRefCountingPolicy
>&
295 static o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
296 o3tl::ThreadSafeRefCountingPolicy
>
302 template <typename EventT
> class NotifySingleListener
305 typedef void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&);
306 NotificationMethod
const m_pMethod
;
307 const EventT
& m_rEvent
;
310 NotifySingleListener(NotificationMethod method
, const EventT
& event
)
317 void operator()(const css::uno::Reference
<ListenerT
>& listener
) const
319 (listener
.get()->*m_pMethod
)(m_rEvent
);
325 inline OInterfaceContainerHelper4
<T
>::OInterfaceContainerHelper4()
326 : maData(OInterfaceContainerHelper4
<T
>::DEFAULT())
331 template <typename FuncT
>
332 inline void OInterfaceContainerHelper4
<T
>::forEach(std::unique_lock
<std::mutex
>& rGuard
,
333 FuncT
const& func
) const
335 assert(rGuard
.owns_lock());
336 if (std::as_const(maData
)->empty())
340 const_cast<OInterfaceContainerHelper4
&>(*this)
341 .maData
.make_unique(); // so we can iterate over the data without holding the lock
342 OInterfaceIteratorHelper4
<T
> iter(rGuard
, const_cast<OInterfaceContainerHelper4
&>(*this));
344 while (iter
.hasMoreElements())
346 auto xListener
= iter
.next();
351 catch (css::lang::DisposedException
const& exc
)
353 if (exc
.Context
== xListener
)
365 template <typename FuncT
, typename ExceptionFuncT
>
366 inline void OInterfaceContainerHelper4
<T
>::forEach(std::unique_lock
<std::mutex
>& rGuard
,
368 ExceptionFuncT
const& exceptionFunc
) const
370 assert(rGuard
.owns_lock());
371 if (std::as_const(maData
)->empty())
375 const_cast<OInterfaceContainerHelper4
&>(*this)
376 .maData
.make_unique(); // so we can iterate over the data without holding the lock
377 OInterfaceIteratorHelper4
<T
> iter(rGuard
, const_cast<OInterfaceContainerHelper4
&>(*this));
379 while (iter
.hasMoreElements())
381 auto xListener
= iter
.next();
386 catch (css::lang::DisposedException
const& exc
)
388 if (exc
.Context
== xListener
)
395 catch (css::uno::Exception
)
403 template <class ListenerT
>
404 template <typename EventT
>
405 inline void OInterfaceContainerHelper4
<ListenerT
>::notifyEach(
406 std::unique_lock
<std::mutex
>& rGuard
,
407 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&), const EventT
& Event
) const
409 forEach
<NotifySingleListener
<EventT
>>(rGuard
,
410 NotifySingleListener
<EventT
>(NotificationMethod
, Event
));
413 template <class ListenerT
>
414 template <typename EventT
, typename ExceptionFuncT
>
415 inline void OInterfaceContainerHelper4
<ListenerT
>::notifyEach(
416 std::unique_lock
<std::mutex
>& rGuard
,
417 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&), const EventT
& Event
,
418 const ExceptionFuncT
& exceptionFunc
) const
420 forEach
<NotifySingleListener
<EventT
>>(
421 rGuard
, NotifySingleListener
<EventT
>(NotificationMethod
, Event
), exceptionFunc
);
424 template <class ListenerT
>
426 OInterfaceContainerHelper4
<ListenerT
>::getLength(std::unique_lock
<std::mutex
>& rGuard
) const
428 assert(rGuard
.owns_lock());
430 return maData
->size();
433 template <class ListenerT
>
434 std::vector
<css::uno::Reference
<ListenerT
>>
435 OInterfaceContainerHelper4
<ListenerT
>::getElements(std::unique_lock
<std::mutex
>& rGuard
) const
437 assert(rGuard
.owns_lock());
442 template <class ListenerT
>
444 OInterfaceContainerHelper4
<ListenerT
>::addInterface(std::unique_lock
<std::mutex
>& rGuard
,
445 const css::uno::Reference
<ListenerT
>& rListener
)
447 assert(rGuard
.owns_lock());
449 assert(rListener
.is());
450 maData
->push_back(rListener
);
451 return std::as_const(maData
)->size();
454 template <class ListenerT
>
455 sal_Int32 OInterfaceContainerHelper4
<ListenerT
>::removeInterface(
456 std::unique_lock
<std::mutex
>& rGuard
, const css::uno::Reference
<ListenerT
>& rListener
)
458 assert(rGuard
.owns_lock());
460 assert(rListener
.is());
462 // It is not valid to compare the pointer directly, but it's faster.
463 auto it
= std::find_if(maData
->begin(), maData
->end(),
464 [&rListener
](const css::uno::Reference
<css::uno::XInterface
>& rItem
) {
465 return rItem
.get() == rListener
.get();
468 // interface not found, use the correct compare method
469 if (it
== maData
->end())
470 it
= std::find(maData
->begin(), maData
->end(), rListener
);
472 if (it
!= maData
->end())
475 return std::as_const(maData
)->size();
478 template <class ListenerT
>
479 void OInterfaceContainerHelper4
<ListenerT
>::disposeAndClear(std::unique_lock
<std::mutex
>& rGuard
,
480 const css::lang::EventObject
& rEvt
)
483 OInterfaceIteratorHelper4
<ListenerT
> aIt(rGuard
, *this);
485 = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector
487 // unlock followed by iterating is only safe because we are not going to call remove() on the iterator
488 while (aIt
.hasMoreElements())
492 aIt
.next()->disposing(rEvt
);
494 catch (css::uno::RuntimeException
&)
496 // be robust, if e.g. a remote bridge has disposed already.
497 // there is no way to delegate the error to the caller :o(.
501 // tdf#152077 need to destruct the OInterfaceIteratorHelper4 before we take the lock again
502 // because there is a vague chance that destructing it will trigger a call back into something
503 // that wants to take the lock.
507 template <class ListenerT
>
508 void OInterfaceContainerHelper4
<ListenerT
>::clear(::std::unique_lock
<::std::mutex
>& rGuard
)
510 assert(rGuard
.owns_lock());
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */