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