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;
element_alias()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. */
hasMoreElements() const89 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.
operator new(size_t nSize)127 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
128 { return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)129 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
130 { ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)131 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
132 { return pMem; }
operator delete(void *,void *)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:
NotifySingleListener(NotificationMethod method,const EventT & event)264 NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
265
operator ()(const::com::sun::star::uno::Reference<ListenerT> & listener) const266 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>
forEach(FuncT const & func)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 >
notifyEach(void (SAL_CALL ListenerT::* NotificationMethod)(const EventT &),const EventT & Event)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.
operator new(size_t nSize)314 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
315 { return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)316 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
317 { ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)318 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
319 { return pMem; }
operator delete(void *,void *)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
find(const key & rKey) const404 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 **/
addListenercppu::OBroadcastHelperVar461 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 **/
removeListenercppu::OBroadcastHelperVar476 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 ***/
getContainercppu::OBroadcastHelperVar493 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 {
operator ()cppu::hashType_Impl507 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.
operator new(size_t nSize)519 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
520 { return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)521 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
522 { ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)523 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
524 { return pMem; }
operator delete(void *,void *)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
616