Avoid potential negative array index access to cached text.
[LibreOffice.git] / include / comphelper / interfacecontainer3.hxx
blobbe140d32289f77852444a8366fdb92f7a39ee760
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 <vector>
28 namespace com::sun::star::uno
30 class XInterface;
32 namespace osl
34 class Mutex;
37 namespace comphelper
39 template <class ListenerT> class OInterfaceContainerHelper3;
40 /**
41 This is the iterator of an OInterfaceContainerHelper3. Typically
42 one constructs an instance on the stack for one firing session.
43 It is not allowed to assign or copy an instance of this class.
45 @tparam ListenerT UNO event listener type
46 @see OInterfaceContainerHelper3
48 template <class ListenerT> class OInterfaceIteratorHelper3
50 public:
51 /**
52 Create an iterator over the elements of the container. The iterator
53 copies the elements of the container. A change to the container
54 during the lifetime of an iterator is allowed and does not
55 affect the iterator-instance. The iterator and the container take cares
56 themself for concurrent access, no additional guarding is necessary.
58 Remark: The copy is on demand. The iterator copy the elements only if the container
59 change the contents...
61 @param rCont the container of the elements.
63 OInterfaceIteratorHelper3(OInterfaceContainerHelper3<ListenerT>& rCont_)
64 : rCont(rCont_)
65 , maData(rCont.maData)
66 // const_cast so we don't trigger make_unique via o3tl::cow_wrapper::operator->
67 , nRemain(std::as_const(maData)->size())
71 /** Return true, if there are more elements in the iterator. */
72 bool hasMoreElements() const { return nRemain != 0; }
73 /** Return the next element of the iterator. Calling this method if
74 hasMoreElements() has returned false, is an error.
76 css::uno::Reference<ListenerT> const& next();
78 /** Removes the current element (the last one returned by next())
79 from the underlying container. Calling this method before
80 next() has been called or calling it twice with no next()
81 in between is an error.
83 void remove();
85 private:
86 OInterfaceContainerHelper3<ListenerT>& rCont;
87 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
88 o3tl::ThreadSafeRefCountingPolicy>
89 maData;
90 sal_Int32 nRemain;
92 OInterfaceIteratorHelper3(const OInterfaceIteratorHelper3&) = delete;
93 OInterfaceIteratorHelper3& operator=(const OInterfaceIteratorHelper3&) = delete;
96 template <class ListenerT>
97 const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper3<ListenerT>::next()
99 nRemain--;
100 return (*std::as_const(maData))[nRemain];
103 template <class ListenerT> void OInterfaceIteratorHelper3<ListenerT>::remove()
105 rCont.removeInterface((*std::as_const(maData))[nRemain]);
109 A container of interfaces. To access the elements use an iterator.
110 This implementation is thread-safe.
112 This is a copy of the code at include/comphelper/interfacecontainer2.hxx,
113 except that it is templatized on the type of the listener, which allows
114 some parts of the code to avoid doing an UNO_QUERY that can be expensive
115 in bulk.
117 @tparam ListenerT UNO event listener type
118 @see OInterfaceIteratorHelper
120 template <class ListenerT> class OInterfaceContainerHelper3
122 public:
124 Create an interface container.
126 @param rMutex the mutex to protect multi thread access.
127 The lifetime must be longer than the lifetime
128 of this object.
130 inline OInterfaceContainerHelper3(::osl::Mutex& rMutex_);
133 Return the number of Elements in the container. Only useful if you have acquired
134 the mutex.
136 sal_Int32 getLength() const;
139 Return all interfaces added to this container.
141 std::vector<css::uno::Reference<ListenerT>> getElements() const;
143 /** Inserts an element into the container. The position is not specified, thus it is not
144 specified in which order events are fired.
146 @attention
147 If you add the same interface more than once, then it will be added to the elements list
148 more than once and thus if you want to remove that interface from the list, you have to call
149 removeInterface() the same number of times.
150 In the latter case, you will also get events fired more than once (if the interface is a
151 listener interface).
153 @param rxIFace
154 interface to be added; it is allowed to insert
155 the same interface more than once
156 @return
157 the new count of elements in the container
159 sal_Int32 addInterface(const css::uno::Reference<ListenerT>& rxIFace);
160 /** Removes an element from the container. It uses interface equality to remove the interface.
162 @param rxIFace
163 interface to be removed
164 @return
165 the new count of elements in the container
167 sal_Int32 removeInterface(const css::uno::Reference<ListenerT>& rxIFace);
168 /** Return an interface by index
170 const css::uno::Reference<ListenerT>& getInterface(sal_Int32 nIndex) const;
172 Call disposing on all object in the container that
173 support XEventListener. Then clear the container.
175 void disposeAndClear(const css::lang::EventObject& rEvt);
177 Clears the container without calling disposing().
179 void clear();
181 /** Executes a functor for each contained listener of specified type, e.g.
182 <code>forEach<awt::XPaintListener>(...</code>.
184 If a css::lang::DisposedException occurs which relates to
185 the called listener, then that listener is removed from the container.
187 @tparam FuncT unary functor type, let your compiler deduce this for you
188 @param func unary functor object expecting an argument of type
189 css::uno::Reference<ListenerT>
191 template <typename FuncT> inline void forEach(FuncT const& func);
193 /** Calls a UNO listener method for each contained listener.
195 The listener method must take a single argument of type EventT,
196 and return <code>void</code>.
198 If a css::lang::DisposedException occurs which relates to
199 the called listener, then that listener is removed from the container.
201 @tparam EventT event type, let your compiler deduce this for you
202 @param NotificationMethod
203 Pointer to a method of a ListenerT interface.
204 @param Event
205 Event to notify to all contained listeners
207 Example:
208 @code
209 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
210 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
211 @endcode
213 template <typename EventT>
214 inline void notifyEach(void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
215 const EventT& Event);
217 private:
218 friend class OInterfaceIteratorHelper3<ListenerT>;
219 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
220 o3tl::ThreadSafeRefCountingPolicy>
221 maData;
222 ::osl::Mutex& mrMutex;
223 OInterfaceContainerHelper3(const OInterfaceContainerHelper3&) = delete;
224 OInterfaceContainerHelper3& operator=(const OInterfaceContainerHelper3&) = delete;
226 static o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
227 o3tl::ThreadSafeRefCountingPolicy>&
228 DEFAULT()
230 static o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>,
231 o3tl::ThreadSafeRefCountingPolicy>
232 SINGLETON;
233 return SINGLETON;
236 private:
237 template <typename EventT> class NotifySingleListener
239 private:
240 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
241 NotificationMethod const m_pMethod;
242 const EventT& m_rEvent;
244 public:
245 NotifySingleListener(NotificationMethod method, const EventT& event)
246 : m_pMethod(method)
247 , m_rEvent(event)
251 void operator()(const css::uno::Reference<ListenerT>& listener) const
253 (listener.get()->*m_pMethod)(m_rEvent);
258 template <class T>
259 inline OInterfaceContainerHelper3<T>::OInterfaceContainerHelper3(::osl::Mutex& rMutex_)
260 : maData(OInterfaceContainerHelper3<T>::DEFAULT())
261 , mrMutex(rMutex_)
265 template <class T>
266 template <typename FuncT>
267 inline void OInterfaceContainerHelper3<T>::forEach(FuncT const& func)
269 osl::ClearableMutexGuard aGuard(mrMutex);
270 if (std::as_const(maData)->empty())
271 return;
272 OInterfaceIteratorHelper3<T> iter(*this);
273 aGuard.clear();
274 while (iter.hasMoreElements())
276 auto xListener = iter.next();
279 func(xListener);
281 catch (css::lang::DisposedException const& exc)
283 if (exc.Context == xListener)
284 iter.remove();
289 template <class ListenerT>
290 template <typename EventT>
291 inline void OInterfaceContainerHelper3<ListenerT>::notifyEach(
292 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event)
294 forEach<NotifySingleListener<EventT>>(NotifySingleListener<EventT>(NotificationMethod, Event));
297 template <class ListenerT> sal_Int32 OInterfaceContainerHelper3<ListenerT>::getLength() const
299 osl::MutexGuard aGuard(mrMutex);
300 return maData->size();
303 template <class ListenerT>
304 std::vector<css::uno::Reference<ListenerT>>
305 OInterfaceContainerHelper3<ListenerT>::getElements() const
307 std::vector<css::uno::Reference<ListenerT>> rVec;
308 osl::MutexGuard aGuard(mrMutex);
309 rVec = *maData;
310 return rVec;
313 template <class ListenerT>
314 sal_Int32
315 OInterfaceContainerHelper3<ListenerT>::addInterface(const css::uno::Reference<ListenerT>& rListener)
317 assert(rListener.is());
318 osl::MutexGuard aGuard(mrMutex);
320 maData->push_back(rListener);
321 return std::as_const(maData)->size();
324 template <class ListenerT>
325 sal_Int32 OInterfaceContainerHelper3<ListenerT>::removeInterface(
326 const css::uno::Reference<ListenerT>& rListener)
328 assert(rListener.is());
329 osl::MutexGuard aGuard(mrMutex);
331 // It is not valid to compare the pointer directly, but it's faster.
332 auto it = std::find_if(maData->begin(), maData->end(),
333 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
334 return rItem.get() == rListener.get();
337 // interface not found, use the correct compare method
338 if (it == maData->end())
339 it = std::find(maData->begin(), maData->end(), rListener);
341 if (it != maData->end())
342 maData->erase(it);
344 return std::as_const(maData)->size();
347 template <class ListenerT>
348 const css::uno::Reference<ListenerT>&
349 OInterfaceContainerHelper3<ListenerT>::getInterface(sal_Int32 nIndex) const
351 osl::MutexGuard aGuard(mrMutex);
353 return (*maData)[nIndex];
356 template <class ListenerT>
357 void OInterfaceContainerHelper3<ListenerT>::disposeAndClear(const css::lang::EventObject& rEvt)
359 osl::ClearableMutexGuard aGuard(mrMutex);
360 OInterfaceIteratorHelper3<ListenerT> aIt(*this);
361 maData->clear();
362 aGuard.clear();
363 while (aIt.hasMoreElements())
367 aIt.next()->disposing(rEvt);
369 catch (css::uno::RuntimeException&)
371 // be robust, if e.g. a remote bridge has disposed already.
372 // there is no way to delegate the error to the caller :o(.
377 template <class ListenerT> void OInterfaceContainerHelper3<ListenerT>::clear()
379 osl::MutexGuard aGuard(mrMutex);
380 maData->clear();
384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */