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 }
71
73 bool hasMoreElements() const { return nRemain != 0; }
77 css::uno::Reference<ListenerT> const& next();
78
86 void remove(::std::unique_lock<::std::mutex>& rGuard);
87
88private:
93 sal_Int32 nRemain;
94
97};
98
99template <class ListenerT>
100const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper4<ListenerT>::next()
101{
102 nRemain--;
103 return (*std::as_const(maData))[nRemain];
104}
105
106template <class ListenerT>
107void OInterfaceIteratorHelper4<ListenerT>::remove(::std::unique_lock<::std::mutex>& rGuard)
108{
109 rCont.removeInterface(rGuard, (*std::as_const(maData))[nRemain]);
110}
111
124template <class ListenerT> class OInterfaceContainerHelper4
125{
126public:
128
135 sal_Int32 getLength(std::unique_lock<std::mutex>& rGuard) const;
136
142 std::vector<css::uno::Reference<ListenerT>>
143 getElements(std::unique_lock<std::mutex>& rGuard) const;
144
163 sal_Int32 addInterface(std::unique_lock<std::mutex>& rGuard,
164 const css::uno::Reference<ListenerT>& rxIFace);
174 sal_Int32 removeInterface(std::unique_lock<std::mutex>& rGuard,
175 const css::uno::Reference<ListenerT>& rxIFace);
181 void disposeAndClear(::std::unique_lock<::std::mutex>& rGuard,
182 const css::lang::EventObject& rEvt);
188 void clear(::std::unique_lock<::std::mutex>& rGuard);
189
202 template <typename FuncT>
203 inline void forEach(std::unique_lock<std::mutex>& rGuard, FuncT const& func);
204
227 template <typename EventT>
228 inline void notifyEach(std::unique_lock<std::mutex>& rGuard,
229 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
230 const EventT& Event);
231
232private:
233 friend class OInterfaceIteratorHelper4<ListenerT>;
239
243 {
246 SINGLETON;
247 return SINGLETON;
248 }
249
250private:
251 template <typename EventT> class NotifySingleListener
252 {
253 private:
254 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
255 NotificationMethod const m_pMethod;
256 const EventT& m_rEvent;
257
258 public:
259 NotifySingleListener(NotificationMethod method, const EventT& event)
260 : m_pMethod(method)
261 , m_rEvent(event)
262 {
263 assert(m_pMethod);
264 }
265
266 void operator()(const css::uno::Reference<ListenerT>& listener) const
267 {
268 (listener.get()->*m_pMethod)(m_rEvent);
269 }
270 };
271};
272
273template <class T>
276{
277}
278
279template <class T>
280template <typename FuncT>
281inline void OInterfaceContainerHelper4<T>::forEach(std::unique_lock<std::mutex>& rGuard,
282 FuncT const& func)
283{
284 if (std::as_const(maData)->size() == 0)
285 {
286 return;
287 }
288 maData.make_unique(); // so we can iterate over the data without holding the lock
289 OInterfaceIteratorHelper4<T> iter(rGuard, *this);
290 rGuard.unlock();
291 while (iter.hasMoreElements())
292 {
293 auto xListener = iter.next();
294 try
295 {
296 func(xListener);
297 }
298 catch (css::lang::DisposedException const& exc)
299 {
300 if (exc.Context == xListener)
301 {
302 rGuard.lock();
303 iter.remove(rGuard);
304 rGuard.unlock();
305 }
306 }
307 }
308 rGuard.lock();
309}
310
311template <class ListenerT>
312template <typename EventT>
314 std::unique_lock<std::mutex>& rGuard,
315 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event)
316{
317 forEach<NotifySingleListener<EventT>>(rGuard,
318 NotifySingleListener<EventT>(NotificationMethod, Event));
319}
320
321template <class ListenerT>
322sal_Int32
323OInterfaceContainerHelper4<ListenerT>::getLength(std::unique_lock<std::mutex>& /*rGuard*/) const
324{
325 return maData->size();
326}
327
328template <class ListenerT>
329std::vector<css::uno::Reference<ListenerT>>
330OInterfaceContainerHelper4<ListenerT>::getElements(std::unique_lock<std::mutex>& /*rGuard*/) const
331{
332 return *maData;
333}
334
335template <class ListenerT>
336sal_Int32
337OInterfaceContainerHelper4<ListenerT>::addInterface(std::unique_lock<std::mutex>& /*rGuard*/,
338 const css::uno::Reference<ListenerT>& rListener)
339{
340 assert(rListener.is());
341 maData->push_back(rListener);
342 return maData->size();
343}
344
345template <class ListenerT>
347 std::unique_lock<std::mutex>& /*rGuard*/, const css::uno::Reference<ListenerT>& rListener)
348{
349 assert(rListener.is());
350
351 // It is not valid to compare the pointer directly, but it's faster.
352 auto it = std::find_if(maData->begin(), maData->end(),
353 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
354 return rItem.get() == rListener.get();
355 });
356
357 // interface not found, use the correct compare method
358 if (it == maData->end())
359 it = std::find(maData->begin(), maData->end(), rListener);
360
361 if (it != maData->end())
362 maData->erase(it);
363
364 return maData->size();
365}
366
367template <class ListenerT>
368void OInterfaceContainerHelper4<ListenerT>::disposeAndClear(std::unique_lock<std::mutex>& rGuard,
369 const css::lang::EventObject& rEvt)
370{
371 OInterfaceIteratorHelper4<ListenerT> aIt(rGuard, *this);
372 maData->clear();
373 rGuard.unlock();
374 // unlock followed by iterating is only safe because we are not going to call remove() on the iterator
375 while (aIt.hasMoreElements())
376 {
377 try
378 {
379 aIt.next()->disposing(rEvt);
380 }
381 catch (css::uno::RuntimeException&)
382 {
383 // be robust, if e.g. a remote bridge has disposed already.
384 // there is no way to delegate the error to the caller :o(.
385 }
386 }
387 rGuard.lock();
388}
389
390template <class ListenerT>
391void OInterfaceContainerHelper4<ListenerT>::clear(::std::unique_lock<::std::mutex>& /*rGuard*/)
392{
393 maData->clear();
394}
395}
396
397/* 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 &)
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
void notifyEach(std::unique_lock< std::mutex > &rGuard, void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &), const EventT &Event)
Calls a UNO listener method for each contained listener.
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Inserts an element into the container.
void forEach(std::unique_lock< std::mutex > &rGuard, FuncT const &func)
Executes a functor for each contained listener of specified type, e.g.
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()
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 > &, OInterfaceContainerHelper4< ListenerT > &rCont_)
Create an iterator over the elements of the container.
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