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