LibreOffice Module comphelper (master) 1
interfacecontainer4.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19#pragma once
20
21#include <sal/config.h>
22
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>
29
30namespace com::sun::star::uno
31{
32class XInterface;
33}
34
35namespace comphelper
36{
37template <class ListenerT> class OInterfaceContainerHelper4;
46template <class ListenerT> class OInterfaceIteratorHelper4
47{
48public:
63 OInterfaceIteratorHelper4(std::unique_lock<std::mutex>& rGuard,
65 : rCont(rCont_)
67 // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator->
68 , nRemain(std::as_const(maData)->size())
69 {
70 assert(rGuard.owns_lock());
71 (void)rGuard;
72 }
73
75 bool hasMoreElements() const { return nRemain != 0; }
79 css::uno::Reference<ListenerT> const& next();
80
88 void remove(::std::unique_lock<::std::mutex>& rGuard);
89
90private:
95 sal_Int32 nRemain;
96
99};
100
101template <class ListenerT>
102const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper4<ListenerT>::next()
103{
104 nRemain--;
105 return (*std::as_const(maData))[nRemain];
106}
107
108template <class ListenerT>
109void OInterfaceIteratorHelper4<ListenerT>::remove(::std::unique_lock<::std::mutex>& rGuard)
110{
111 rCont.removeInterface(rGuard, (*std::as_const(maData))[nRemain]);
112}
113
126template <class ListenerT> class OInterfaceContainerHelper4
127{
128public:
130
137 sal_Int32 getLength(std::unique_lock<std::mutex>& rGuard) const;
138
144 std::vector<css::uno::Reference<ListenerT>>
145 getElements(std::unique_lock<std::mutex>& rGuard) const;
146
165 sal_Int32 addInterface(std::unique_lock<std::mutex>& rGuard,
166 const css::uno::Reference<ListenerT>& rxIFace);
176 sal_Int32 removeInterface(std::unique_lock<std::mutex>& rGuard,
177 const css::uno::Reference<ListenerT>& rxIFace);
183 void disposeAndClear(::std::unique_lock<::std::mutex>& rGuard,
184 const css::lang::EventObject& rEvt);
190 void clear(::std::unique_lock<::std::mutex>& rGuard);
191
204 template <typename FuncT>
205 inline void forEach(std::unique_lock<std::mutex>& rGuard, FuncT const& func) const;
206
229 template <typename EventT>
230 inline void notifyEach(std::unique_lock<std::mutex>& rGuard,
231 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
232 const EventT& Event) const;
233
234 // this is moveable, but not copyable
237
238private:
239 friend class OInterfaceIteratorHelper4<ListenerT>;
245
249 {
252 SINGLETON;
253 return SINGLETON;
254 }
255
256private:
257 template <typename EventT> class NotifySingleListener
258 {
259 private:
260 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
261 NotificationMethod const m_pMethod;
262 const EventT& m_rEvent;
263
264 public:
265 NotifySingleListener(NotificationMethod method, const EventT& event)
266 : m_pMethod(method)
267 , m_rEvent(event)
268 {
269 assert(m_pMethod);
270 }
271
272 void operator()(const css::uno::Reference<ListenerT>& listener) const
273 {
274 (listener.get()->*m_pMethod)(m_rEvent);
275 }
276 };
277};
278
279template <class T>
282{
283}
284
285template <class T>
286template <typename FuncT>
287inline void OInterfaceContainerHelper4<T>::forEach(std::unique_lock<std::mutex>& rGuard,
288 FuncT const& func) const
289{
290 assert(rGuard.owns_lock());
291 if (std::as_const(maData)->size() == 0)
292 {
293 return;
294 }
295 const_cast<OInterfaceContainerHelper4&>(*this)
296 .maData.make_unique(); // so we can iterate over the data without holding the lock
297 OInterfaceIteratorHelper4<T> iter(rGuard, const_cast<OInterfaceContainerHelper4&>(*this));
298 rGuard.unlock();
299 while (iter.hasMoreElements())
300 {
301 auto xListener = iter.next();
302 try
303 {
304 func(xListener);
305 }
306 catch (css::lang::DisposedException const& exc)
307 {
308 if (exc.Context == xListener)
309 {
310 rGuard.lock();
311 iter.remove(rGuard);
312 rGuard.unlock();
313 }
314 }
315 }
316 rGuard.lock();
317}
318
319template <class ListenerT>
320template <typename EventT>
322 std::unique_lock<std::mutex>& rGuard,
323 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event) const
324{
325 forEach<NotifySingleListener<EventT>>(rGuard,
326 NotifySingleListener<EventT>(NotificationMethod, Event));
327}
328
329template <class ListenerT>
330sal_Int32
331OInterfaceContainerHelper4<ListenerT>::getLength(std::unique_lock<std::mutex>& rGuard) const
332{
333 assert(rGuard.owns_lock());
334 (void)rGuard;
335 return maData->size();
336}
337
338template <class ListenerT>
339std::vector<css::uno::Reference<ListenerT>>
340OInterfaceContainerHelper4<ListenerT>::getElements(std::unique_lock<std::mutex>& rGuard) const
341{
342 assert(rGuard.owns_lock());
343 (void)rGuard;
344 return *maData;
345}
346
347template <class ListenerT>
348sal_Int32
349OInterfaceContainerHelper4<ListenerT>::addInterface(std::unique_lock<std::mutex>& rGuard,
350 const css::uno::Reference<ListenerT>& rListener)
351{
352 assert(rGuard.owns_lock());
353 (void)rGuard;
354 assert(rListener.is());
355 maData->push_back(rListener);
356 return maData->size();
357}
358
359template <class ListenerT>
361 std::unique_lock<std::mutex>& rGuard, const css::uno::Reference<ListenerT>& rListener)
362{
363 assert(rGuard.owns_lock());
364 (void)rGuard;
365 assert(rListener.is());
366
367 // It is not valid to compare the pointer directly, but it's faster.
368 auto it = std::find_if(maData->begin(), maData->end(),
369 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
370 return rItem.get() == rListener.get();
371 });
372
373 // interface not found, use the correct compare method
374 if (it == maData->end())
375 it = std::find(maData->begin(), maData->end(), rListener);
376
377 if (it != maData->end())
378 maData->erase(it);
379
380 return maData->size();
381}
382
383template <class ListenerT>
384void OInterfaceContainerHelper4<ListenerT>::disposeAndClear(std::unique_lock<std::mutex>& rGuard,
385 const css::lang::EventObject& rEvt)
386{
387 {
388 OInterfaceIteratorHelper4<ListenerT> aIt(rGuard, *this);
389 maData
390 = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector
391 rGuard.unlock();
392 // unlock followed by iterating is only safe because we are not going to call remove() on the iterator
393 while (aIt.hasMoreElements())
394 {
395 try
396 {
397 aIt.next()->disposing(rEvt);
398 }
399 catch (css::uno::RuntimeException&)
400 {
401 // be robust, if e.g. a remote bridge has disposed already.
402 // there is no way to delegate the error to the caller :o(.
403 }
404 }
405 }
406 // tdf#152077 need to destruct the OInterfaceIteratorHelper4 before we take the lock again
407 // because there is a vague chance that destructing it will trigger a call back into something
408 // that wants to take the lock.
409 rGuard.lock();
410}
411
412template <class ListenerT>
413void OInterfaceContainerHelper4<ListenerT>::clear(::std::unique_lock<::std::mutex>& rGuard)
414{
415 assert(rGuard.owns_lock());
416 (void)rGuard;
417 maData->clear();
418}
419}
420
421/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void operator()(const css::uno::Reference< ListenerT > &listener) const
NotifySingleListener(NotificationMethod method, const EventT &event)
typedef void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &)
void forEach(std::unique_lock< std::mutex > &rGuard, FuncT const &func) const
Executes a functor for each contained listener of specified type, e.g.
OInterfaceContainerHelper4(OInterfaceContainerHelper4 &&)=default
std::vector< css::uno::Reference< ListenerT > > getElements(std::unique_lock< std::mutex > &rGuard) const
Return all interfaces added to this container.
OInterfaceContainerHelper4 & operator=(const OInterfaceContainerHelper4 &)=delete
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Inserts an element into the container.
void notifyEach(std::unique_lock< std::mutex > &rGuard, void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &), const EventT &Event) const
Calls a UNO listener method for each contained listener.
void disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
void clear(::std::unique_lock<::std::mutex > &rGuard)
Clears the container without calling disposing().
OInterfaceContainerHelper4(const OInterfaceContainerHelper4 &)=delete
sal_Int32 getLength(std::unique_lock< std::mutex > &rGuard) const
Return the number of Elements in the container.
static o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > & DEFAULT()
OInterfaceContainerHelper4 & operator=(OInterfaceContainerHelper4 &&)=default
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Removes an element from the container.
o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > maData
This is the iterator of an OInterfaceContainerHelper4.
o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > maData
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
OInterfaceContainerHelper4< ListenerT > & rCont
OInterfaceIteratorHelper4 & operator=(const OInterfaceIteratorHelper4 &)=delete
css::uno::Reference< ListenerT > const & next()
Return the next element of the iterator.
OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4 &)=delete
void remove(::std::unique_lock<::std::mutex > &rGuard)
Removes the current element (the last one returned by next()) from the underlying container.
OInterfaceIteratorHelper4(std::unique_lock< std::mutex > &rGuard, OInterfaceContainerHelper4< ListenerT > &rCont_)
Create an iterator over the elements of the container.
value_type & make_unique()
std::vector< sal_Int8, boost::noinit_adaptor< std::allocator< sal_Int8 > > > maData
size
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept