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
20 /*
21 * This file is part of LibreOffice published API.
22 */
23 #ifndef INCLUDED_CPPUHELPER_INTERFACECONTAINER_H
24 #define INCLUDED_CPPUHELPER_INTERFACECONTAINER_H
25
26 #include "sal/config.h"
27
28 #include <cstddef>
29 #include <functional>
30 #include <vector>
31 #include <utility>
32
33 #include "osl/diagnose.h"
34 #include "osl/mutex.hxx"
35 #include "rtl/alloc.h"
36 #include "com/sun/star/uno/Sequence.hxx"
37 #include "com/sun/star/lang/EventObject.hpp"
38
39 #include "com/sun/star/lang/DisposedException.hpp"
40 #include "cppuhelper/cppuhelperdllapi.h"
41
42 namespace com { namespace sun { namespace star { namespace uno { class XInterface; } } } }
43
44 /** */ //for docpp
45 namespace cppu
46 {
47
48 namespace detail {
49
50 /**
51 This is here to optimise space in the common case that there are zero or one
52 listeners.
53 */
54 union element_alias
55 {
56 std::vector< css::uno::Reference< css::uno::XInterface > > *pAsVector;
57 css::uno::XInterface * pAsInterface;
element_alias()58 element_alias() : pAsInterface(NULL) {}
59 };
60
61 }
62
63
64 class OInterfaceContainerHelper;
65 /**
66 This is the iterator of an InterfaceContainerHelper. Typically
67 one constructs an instance on the stack for one firing session.
68 It is not allowed to assign or copy an instance of this class.
69
70 @see OInterfaceContainerHelper
71 */
72 class CPPUHELPER_DLLPUBLIC OInterfaceIteratorHelper
73 {
74 public:
75 /**
76 Create an iterator over the elements of the container. The iterator
77 copies the elements of the container. A change to the container
78 during the lifetime of an iterator is allowed and does not
79 affect the iterator-instance. The iterator and the container take cares
80 themself for concurrent access, no additional guarding is necessary.
81
82 Remark: The copy is on demand. The iterator copy the elements only if the container
83 change the contents. It is not allowed to destroy the container as long
84 as an iterator exist.
85
86 @param rCont the container of the elements.
87 */
88 OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont );
89
90 /**
91 Releases the connection to the container.
92 */
93 ~OInterfaceIteratorHelper();
94
95 /** Return true, if there are more elements in the iterator. */
hasMoreElements()96 bool SAL_CALL hasMoreElements() const
97 { return nRemain != 0; }
98 /** Return the next element of the iterator. Calling this method if
99 hasMoreElements() has returned false, is an error. Cast the
100 returned pointer to the
101 */
102 css::uno::XInterface * SAL_CALL next();
103
104 /** Removes the current element (the last one returned by next())
105 from the underlying container. Calling this method before
106 next() has been called or calling it twice with no next()
107 inbetween is an error.
108 */
109 void SAL_CALL remove();
110
111 private:
112 OInterfaceContainerHelper & rCont;
113 sal_Bool bIsList;
114
115 detail::element_alias aData;
116
117 sal_Int32 nRemain;
118
119 OInterfaceIteratorHelper( const OInterfaceIteratorHelper & )
120 SAL_DELETED_FUNCTION;
121 OInterfaceIteratorHelper & operator = ( const OInterfaceIteratorHelper & )
122 SAL_DELETED_FUNCTION;
123 };
124
125
126 /**
127 A container of interfaces. To access the elements use an iterator.
128 This implementation is thread save.
129
130 @see OInterfaceIteratorHelper
131 */
132 class SAL_WARN_UNUSED CPPUHELPER_DLLPUBLIC OInterfaceContainerHelper
133 {
134 public:
135 // these are here to force memory de/allocation to sal lib.
new(size_t nSize)136 static void * SAL_CALL operator new( size_t nSize )
137 { return ::rtl_allocateMemory( nSize ); }
delete(void * pMem)138 static void SAL_CALL operator delete( void * pMem )
139 { ::rtl_freeMemory( pMem ); }
new(size_t,void * pMem)140 static void * SAL_CALL operator new( size_t, void * pMem )
141 { return pMem; }
delete(void *,void *)142 static void SAL_CALL operator delete( void *, void * )
143 {}
144
145 /**
146 Create an interface container.
147
148 @param rMutex the mutex to protect multi thread access.
149 The lifetime must be longer than the lifetime
150 of this object.
151 */
152 OInterfaceContainerHelper( ::osl::Mutex & rMutex );
153 /**
154 Release all interfaces. All iterators must be destroyed before
155 the container is destructed.
156 */
157 ~OInterfaceContainerHelper();
158 /**
159 Return the number of Elements in the container. Only useful if you have acquired
160 the mutex.
161 */
162 sal_Int32 SAL_CALL getLength() const;
163
164 /**
165 Return all interfaces added to this container.
166 **/
167 css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > SAL_CALL getElements() const;
168
169 /** Inserts an element into the container. The position is not specified, thus it is not
170 specified in which order events are fired.
171
172 @attention
173 If you add the same interface more than once, then it will be added to the elements list
174 more than once and thus if you want to remove that interface from the list, you have to call
175 removeInterface() the same number of times.
176 In the latter case, you will also get events fired more than once (if the interface is a
177 listener interface).
178
179 @param rxIFace
180 interface to be added; it is allowed to insert null or
181 the same interface more than once
182 @return
183 the new count of elements in the container
184 */
185 sal_Int32 SAL_CALL addInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
186 /** Removes an element from the container. It uses interface equality to remove the interface.
187
188 @param rxIFace
189 interface to be removed
190 @return
191 the new count of elements in the container
192 */
193 sal_Int32 SAL_CALL removeInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
194 /**
195 Call disposing on all object in the container that
196 support XEventListener. Then clear the container.
197 */
198 void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
199 /**
200 Clears the container without calling disposing().
201 */
202 void SAL_CALL clear();
203
204 /** Executes a functor for each contained listener of specified type, e.g.
205 <code>forEach<awt::XPaintListener>(...</code>.
206
207 If a css::lang::DisposedException occurs which relates to
208 the called listener, then that listener is removed from the container.
209
210 @tparam ListenerT listener type
211 @tparam FuncT unary functor type, let your compiler deduce this for you
212 @param func unary functor object expecting an argument of type
213 css::uno::Reference<ListenerT>
214 */
215 template <typename ListenerT, typename FuncT>
216 inline void forEach( FuncT const& func );
217
218 /** Calls a UNO listener method for each contained listener.
219
220 The listener method must take a single argument of type EventT,
221 and return <code>void</code>.
222
223 If a css::lang::DisposedException occurs which relates to
224 the called listener, then that listener is removed from the container.
225
226 @tparam ListenerT UNO event listener type, let your compiler deduce this for you
227 @tparam EventT event type, let your compiler deduce this for you
228 @param NotificationMethod
229 Pointer to a method of a ListenerT interface.
230 @param Event
231 Event to notify to all contained listeners
232
233 Example:
234 @code
235 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
236 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
237 @endcode
238 */
239 template< typename ListenerT, typename EventT >
240 inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event );
241
242 private:
243 friend class OInterfaceIteratorHelper;
244 /**
245 bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >,
246 otherwise aData.pAsInterface == of type (XEventListener *)
247 */
248 detail::element_alias aData;
249 ::osl::Mutex & rMutex;
250 /** TRUE -> used by an iterator. */
251 sal_Bool bInUse;
252 /** TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >. */
253 sal_Bool bIsList;
254
255 OInterfaceContainerHelper( const OInterfaceContainerHelper & )
256 SAL_DELETED_FUNCTION;
257 OInterfaceContainerHelper & operator = ( const OInterfaceContainerHelper & )
258 SAL_DELETED_FUNCTION;
259
260 /*
261 Duplicate content of the container and release the old one without destroying.
262 The mutex must be locked and the memberbInUse must be true.
263 */
264 void copyAndResetInUse();
265
266 private:
267 template< typename ListenerT, typename EventT >
268 class NotifySingleListener
269 {
270 private:
271 typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
272 NotificationMethod m_pMethod;
273 const EventT& m_rEvent;
274 public:
NotifySingleListener(NotificationMethod method,const EventT & event)275 NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
276
operator()277 void operator()( const css::uno::Reference<ListenerT>& listener ) const
278 {
279 (listener.get()->*m_pMethod)( m_rEvent );
280 }
281 };
282 };
283
284 template <typename ListenerT, typename FuncT>
forEach(FuncT const & func)285 inline void OInterfaceContainerHelper::forEach( FuncT const& func )
286 {
287 OInterfaceIteratorHelper iter( *this );
288 while (iter.hasMoreElements()) {
289 css::uno::Reference<ListenerT> const xListener( iter.next(), css::uno::UNO_QUERY );
290 if (xListener.is()) {
291 try {
292 func( xListener );
293 }
294 catch (css::lang::DisposedException const& exc) {
295 if (exc.Context == xListener)
296 iter.remove();
297 }
298 }
299 }
300 }
301
302 template< typename ListenerT, typename EventT >
notifyEach(void (SAL_CALL ListenerT::* NotificationMethod)(const EventT &),const EventT & Event)303 inline void OInterfaceContainerHelper::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event )
304 {
305 forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) );
306 }
307
308
309 /**
310 A helper class to store interface references of different types.
311
312 @see OInterfaceIteratorHelper
313 @see OInterfaceContainerHelper
314 */
315 template< class key, class hashImpl = void, class equalImpl = std::equal_to<key> >
316 class OMultiTypeInterfaceContainerHelperVar
317 {
318 public:
319 // these are here to force memory de/allocation to sal lib.
new(size_t nSize)320 static void * SAL_CALL operator new( size_t nSize )
321 { return ::rtl_allocateMemory( nSize ); }
delete(void * pMem)322 static void SAL_CALL operator delete( void * pMem )
323 { ::rtl_freeMemory( pMem ); }
new(size_t,void * pMem)324 static void * SAL_CALL operator new( size_t, void * pMem )
325 { return pMem; }
delete(void *,void *)326 static void SAL_CALL operator delete( void *, void * )
327 {}
328
329 /**
330 Create a container of interface containers.
331
332 @param rMutex the mutex to protect multi thread access.
333 The lifetime must be longer than the lifetime
334 of this object.
335 */
336 inline OMultiTypeInterfaceContainerHelperVar( ::osl::Mutex & rMutex );
337 /**
338 Deletes all containers.
339 */
340 inline ~OMultiTypeInterfaceContainerHelperVar();
341
342 /**
343 Return all id's under which at least one interface is added.
344 */
345 inline css::uno::Sequence< key > SAL_CALL getContainedTypes() const;
346
347 /**
348 Return the container created under this key.
349 The InterfaceContainerHelper exists until the whole MultiTypeContainer is destroyed.
350 @return the container created under this key. If the container
351 was not created, null was returned.
352 */
353 inline OInterfaceContainerHelper * SAL_CALL getContainer( const key & ) const;
354
355 /** Inserts an element into the container with the specified key.
356 The position is not specified, thus it is not specified in which order events are fired.
357
358 @attention
359 If you add the same interface more than once, then it will be added to the elements list
360 more than once and thus if you want to remove that interface from the list, you have to call
361 removeInterface() the same number of times.
362 In the latter case, you will also get events fired more than once (if the interface is a
363 listener interface).
364
365 @param rKey
366 the id of the container
367 @param r
368 interface to be added; it is allowed, to insert null or
369 the same interface more than once
370 @return
371 the new count of elements in the container
372 */
373 inline sal_Int32 SAL_CALL addInterface(
374 const key & rKey,
375 const css::uno::Reference< css::uno::XInterface > & r );
376
377 /** Removes an element from the container with the specified key.
378 It uses interface equality to remove the interface.
379
380 @param rKey
381 the id of the container
382 @param rxIFace
383 interface to be removed
384 @return
385 the new count of elements in the container
386 */
387 inline sal_Int32 SAL_CALL removeInterface(
388 const key & rKey,
389 const css::uno::Reference< css::uno::XInterface > & rxIFace );
390
391 /**
392 Call disposing on all references in the container, that
393 support XEventListener. Then clears the container.
394 @param rEvt the event object which is passed during disposing() call
395 */
396 inline void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
397 /**
398 Remove all elements of all containers. Does not delete the container.
399 */
400 inline void SAL_CALL clear();
401
402 typedef key keyType;
403 private:
404 typedef ::std::vector< std::pair < key , void* > > InterfaceMap;
405 InterfaceMap *m_pMap;
406 ::osl::Mutex & rMutex;
407
find(const key & rKey)408 typename InterfaceMap::iterator find(const key &rKey) const
409 {
410 typename InterfaceMap::iterator iter = m_pMap->begin();
411 typename InterfaceMap::iterator end = m_pMap->end();
412
413 while( iter != end )
414 {
415 equalImpl equal;
416 if( equal( iter->first, rKey ) )
417 break;
418 ++iter;
419 }
420 return iter;
421 }
422
423 OMultiTypeInterfaceContainerHelperVar( const OMultiTypeInterfaceContainerHelperVar & ) SAL_DELETED_FUNCTION;
424 OMultiTypeInterfaceContainerHelperVar & operator = ( const OMultiTypeInterfaceContainerHelperVar & ) SAL_DELETED_FUNCTION;
425 };
426
427
428
429
430 /**
431 This struct contains the standard variables of a broadcaster. Helper
432 classes only know a reference to this struct instead of references
433 to the four members. The access to the members must be guarded with
434 rMutex.
435
436 The additional template parameter keyType has been added, because gcc
437 can't compile addListener( const container::keyType &key ).
438 */
439 template < class container , class keyType >
440 struct SAL_WARN_UNUSED OBroadcastHelperVar
441 {
442 /** The shared mutex. */
443 ::osl::Mutex & rMutex;
444 /** ListenerContainer class is thread safe. */
445 container aLC;
446 /** Dispose call ready. */
447 sal_Bool bDisposed;
448 /** In dispose call. */
449 sal_Bool bInDispose;
450
451 /**
452 Initialize the structure. bDispose and bInDispose are set to false.
453 @param rMutex_ the mutex reference.
454 */
OBroadcastHelperVarOBroadcastHelperVar455 OBroadcastHelperVar( ::osl::Mutex & rMutex_ )
456 : rMutex( rMutex_ )
457 , aLC( rMutex_ )
458 , bDisposed( false )
459 , bInDispose( false )
460 {}
461
462 /**
463 adds a listener threadsafe.
464 **/
addListenerOBroadcastHelperVar465 void addListener(
466 const keyType &key,
467 const css::uno::Reference < css::uno::XInterface > &r )
468 {
469 ::osl::MutexGuard guard( rMutex );
470 OSL_ENSURE( !bInDispose, "do not add listeners in the dispose call" );
471 OSL_ENSURE( !bDisposed, "object is disposed" );
472 if( ! bInDispose && ! bDisposed )
473 aLC.addInterface( key , r );
474 }
475
476 /**
477 removes a listener threadsafe
478 **/
removeListenerOBroadcastHelperVar479 void removeListener(
480 const keyType &key,
481 const css::uno::Reference < css::uno::XInterface > & r )
482 {
483 ::osl::MutexGuard guard( rMutex );
484 if( ! bInDispose && ! bDisposed )
485 aLC.removeInterface( key , r );
486 }
487
488 /**
489 Return the container created under this key.
490 @return the container created under this key. If the container
491 was not created, null was returned. This can be used to optimize
492 performance ( construction of an event object can be avoided ).
493 ***/
getContainerOBroadcastHelperVar494 OInterfaceContainerHelper * SAL_CALL getContainer( const keyType &key ) const
495 { return aLC.getContainer( key ); }
496 };
497
498 /*------------------------------------------
499 *
500 * In general, the above templates are used with a Type as key.
501 * Therefore a default declaration is given ( OMultiTypeInterfaceContainerHelper and OBroadcastHelper )
502 *
503 *------------------------------------------*/
504
505 // helper function call class
506 struct hashType_Impl
507 {
operatorhashType_Impl508 size_t operator()(const css::uno::Type & s) const
509 { return static_cast<size_t>(s.getTypeName().hashCode()); }
510 };
511
512
513 /** Specialized class for key type css::uno::Type,
514 without explicit usage of STL symbols.
515 */
516 class CPPUHELPER_DLLPUBLIC OMultiTypeInterfaceContainerHelper
517 {
518 public:
519 // these are here to force memory de/allocation to sal lib.
new(size_t nSize)520 static void * SAL_CALL operator new( size_t nSize )
521 { return ::rtl_allocateMemory( nSize ); }
delete(void * pMem)522 static void SAL_CALL operator delete( void * pMem )
523 { ::rtl_freeMemory( pMem ); }
new(size_t,void * pMem)524 static void * SAL_CALL operator new( size_t, void * pMem )
525 { return pMem; }
delete(void *,void *)526 static void SAL_CALL operator delete( void *, void * )
527 {}
528
529 /**
530 Create a container of interface containers.
531
532 @param rMutex the mutex to protect multi thread access.
533 The lifetime must be longer than the lifetime
534 of this object.
535 */
536 OMultiTypeInterfaceContainerHelper( ::osl::Mutex & rMutex );
537 /**
538 Delete all containers.
539 */
540 ~OMultiTypeInterfaceContainerHelper();
541
542 /**
543 Return all id's under which at least one interface is added.
544 */
545 css::uno::Sequence< css::uno::Type > SAL_CALL getContainedTypes() const;
546
547 /**
548 Return the container created under this key.
549 @return the container created under this key. If the container
550 was not created, null was returned.
551 */
552 OInterfaceContainerHelper * SAL_CALL getContainer( const css::uno::Type & rKey ) const;
553
554 /** Inserts an element into the container with the specified key.
555 The position is not specified, thus it is not specified in which order events are fired.
556
557 @attention
558 If you add the same interface more than once, then it will be added to the elements list
559 more than once and thus if you want to remove that interface from the list, you have to call
560 removeInterface() the same number of times.
561 In the latter case, you will also get events fired more than once (if the interface is a
562 listener interface).
563
564 @param rKey
565 the id of the container
566 @param r
567 interface to be added; it is allowed, to insert null or
568 the same interface more than once
569 @return
570 the new count of elements in the container
571 */
572 sal_Int32 SAL_CALL addInterface(
573 const css::uno::Type & rKey,
574 const css::uno::Reference< css::uno::XInterface > & r );
575
576 /** Removes an element from the container with the specified key.
577 It uses interface equality to remove the interface.
578
579 @param rKey
580 the id of the container
581 @param rxIFace
582 interface to be removed
583 @return
584 the new count of elements in the container
585 */
586 sal_Int32 SAL_CALL removeInterface(
587 const css::uno::Type & rKey,
588 const css::uno::Reference< css::uno::XInterface > & rxIFace );
589
590 /**
591 Call disposing on all object in the container that
592 support XEventListener. Then clear the container.
593 */
594 void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
595 /**
596 Remove all elements of all containers. Does not delete the container.
597 */
598 void SAL_CALL clear();
599
600 typedef css::uno::Type keyType;
601 private:
602 void * m_pMap;
603 ::osl::Mutex & rMutex;
604
605 OMultiTypeInterfaceContainerHelper( const OMultiTypeInterfaceContainerHelper & ) SAL_DELETED_FUNCTION;
606 OMultiTypeInterfaceContainerHelper & operator = ( const OMultiTypeInterfaceContainerHelper & ) SAL_DELETED_FUNCTION;
607 };
608
609 typedef OBroadcastHelperVar< OMultiTypeInterfaceContainerHelper , OMultiTypeInterfaceContainerHelper::keyType > OBroadcastHelper;
610
611 }
612
613 #endif
614
615 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
616