tdf#162786, tdf#161947: Add support for setuptools and pip
[LibreOffice.git] / include / comphelper / interfacecontainer4.hxx
blobc23c04c76018f98647651ee3a56baccc66c6858a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
19 #pragma once
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>
26 #include <cassert>
27 #include <mutex>
28 #include <vector>
30 namespace com::sun::star::uno
32 class XInterface;
35 namespace comphelper
37 template <class ListenerT> class OInterfaceContainerHelper4;
38 /**
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
48 public:
49 /**
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.
60 @param rGuard
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_)
65 : rCont(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());
71 (void)rGuard;
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.
85 @param rGuard
86 this parameter only here to make that this container is accessed while locked
88 void remove(::std::unique_lock<::std::mutex>& rGuard);
90 private:
91 OInterfaceContainerHelper4<ListenerT>& rCont;
92 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
93 o3tl::ThreadSafeRefCountingPolicy>
94 maData;
95 sal_Int32 nRemain;
97 OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4&) = delete;
98 OInterfaceIteratorHelper4& operator=(const OInterfaceIteratorHelper4&) = delete;
101 template <class ListenerT>
102 const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper4<ListenerT>::next()
104 nRemain--;
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
128 public:
129 OInterfaceContainerHelper4();
132 Return the number of Elements in the container. Only useful if you have acquired
133 the mutex.
134 @param rGuard
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.
141 @param rGuard
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.
150 @attention
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
155 listener interface).
157 @param rxIFace
158 interface to be added; it is allowed to insert
159 the same interface more than once
160 @param rGuard
161 this parameter only here to make that this container is accessed while locked
162 @return
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.
169 @param rxIFace
170 interface to be removed
171 @param rGuard
172 this parameter only here to make that this container is accessed while locked
173 @return
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().
187 @param rGuard
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>
201 @param rGuard
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
220 @param rGuard
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.
238 @param Event
239 Event to notify to all contained listeners
240 @param rGuard
241 this parameter only here to make that this container is accessed while locked
243 Example:
244 @code
245 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
246 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
247 @endcode
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.
268 @param Event
269 Event to notify to all contained listeners
270 @param exceptionFunc nullary functor object
271 @param rGuard
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;
283 private:
284 friend class OInterfaceIteratorHelper4<ListenerT>;
285 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
286 o3tl::ThreadSafeRefCountingPolicy>
287 maData;
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>&
293 DEFAULT()
295 static o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
296 o3tl::ThreadSafeRefCountingPolicy>
297 SINGLETON;
298 return SINGLETON;
301 private:
302 template <typename EventT> class NotifySingleListener
304 private:
305 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
306 NotificationMethod const m_pMethod;
307 const EventT& m_rEvent;
309 public:
310 NotifySingleListener(NotificationMethod method, const EventT& event)
311 : m_pMethod(method)
312 , m_rEvent(event)
314 assert(m_pMethod);
317 void operator()(const css::uno::Reference<ListenerT>& listener) const
319 (listener.get()->*m_pMethod)(m_rEvent);
324 template <class T>
325 inline OInterfaceContainerHelper4<T>::OInterfaceContainerHelper4()
326 : maData(OInterfaceContainerHelper4<T>::DEFAULT())
330 template <class T>
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())
338 return;
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));
343 rGuard.unlock();
344 while (iter.hasMoreElements())
346 auto xListener = iter.next();
349 func(xListener);
351 catch (css::lang::DisposedException const& exc)
353 if (exc.Context == xListener)
355 rGuard.lock();
356 iter.remove(rGuard);
357 rGuard.unlock();
361 rGuard.lock();
364 template <class T>
365 template <typename FuncT, typename ExceptionFuncT>
366 inline void OInterfaceContainerHelper4<T>::forEach(std::unique_lock<std::mutex>& rGuard,
367 FuncT const& func,
368 ExceptionFuncT const& exceptionFunc) const
370 assert(rGuard.owns_lock());
371 if (std::as_const(maData)->empty())
373 return;
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));
378 rGuard.unlock();
379 while (iter.hasMoreElements())
381 auto xListener = iter.next();
384 func(xListener);
386 catch (css::lang::DisposedException const& exc)
388 if (exc.Context == xListener)
390 rGuard.lock();
391 iter.remove(rGuard);
392 rGuard.unlock();
395 catch (css::uno::Exception)
397 exceptionFunc();
400 rGuard.lock();
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>
425 sal_Int32
426 OInterfaceContainerHelper4<ListenerT>::getLength(std::unique_lock<std::mutex>& rGuard) const
428 assert(rGuard.owns_lock());
429 (void)rGuard;
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());
438 (void)rGuard;
439 return *maData;
442 template <class ListenerT>
443 sal_Int32
444 OInterfaceContainerHelper4<ListenerT>::addInterface(std::unique_lock<std::mutex>& rGuard,
445 const css::uno::Reference<ListenerT>& rListener)
447 assert(rGuard.owns_lock());
448 (void)rGuard;
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());
459 (void)rGuard;
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())
473 maData->erase(it);
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);
484 maData
485 = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector
486 rGuard.unlock();
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.
504 rGuard.lock();
507 template <class ListenerT>
508 void OInterfaceContainerHelper4<ListenerT>::clear(::std::unique_lock<::std::mutex>& rGuard)
510 assert(rGuard.owns_lock());
511 (void)rGuard;
512 maData->clear();
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */