1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <cppuhelper/interfacecontainer.hxx>
22 #include <cppuhelper/queryinterface.hxx>
23 #include <cppuhelper/propshlp.hxx>
25 #include <osl/diagnose.h>
26 #include <osl/mutex.hxx>
28 #include <boost/unordered_map.hpp>
30 #include <com/sun/star/lang/XEventListener.hpp>
34 using namespace com::sun::star::uno
;
35 using namespace com::sun::star::lang
;
40 * Reallocate the sequence.
42 static void realloc( Sequence
< Reference
< XInterface
> > & rSeq
, sal_Int32 nNewLen
)
45 rSeq
.realloc( nNewLen
);
49 * Remove an element from an interface sequence.
51 static void sequenceRemoveElementAt( Sequence
< Reference
< XInterface
> > & rSeq
, sal_Int32 index
)
54 sal_Int32 nNewLen
= rSeq
.getLength() - 1;
56 Sequence
< Reference
< XInterface
> > aDestSeq( rSeq
.getLength() - 1 );
57 // getArray on a const sequence is faster
58 const Reference
< XInterface
> * pSource
= ((const Sequence
< Reference
< XInterface
> > &)rSeq
).getConstArray();
59 Reference
< XInterface
> * pDest
= aDestSeq
.getArray();
61 for( ; i
< index
; i
++ )
62 pDest
[i
] = pSource
[i
];
63 for( sal_Int32 j
= i
; j
< nNewLen
; j
++ )
64 pDest
[j
] = pSource
[j
+1];
69 #pragma warning( disable: 4786 )
72 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper
& rCont_
)
76 MutexGuard
aGuard( rCont
.rMutex
);
78 // worst case, two iterators at the same time
79 rCont
.copyAndResetInUse();
80 bIsList
= rCont_
.bIsList
;
84 rCont
.bInUse
= sal_True
;
85 nRemain
= aData
.pAsSequence
->getLength();
87 else if( aData
.pAsInterface
)
89 aData
.pAsInterface
->acquire();
96 OInterfaceIteratorHelper::~OInterfaceIteratorHelper() SAL_THROW(())
100 MutexGuard
aGuard( rCont
.rMutex
);
101 // bResetInUse protect the iterator against recursion
102 bShared
= aData
.pAsSequence
== rCont
.aData
.pAsSequence
&& rCont
.bIsList
;
105 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper must be in use" );
106 rCont
.bInUse
= sal_False
;
113 // Sequence owned by the iterator
114 delete aData
.pAsSequence
;
115 else if( aData
.pAsInterface
)
116 // Interface is acquired by the iterator
117 aData
.pAsInterface
->release();
121 XInterface
* OInterfaceIteratorHelper::next() SAL_THROW(())
127 // typecase to const,so the getArray method is faster
128 return aData
.pAsSequence
->getConstArray()[nRemain
].get();
129 else if( aData
.pAsInterface
)
130 return aData
.pAsInterface
;
136 void OInterfaceIteratorHelper::remove() SAL_THROW(())
140 OSL_ASSERT( nRemain
>= 0 &&
141 nRemain
< aData
.pAsSequence
->getLength() );
142 XInterface
* p
= aData
.pAsSequence
->getConstArray()[nRemain
].get();
143 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >( &p
) );
147 OSL_ASSERT( 0 == nRemain
);
148 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >(&aData
.pAsInterface
));
152 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex
& rMutex_
) SAL_THROW(())
154 , bInUse( sal_False
)
155 , bIsList( sal_False
)
159 OInterfaceContainerHelper::~OInterfaceContainerHelper() SAL_THROW(())
161 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper but is in use" );
163 delete aData
.pAsSequence
;
164 else if( aData
.pAsInterface
)
165 aData
.pAsInterface
->release();
168 sal_Int32
OInterfaceContainerHelper::getLength() const SAL_THROW(())
170 MutexGuard
aGuard( rMutex
);
172 return aData
.pAsSequence
->getLength();
173 else if( aData
.pAsInterface
)
178 Sequence
< Reference
<XInterface
> > OInterfaceContainerHelper::getElements() const SAL_THROW(())
180 MutexGuard
aGuard( rMutex
);
182 return *aData
.pAsSequence
;
183 else if( aData
.pAsInterface
)
185 Reference
<XInterface
> x( aData
.pAsInterface
);
186 return Sequence
< Reference
< XInterface
> >( &x
, 1 );
188 return Sequence
< Reference
< XInterface
> >();
191 void OInterfaceContainerHelper::copyAndResetInUse() SAL_THROW(())
193 OSL_ENSURE( bInUse
, "OInterfaceContainerHelper not in use" );
196 // this should be the worst case. If a iterator is active
197 // and a new Listener is added.
199 aData
.pAsSequence
= new Sequence
< Reference
< XInterface
> >( *aData
.pAsSequence
);
200 else if( aData
.pAsInterface
)
201 aData
.pAsInterface
->acquire();
207 sal_Int32
OInterfaceContainerHelper::addInterface( const Reference
<XInterface
> & rListener
) SAL_THROW(())
209 OSL_ASSERT( rListener
.is() );
210 MutexGuard
aGuard( rMutex
);
216 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
217 realloc( *aData
.pAsSequence
, nLen
+1 );
218 aData
.pAsSequence
->getArray()[ nLen
] = rListener
;
221 else if( aData
.pAsInterface
)
223 Sequence
< Reference
< XInterface
> > * pSeq
= new Sequence
< Reference
< XInterface
> >( 2 );
224 Reference
<XInterface
> * pArray
= pSeq
->getArray();
225 pArray
[0] = aData
.pAsInterface
;
226 pArray
[1] = rListener
;
227 aData
.pAsInterface
->release();
228 aData
.pAsSequence
= pSeq
;
234 aData
.pAsInterface
= rListener
.get();
236 rListener
->acquire();
241 sal_Int32
OInterfaceContainerHelper::removeInterface( const Reference
<XInterface
> & rListener
) SAL_THROW(())
243 OSL_ASSERT( rListener
.is() );
244 MutexGuard
aGuard( rMutex
);
250 const Reference
<XInterface
> * pL
= aData
.pAsSequence
->getConstArray();
251 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
253 for( i
= 0; i
< nLen
; i
++ )
255 // It is not valid to compare the Pointer direkt, but is is is much
257 if( pL
[i
].get() == rListener
.get() )
259 sequenceRemoveElementAt( *aData
.pAsSequence
, i
);
266 // interface not found, use the correct compare method
267 for( i
= 0; i
< nLen
; i
++ )
269 if( pL
[i
] == rListener
)
271 sequenceRemoveElementAt(*aData
.pAsSequence
, i
);
277 if( aData
.pAsSequence
->getLength() == 1 )
279 XInterface
* p
= aData
.pAsSequence
->getConstArray()[0].get();
281 delete aData
.pAsSequence
;
282 aData
.pAsInterface
= p
;
287 return aData
.pAsSequence
->getLength();
289 else if( aData
.pAsInterface
&& Reference
<XInterface
>( aData
.pAsInterface
) == rListener
)
291 aData
.pAsInterface
->release();
292 aData
.pAsInterface
= 0;
294 return aData
.pAsInterface
? 1 : 0;
297 void OInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
) SAL_THROW(())
299 ClearableMutexGuard
aGuard( rMutex
);
300 OInterfaceIteratorHelper
aIt( *this );
301 // Release container, in case new entries come while disposing
302 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
303 if( !bIsList
&& aData
.pAsInterface
)
304 aData
.pAsInterface
->release();
305 // set the member to null, use the iterator to delete the values
306 aData
.pAsInterface
= NULL
;
310 while( aIt
.hasMoreElements() )
314 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
316 xLst
->disposing( rEvt
);
318 catch ( RuntimeException
& )
320 // be robust, if e.g. a remote bridge has disposed already.
321 // there is no way to delegate the error to the caller :o(.
327 void OInterfaceContainerHelper::clear() SAL_THROW(())
329 ClearableMutexGuard
aGuard( rMutex
);
330 OInterfaceIteratorHelper
aIt( *this );
331 // Release container, in case new entries come while disposing
332 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
333 if( !bIsList
&& aData
.pAsInterface
)
334 aData
.pAsInterface
->release();
335 // set the member to null, use the iterator to delete the values
336 aData
.pAsInterface
= 0;
339 // release mutex before aIt destructor call
343 // specialized class for type
345 typedef ::std::vector
< std::pair
< Type
, void* > > t_type2ptr
;
347 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex
& rMutex_
)
351 m_pMap
= new t_type2ptr();
353 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
356 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
357 t_type2ptr::iterator iter
= pMap
->begin();
358 t_type2ptr::iterator end
= pMap
->end();
362 delete (OInterfaceContainerHelper
*)(*iter
).second
;
368 Sequence
< Type
> OMultiTypeInterfaceContainerHelper::getContainedTypes() const
371 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
372 t_type2ptr::size_type nSize
;
374 ::osl::MutexGuard
aGuard( rMutex
);
375 nSize
= pMap
->size();
378 ::com::sun::star::uno::Sequence
< Type
> aInterfaceTypes( nSize
);
379 Type
* pArray
= aInterfaceTypes
.getArray();
381 t_type2ptr::iterator iter
= pMap
->begin();
382 t_type2ptr::iterator end
= pMap
->end();
387 // are interfaces added to this container?
388 if( ((OInterfaceContainerHelper
*)(*iter
).second
)->getLength() )
389 // yes, put the type in the array
390 pArray
[i
++] = (*iter
).first
;
393 if( (t_type2ptr::size_type
)i
!= nSize
) {
394 // may be empty container, reduce the sequence to the right size
395 aInterfaceTypes
= ::com::sun::star::uno::Sequence
< Type
>( pArray
, i
);
397 return aInterfaceTypes
;
399 return ::com::sun::star::uno::Sequence
< Type
>();
402 static t_type2ptr::iterator
findType(t_type2ptr
*pMap
, const Type
& rKey
)
404 t_type2ptr::iterator iter
= pMap
->begin();
405 t_type2ptr::iterator end
= pMap
->end();
409 if (iter
->first
== rKey
)
416 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelper::getContainer( const Type
& rKey
) const
419 ::osl::MutexGuard
aGuard( rMutex
);
421 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
422 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
423 if( iter
!= pMap
->end() )
424 return (OInterfaceContainerHelper
*) (*iter
).second
;
427 sal_Int32
OMultiTypeInterfaceContainerHelper::addInterface(
428 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
431 ::osl::MutexGuard
aGuard( rMutex
);
432 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
433 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
434 if( iter
== pMap
->end() )
436 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
437 pMap
->push_back(std::pair
<Type
, void*>(rKey
, pLC
));
438 return pLC
->addInterface( rListener
);
441 return ((OInterfaceContainerHelper
*)(*iter
).second
)->addInterface( rListener
);
443 sal_Int32
OMultiTypeInterfaceContainerHelper::removeInterface(
444 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
447 ::osl::MutexGuard
aGuard( rMutex
);
449 // search container with id nUik
450 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
451 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
453 if( iter
!= pMap
->end() )
454 return ((OInterfaceContainerHelper
*)(*iter
).second
)->removeInterface( rListener
);
456 // no container with this id. Always return 0
459 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
)
462 t_type2ptr::size_type nSize
= 0;
463 OInterfaceContainerHelper
** ppListenerContainers
= NULL
;
465 ::osl::MutexGuard
aGuard( rMutex
);
466 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
467 nSize
= pMap
->size();
470 typedef OInterfaceContainerHelper
* ppp
;
471 ppListenerContainers
= new ppp
[nSize
];
472 //ppListenerContainers = new (ListenerContainer*)[nSize];
474 t_type2ptr::iterator iter
= pMap
->begin();
475 t_type2ptr::iterator end
= pMap
->end();
477 t_type2ptr::size_type i
= 0;
480 ppListenerContainers
[i
++] = (OInterfaceContainerHelper
*)(*iter
).second
;
486 // create a copy, because do not fire event in a guarded section
487 for( t_type2ptr::size_type i
= 0;
490 if( ppListenerContainers
[i
] )
491 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
494 delete [] ppListenerContainers
;
496 void OMultiTypeInterfaceContainerHelper::clear()
499 ::osl::MutexGuard
aGuard( rMutex
);
500 t_type2ptr
* pMap
= (t_type2ptr
*)m_pMap
;
501 t_type2ptr::iterator iter
= pMap
->begin();
502 t_type2ptr::iterator end
= pMap
->end();
506 ((OInterfaceContainerHelper
*)(*iter
).second
)->clear();
511 // specialized class for long
513 typedef ::std::vector
< std::pair
< sal_Int32
, void* > > t_long2ptr
;
515 static t_long2ptr::iterator
findLong(t_long2ptr
*pMap
, sal_Int32 nKey
)
517 t_long2ptr::iterator iter
= pMap
->begin();
518 t_long2ptr::iterator end
= pMap
->end();
522 if (iter
->first
== nKey
)
529 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex
& rMutex_
)
534 // delay pMap allocation until necessary.
536 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
542 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
543 t_long2ptr::iterator iter
= pMap
->begin();
544 t_long2ptr::iterator end
= pMap
->end();
548 delete (OInterfaceContainerHelper
*)(*iter
).second
;
554 Sequence
< sal_Int32
> OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
557 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
558 t_long2ptr::size_type nSize
;
560 ::osl::MutexGuard
aGuard( rMutex
);
561 nSize
= pMap
? pMap
->size() : 0;
564 ::com::sun::star::uno::Sequence
< sal_Int32
> aInterfaceTypes( nSize
);
565 sal_Int32
* pArray
= aInterfaceTypes
.getArray();
567 t_long2ptr::iterator iter
= pMap
->begin();
568 t_long2ptr::iterator end
= pMap
->end();
573 // are interfaces added to this container?
574 if( ((OInterfaceContainerHelper
*)(*iter
).second
)->getLength() )
575 // yes, put the type in the array
576 pArray
[i
++] = (*iter
).first
;
579 if( (t_long2ptr::size_type
)i
!= nSize
) {
580 // may be empty container, reduce the sequence to the right size
581 aInterfaceTypes
= ::com::sun::star::uno::Sequence
< sal_Int32
>( pArray
, i
);
583 return aInterfaceTypes
;
585 return ::com::sun::star::uno::Sequence
< sal_Int32
>();
587 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32
& rKey
) const
590 ::osl::MutexGuard
aGuard( rMutex
);
594 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
595 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
596 if( iter
!= pMap
->end() )
597 return (OInterfaceContainerHelper
*) (*iter
).second
;
600 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::addInterface(
601 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
604 ::osl::MutexGuard
aGuard( rMutex
);
606 m_pMap
= new t_long2ptr();
607 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
608 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
609 if( iter
== pMap
->end() )
611 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
612 pMap
->push_back(std::pair
< sal_Int32
, void* >(rKey
, pLC
));
613 return pLC
->addInterface( rListener
);
616 return ((OInterfaceContainerHelper
*)(*iter
).second
)->addInterface( rListener
);
618 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::removeInterface(
619 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
622 ::osl::MutexGuard
aGuard( rMutex
);
626 // search container with id nUik
627 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
628 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
630 if( iter
!= pMap
->end() )
631 return ((OInterfaceContainerHelper
*)(*iter
).second
)->removeInterface( rListener
);
633 // no container with this id. Always return 0
636 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject
& rEvt
)
639 t_long2ptr::size_type nSize
= 0;
640 OInterfaceContainerHelper
** ppListenerContainers
= NULL
;
642 ::osl::MutexGuard
aGuard( rMutex
);
646 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
647 nSize
= pMap
->size();
650 typedef OInterfaceContainerHelper
* ppp
;
651 ppListenerContainers
= new ppp
[nSize
];
653 t_long2ptr::iterator iter
= pMap
->begin();
654 t_long2ptr::iterator end
= pMap
->end();
656 t_long2ptr::size_type i
= 0;
659 ppListenerContainers
[i
++] = (OInterfaceContainerHelper
*)(*iter
).second
;
665 // create a copy, because do not fire event in a guarded section
666 for( t_long2ptr::size_type i
= 0;
669 if( ppListenerContainers
[i
] )
670 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
673 delete [] ppListenerContainers
;
675 void OMultiTypeInterfaceContainerHelperInt32::clear()
678 ::osl::MutexGuard
aGuard( rMutex
);
681 t_long2ptr
* pMap
= (t_long2ptr
*)m_pMap
;
682 t_long2ptr::iterator iter
= pMap
->begin();
683 t_long2ptr::iterator end
= pMap
->end();
687 ((OInterfaceContainerHelper
*)(*iter
).second
)->clear();
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */