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