LibreOffice Module cppuhelper (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
40namespace cppuhelper
41{
42template <class ListenerT> class OInterfaceContainerHelper4;
51template <class ListenerT> class OInterfaceIteratorHelper4
52{
53public:
68 OInterfaceIteratorHelper4(std::unique_lock<std::mutex>& rGuard,
70 : rCont(rCont_)
72 // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator->
73 , nRemain(std::as_const(maData)->size())
74 {
75 assert(rGuard.owns_lock());
76 (void)rGuard;
77 }
78
80 bool hasMoreElements() const { return nRemain != 0; }
84 css::uno::Reference<ListenerT> const& next();
85
93 void remove(::std::unique_lock<::std::mutex>& rGuard);
94
95private:
100 sal_Int32 nRemain;
101
104};
105
106template <class ListenerT>
107const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper4<ListenerT>::next()
108{
109 nRemain--;
110 return (*std::as_const(maData))[nRemain];
111}
112
113template <class ListenerT>
114void OInterfaceIteratorHelper4<ListenerT>::remove(::std::unique_lock<::std::mutex>& rGuard)
115{
116 rCont.removeInterface(rGuard, (*std::as_const(maData))[nRemain]);
117}
118
131template <class ListenerT> class OInterfaceContainerHelper4
132{
133public:
135
142 sal_Int32 getLength(std::unique_lock<std::mutex>& rGuard) const;
143
149 std::vector<css::uno::Reference<ListenerT>>
150 getElements(std::unique_lock<std::mutex>& rGuard) const;
151
170 sal_Int32 addInterface(std::unique_lock<std::mutex>& rGuard,
171 const css::uno::Reference<ListenerT>& rxIFace);
181 sal_Int32 removeInterface(std::unique_lock<std::mutex>& rGuard,
182 const css::uno::Reference<ListenerT>& rxIFace);
188 void disposeAndClear(::std::unique_lock<::std::mutex>& rGuard,
189 const css::lang::EventObject& rEvt);
195 void clear(::std::unique_lock<::std::mutex>& rGuard);
196
209 template <typename FuncT>
210 inline void forEach(std::unique_lock<std::mutex>& rGuard, FuncT const& func) const;
211
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;
238
239 // this is moveable, but not copyable
242
243private:
244 friend class OInterfaceIteratorHelper4<ListenerT>;
250
254 {
257 SINGLETON;
258 return SINGLETON;
259 }
260
261private:
262 template <typename EventT> class NotifySingleListener
263 {
264 private:
265 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
266 NotificationMethod const m_pMethod;
267 const EventT& m_rEvent;
268
269 public:
270 NotifySingleListener(NotificationMethod method, const EventT& event)
271 : m_pMethod(method)
272 , m_rEvent(event)
273 {
274 assert(m_pMethod);
275 }
276
277 void operator()(const css::uno::Reference<ListenerT>& listener) const
278 {
279 (listener.get()->*m_pMethod)(m_rEvent);
280 }
281 };
282};
283
284template <class T>
287{
288}
289
290template <class T>
291template <typename FuncT>
292inline void OInterfaceContainerHelper4<T>::forEach(std::unique_lock<std::mutex>& rGuard,
293 FuncT const& func) const
294{
295 assert(rGuard.owns_lock());
296 if (std::as_const(maData)->size() == 0)
297 {
298 return;
299 }
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));
303 rGuard.unlock();
304 while (iter.hasMoreElements())
305 {
306 auto xListener = iter.next();
307 try
308 {
309 func(xListener);
310 }
311 catch (css::lang::DisposedException const& exc)
312 {
313 if (exc.Context == xListener)
314 {
315 rGuard.lock();
316 iter.remove(rGuard);
317 rGuard.unlock();
318 }
319 }
320 }
321 rGuard.lock();
322}
323
324template <class ListenerT>
325template <typename EventT>
327 std::unique_lock<std::mutex>& rGuard,
328 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event) const
329{
330 forEach<NotifySingleListener<EventT>>(rGuard,
331 NotifySingleListener<EventT>(NotificationMethod, Event));
332}
333
334template <class ListenerT>
335sal_Int32
336OInterfaceContainerHelper4<ListenerT>::getLength(std::unique_lock<std::mutex>& rGuard) const
337{
338 assert(rGuard.owns_lock());
339 (void)rGuard;
340 return maData->size();
341}
342
343template <class ListenerT>
344std::vector<css::uno::Reference<ListenerT>>
345OInterfaceContainerHelper4<ListenerT>::getElements(std::unique_lock<std::mutex>& rGuard) const
346{
347 assert(rGuard.owns_lock());
348 (void)rGuard;
349 return *maData;
350}
351
352template <class ListenerT>
353sal_Int32
354OInterfaceContainerHelper4<ListenerT>::addInterface(std::unique_lock<std::mutex>& rGuard,
355 const css::uno::Reference<ListenerT>& rListener)
356{
357 assert(rGuard.owns_lock());
358 (void)rGuard;
359 assert(rListener.is());
360 maData->push_back(rListener);
361 return maData->size();
362}
363
364template <class ListenerT>
366 std::unique_lock<std::mutex>& rGuard, const css::uno::Reference<ListenerT>& rListener)
367{
368 assert(rGuard.owns_lock());
369 (void)rGuard;
370 assert(rListener.is());
371
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();
376 });
377
378 // interface not found, use the correct compare method
379 if (it == maData->end())
380 it = std::find(maData->begin(), maData->end(), rListener);
381
382 if (it != maData->end())
383 maData->erase(it);
384
385 return maData->size();
386}
387
388template <class ListenerT>
389void OInterfaceContainerHelper4<ListenerT>::disposeAndClear(std::unique_lock<std::mutex>& rGuard,
390 const css::lang::EventObject& rEvt)
391{
392 {
393 OInterfaceIteratorHelper4<ListenerT> aIt(rGuard, *this);
394 maData
395 = DEFAULT(); // cheaper than calling maData->clear() because it doesn't allocate a new vector
396 rGuard.unlock();
397 // unlock followed by iterating is only safe because we are not going to call remove() on the iterator
398 while (aIt.hasMoreElements())
399 {
400 try
401 {
402 aIt.next()->disposing(rEvt);
403 }
404 catch (css::uno::RuntimeException&)
405 {
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(.
408 }
409 }
410 }
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.
414 rGuard.lock();
415}
416
417template <class ListenerT>
418void OInterfaceContainerHelper4<ListenerT>::clear(::std::unique_lock<::std::mutex>& rGuard)
419{
420 assert(rGuard.owns_lock());
421 (void)rGuard;
422 maData->clear();
423}
424}
425
426/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
NotifySingleListener(NotificationMethod method, const EventT &event)
typedef void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &)
void operator()(const css::uno::Reference< ListenerT > &listener) const
std::vector< css::uno::Reference< ListenerT > > getElements(std::unique_lock< std::mutex > &rGuard) const
Return all interfaces added to this 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 forEach(std::unique_lock< std::mutex > &rGuard, FuncT const &func) const
Executes a functor for each contained listener of specified type, e.g.
sal_Int32 getLength(std::unique_lock< std::mutex > &rGuard) const
Return the number of Elements in the container.
OInterfaceContainerHelper4(OInterfaceContainerHelper4 &&)=default
OInterfaceContainerHelper4 & operator=(const OInterfaceContainerHelper4 &)=delete
static o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > & DEFAULT()
OInterfaceContainerHelper4(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 disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
OInterfaceContainerHelper4 & operator=(OInterfaceContainerHelper4 &&)=default
o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > maData
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Removes an element from the container.
void clear(::std::unique_lock<::std::mutex > &rGuard)
Clears the container without calling disposing().
This is the iterator of an OInterfaceContainerHelper4.
OInterfaceIteratorHelper4(std::unique_lock< std::mutex > &rGuard, OInterfaceContainerHelper4< ListenerT > &rCont_)
Create an iterator over the elements of the container.
OInterfaceIteratorHelper4 & operator=(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.
o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > maData
OInterfaceIteratorHelper4(const OInterfaceIteratorHelper4 &)=delete
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
OInterfaceContainerHelper4< ListenerT > & rCont
css::uno::Reference< ListenerT > const & next()
Return the next element of the iterator.
value_type & make_unique()
std::vector< sal_Int8, boost::noinit_adaptor< std::allocator< sal_Int8 > > > maData
size
This is a straight copy of the include/comphelper/compbase.hxx file, copied here because it is nigh i...
Definition: compbase.cxx:15