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