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