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