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
36 This is a straight copy of the include/comphelper/interfacecontainer4.hxx file, copied here
37 because it is nigh impossible to move shared code down into the URE layer.
42 template <class ListenerT
> class OInterfaceContainerHelper4
;
44 This is the iterator of an OInterfaceContainerHelper4. Typically
45 one constructs an instance on the stack for one firing session.
46 It is not allowed to assign or copy an instance of this class.
48 @tparam ListenerT UNO event listener type
49 @see OInterfaceContainerHelper4
51 template <class ListenerT
> class OInterfaceIteratorHelper4
55 Create an iterator over the elements of the container. The iterator
56 copies the elements of the container. A change to the container
57 during the lifetime of an iterator is allowed and does not
58 affect the iterator-instance. The iterator and the container take cares
59 themself for concurrent access, no additional guarding is necessary.
61 Remark: The copy is on demand. The iterator copy the elements only if the container
62 change the contents...
64 @param rCont the container of the elements.
66 this parameter only here to make that this container is accessed while locked
68 OInterfaceIteratorHelper4(std::unique_lock
<std::mutex
>& rGuard
,
69 OInterfaceContainerHelper4
<ListenerT
>& rCont_
)
71 , maData(rCont
.maData
)
72 // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator->
73 , nRemain(std::as_const(maData
)->size())
75 assert(rGuard
.owns_lock());
79 /** Return true, if there are more elements in the iterator. */
80 bool hasMoreElements() const { return nRemain
!= 0; }
81 /** Return the next element of the iterator. Calling this method if
82 hasMoreElements() has returned false, is an error.
84 css::uno::Reference
<ListenerT
> const& next();
86 /** Removes the current element (the last one returned by next())
87 from the underlying container. Calling this method before
88 next() has been called or calling it twice with no next()
89 in between is an error.
91 this parameter only here to make that this container is accessed while locked
93 void remove(::std::unique_lock
<::std::mutex
>& rGuard
);
96 OInterfaceContainerHelper4
<ListenerT
>& rCont
;
97 o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
98 o3tl::ThreadSafeRefCountingPolicy
>
102 OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4
&) = delete;
103 OInterfaceIteratorHelper4
& operator=(const OInterfaceIteratorHelper4
&) = delete;
106 template <class ListenerT
>
107 const css::uno::Reference
<ListenerT
>& OInterfaceIteratorHelper4
<ListenerT
>::next()
110 return (*std::as_const(maData
))[nRemain
];
113 template <class ListenerT
>
114 void OInterfaceIteratorHelper4
<ListenerT
>::remove(::std::unique_lock
<::std::mutex
>& rGuard
)
116 rCont
.removeInterface(rGuard
, (*std::as_const(maData
))[nRemain
]);
120 A container of interfaces. To access the elements use an iterator.
121 This implementation is thread-safe.
123 This is a copy of the code at include/comphelper/interfacecontainer3.hxx,
124 except that it (a) uses std::mutex instead of osl::Mutex and (b) does not
125 store a reference to the mutex, but relies on the calling class to take
126 a lock around using it.
128 @tparam ListenerT UNO event listener type
129 @see OInterfaceIteratorHelper
131 template <class ListenerT
> class OInterfaceContainerHelper4
134 OInterfaceContainerHelper4();
137 Return the number of Elements in the container. Only useful if you have acquired
140 this parameter only here to make that this container is accessed while locked
142 sal_Int32
getLength(std::unique_lock
<std::mutex
>& rGuard
) const;
145 Return all interfaces added to this container.
147 this parameter only here to make that this container is accessed while locked
149 std::vector
<css::uno::Reference
<ListenerT
>>
150 getElements(std::unique_lock
<std::mutex
>& rGuard
) const;
152 /** Inserts an element into the container. The position is not specified, thus it is not
153 specified in which order events are fired.
156 If you add the same interface more than once, then it will be added to the elements list
157 more than once and thus if you want to remove that interface from the list, you have to call
158 removeInterface() the same number of times.
159 In the latter case, you will also get events fired more than once (if the interface is a
163 interface to be added; it is allowed to insert
164 the same interface more than once
166 this parameter only here to make that this container is accessed while locked
168 the new count of elements in the container
170 sal_Int32
addInterface(std::unique_lock
<std::mutex
>& rGuard
,
171 const css::uno::Reference
<ListenerT
>& rxIFace
);
172 /** Removes an element from the container. It uses interface equality to remove the interface.
175 interface to be removed
177 this parameter only here to make that this container is accessed while locked
179 the new count of elements in the container
181 sal_Int32
removeInterface(std::unique_lock
<std::mutex
>& rGuard
,
182 const css::uno::Reference
<ListenerT
>& rxIFace
);
184 Call disposing on all object in the container that
185 support XEventListener. Then clear the container.
186 The guard is unlock()'ed before calling the listeners.
188 void disposeAndClear(::std::unique_lock
<::std::mutex
>& rGuard
,
189 const css::lang::EventObject
& rEvt
);
191 Clears the container without calling disposing().
193 this parameter only here to make that this container is accessed while locked
195 void clear(::std::unique_lock
<::std::mutex
>& rGuard
);
197 /** Executes a functor for each contained listener of specified type, e.g.
198 <code>forEach<awt::XPaintListener>(...</code>.
200 If a css::lang::DisposedException occurs which relates to
201 the called listener, then that listener is removed from the container.
203 @tparam FuncT unary functor type, let your compiler deduce this for you
204 @param func unary functor object expecting an argument of type
205 css::uno::Reference<ListenerT>
207 this parameter only here to make that this container is accessed while locked
209 template <typename FuncT
>
210 inline void forEach(std::unique_lock
<std::mutex
>& rGuard
, FuncT
const& func
) const;
212 /** Calls a UNO listener method for each contained listener.
214 The listener method must take a single argument of type EventT,
215 and return <code>void</code>.
217 If a css::lang::DisposedException occurs which relates to
218 the called listener, then that listener is removed from the container.
220 @tparam EventT event type, let your compiler deduce this for you
221 @param NotificationMethod
222 Pointer to a method of a ListenerT interface.
224 Event to notify to all contained listeners
226 this parameter only here to make that this container is accessed while locked
230 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
231 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
234 template <typename EventT
>
235 inline void notifyEach(std::unique_lock
<std::mutex
>& rGuard
,
236 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&),
237 const EventT
& Event
) const;
239 // this is moveable, but not copyable
240 OInterfaceContainerHelper4(OInterfaceContainerHelper4
&&) = default;
241 OInterfaceContainerHelper4
& operator=(OInterfaceContainerHelper4
&&) = default;
244 friend class OInterfaceIteratorHelper4
<ListenerT
>;
245 o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
246 o3tl::ThreadSafeRefCountingPolicy
>
248 OInterfaceContainerHelper4(const OInterfaceContainerHelper4
&) = delete;
249 OInterfaceContainerHelper4
& operator=(const OInterfaceContainerHelper4
&) = delete;
251 static o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
252 o3tl::ThreadSafeRefCountingPolicy
>&
255 static o3tl::cow_wrapper
<std::vector
<css::uno::Reference
<ListenerT
>>,
256 o3tl::ThreadSafeRefCountingPolicy
>
262 template <typename EventT
> class NotifySingleListener
265 typedef void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&);
266 NotificationMethod
const m_pMethod
;
267 const EventT
& m_rEvent
;
270 NotifySingleListener(NotificationMethod method
, const EventT
& event
)
277 void operator()(const css::uno::Reference
<ListenerT
>& listener
) const
279 (listener
.get()->*m_pMethod
)(m_rEvent
);
285 inline OInterfaceContainerHelper4
<T
>::OInterfaceContainerHelper4()
286 : maData(OInterfaceContainerHelper4
<T
>::DEFAULT())
291 template <typename FuncT
>
292 inline void OInterfaceContainerHelper4
<T
>::forEach(std::unique_lock
<std::mutex
>& rGuard
,
293 FuncT
const& func
) const
295 assert(rGuard
.owns_lock());
296 if (std::as_const(maData
)->size() == 0)
300 const_cast<OInterfaceContainerHelper4
&>(*this)
301 .maData
.make_unique(); // so we can iterate over the data without holding the lock
302 OInterfaceIteratorHelper4
<T
> iter(rGuard
, const_cast<OInterfaceContainerHelper4
&>(*this));
304 while (iter
.hasMoreElements())
306 auto xListener
= iter
.next();
311 catch (css::lang::DisposedException
const& exc
)
313 if (exc
.Context
== xListener
)
324 template <class ListenerT
>
325 template <typename EventT
>
326 inline void OInterfaceContainerHelper4
<ListenerT
>::notifyEach(
327 std::unique_lock
<std::mutex
>& rGuard
,
328 void (SAL_CALL
ListenerT::*NotificationMethod
)(const EventT
&), const EventT
& Event
) const
330 forEach
<NotifySingleListener
<EventT
>>(rGuard
,
331 NotifySingleListener
<EventT
>(NotificationMethod
, Event
));
334 template <class ListenerT
>
336 OInterfaceContainerHelper4
<ListenerT
>::getLength(std::unique_lock
<std::mutex
>& rGuard
) const
338 assert(rGuard
.owns_lock());
340 return maData
->size();
343 template <class ListenerT
>
344 std::vector
<css::uno::Reference
<ListenerT
>>
345 OInterfaceContainerHelper4
<ListenerT
>::getElements(std::unique_lock
<std::mutex
>& rGuard
) const
347 assert(rGuard
.owns_lock());
352 template <class ListenerT
>
354 OInterfaceContainerHelper4
<ListenerT
>::addInterface(std::unique_lock
<std::mutex
>& rGuard
,
355 const css::uno::Reference
<ListenerT
>& rListener
)
357 assert(rGuard
.owns_lock());
359 assert(rListener
.is());
360 maData
->push_back(rListener
);
361 return std::as_const(maData
)->size();
364 template <class ListenerT
>
365 sal_Int32 OInterfaceContainerHelper4
<ListenerT
>::removeInterface(
366 std::unique_lock
<std::mutex
>& rGuard
, const css::uno::Reference
<ListenerT
>& rListener
)
368 assert(rGuard
.owns_lock());
370 assert(rListener
.is());
372 // It is not valid to compare the pointer directly, but it's faster.
373 auto it
= std::find_if(maData
->begin(), maData
->end(),
374 [&rListener
](const css::uno::Reference
<css::uno::XInterface
>& rItem
) {
375 return rItem
.get() == rListener
.get();
378 // interface not found, use the correct compare method
379 if (it
== maData
->end())
380 it
= std::find(maData
->begin(), maData
->end(), rListener
);
382 if (it
!= maData
->end())
385 return std::as_const(maData
)->size();
388 template <class ListenerT
>
389 void OInterfaceContainerHelper4
<ListenerT
>::disposeAndClear(std::unique_lock
<std::mutex
>& rGuard
,
390 const css::lang::EventObject
& rEvt
)
393 OInterfaceIteratorHelper4
<ListenerT
> aIt(rGuard
, *this);
395 = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector
397 // unlock followed by iterating is only safe because we are not going to call remove() on the iterator
398 while (aIt
.hasMoreElements())
402 aIt
.next()->disposing(rEvt
);
404 catch (css::uno::RuntimeException
&)
406 // be robust, if e.g. a remote bridge has disposed already.
407 // there is no way to delegate the error to the caller :o(.
411 // tdf#152077 need to destruct the OInterfaceIteratorHelper4 before we take the lock again
412 // because there is a vague chance that destructing it will trigger a call back into something
413 // that wants to take the lock.
417 template <class ListenerT
>
418 void OInterfaceContainerHelper4
<ListenerT
>::clear(::std::unique_lock
<::std::mutex
>& rGuard
)
420 assert(rGuard
.owns_lock());
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */