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