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>
30 #include <com/sun/star/lang/XEventListener.hpp>
34 using namespace com::sun::star::uno
;
35 using namespace com::sun::star::lang
;
40 * Remove an element from an interface sequence.
42 static void sequenceRemoveElementAt( Sequence
< Reference
< XInterface
> > & rSeq
, sal_Int32 index
)
44 sal_Int32 nNewLen
= rSeq
.getLength() - 1;
46 Sequence
< Reference
< XInterface
> > aDestSeq( rSeq
.getLength() - 1 );
47 // getArray on a const sequence is faster
48 const Reference
< XInterface
> * pSource
= rSeq
.getConstArray();
49 Reference
< XInterface
> * pDest
= aDestSeq
.getArray();
51 for( ; i
< index
; i
++ )
52 pDest
[i
] = pSource
[i
];
53 for( sal_Int32 j
= i
; j
< nNewLen
; j
++ )
54 pDest
[j
] = pSource
[j
+1];
58 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper
& rCont_
)
61 MutexGuard
aGuard( rCont
.rMutex
);
63 // worst case, two iterators at the same time
64 rCont
.copyAndResetInUse();
65 bIsList
= rCont_
.bIsList
;
70 nRemain
= aData
.pAsSequence
->getLength();
72 else if( aData
.pAsInterface
)
74 aData
.pAsInterface
->acquire();
81 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
85 MutexGuard
aGuard( rCont
.rMutex
);
86 // bResetInUse protect the iterator against recursion
87 bShared
= aData
.pAsSequence
== rCont
.aData
.pAsSequence
&& rCont
.bIsList
;
90 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper must be in use" );
98 // Sequence owned by the iterator
99 delete aData
.pAsSequence
;
100 else if( aData
.pAsInterface
)
101 // Interface is acquired by the iterator
102 aData
.pAsInterface
->release();
106 XInterface
* OInterfaceIteratorHelper::next()
112 // typecase to const,so the getArray method is faster
113 return aData
.pAsSequence
->getConstArray()[nRemain
].get();
114 if( aData
.pAsInterface
)
115 return aData
.pAsInterface
;
121 void OInterfaceIteratorHelper::remove()
125 OSL_ASSERT( nRemain
>= 0 &&
126 nRemain
< aData
.pAsSequence
->getLength() );
127 XInterface
* p
= aData
.pAsSequence
->getConstArray()[nRemain
].get();
128 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >( &p
) );
132 OSL_ASSERT( 0 == nRemain
);
133 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >(&aData
.pAsInterface
));
137 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex
& rMutex_
)
144 OInterfaceContainerHelper::~OInterfaceContainerHelper()
146 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper but is in use" );
148 delete aData
.pAsSequence
;
149 else if( aData
.pAsInterface
)
150 aData
.pAsInterface
->release();
153 sal_Int32
OInterfaceContainerHelper::getLength() const
155 MutexGuard
aGuard( rMutex
);
157 return aData
.pAsSequence
->getLength();
158 if( aData
.pAsInterface
)
163 Sequence
< Reference
<XInterface
> > OInterfaceContainerHelper::getElements() const
165 MutexGuard
aGuard( rMutex
);
167 return *aData
.pAsSequence
;
168 if( aData
.pAsInterface
)
170 Reference
<XInterface
> x( aData
.pAsInterface
);
171 return Sequence
< Reference
< XInterface
> >( &x
, 1 );
173 return Sequence
< Reference
< XInterface
> >();
176 void OInterfaceContainerHelper::copyAndResetInUse()
178 OSL_ENSURE( bInUse
, "OInterfaceContainerHelper not in use" );
181 // this should be the worst case. If a iterator is active
182 // and a new Listener is added.
184 aData
.pAsSequence
= new Sequence
< Reference
< XInterface
> >( *aData
.pAsSequence
);
185 else if( aData
.pAsInterface
)
186 aData
.pAsInterface
->acquire();
192 sal_Int32
OInterfaceContainerHelper::addInterface( const Reference
<XInterface
> & rListener
)
194 OSL_ASSERT( rListener
.is() );
195 MutexGuard
aGuard( rMutex
);
201 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
202 aData
.pAsSequence
->realloc( nLen
+1 );
203 aData
.pAsSequence
->getArray()[ nLen
] = rListener
;
206 if( aData
.pAsInterface
)
208 Sequence
< Reference
< XInterface
> > * pSeq
= new Sequence
< Reference
< XInterface
> >( 2 );
209 Reference
<XInterface
> * pArray
= pSeq
->getArray();
210 pArray
[0] = aData
.pAsInterface
;
211 pArray
[1] = rListener
;
212 aData
.pAsInterface
->release();
213 aData
.pAsSequence
= pSeq
;
217 aData
.pAsInterface
= rListener
.get();
219 rListener
->acquire();
223 sal_Int32
OInterfaceContainerHelper::removeInterface( const Reference
<XInterface
> & rListener
)
225 OSL_ASSERT( rListener
.is() );
226 MutexGuard
aGuard( rMutex
);
232 const Reference
<XInterface
> * pL
= aData
.pAsSequence
->getConstArray();
233 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
235 for( i
= 0; i
< nLen
; i
++ )
237 // It is not valid to compare the pointer directly, but it's faster.
238 if( pL
[i
].get() == rListener
.get() )
240 sequenceRemoveElementAt( *aData
.pAsSequence
, i
);
247 // interface not found, use the correct compare method
248 for( i
= 0; i
< nLen
; i
++ )
250 if( pL
[i
] == rListener
)
252 sequenceRemoveElementAt(*aData
.pAsSequence
, i
);
258 if( aData
.pAsSequence
->getLength() == 1 )
260 XInterface
* p
= aData
.pAsSequence
->getConstArray()[0].get();
262 delete aData
.pAsSequence
;
263 aData
.pAsInterface
= p
;
267 return aData
.pAsSequence
->getLength();
269 if( aData
.pAsInterface
&& Reference
<XInterface
>( aData
.pAsInterface
) == rListener
)
271 aData
.pAsInterface
->release();
272 aData
.pAsInterface
= nullptr;
274 return aData
.pAsInterface
? 1 : 0;
277 void OInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
)
279 ClearableMutexGuard
aGuard( rMutex
);
280 OInterfaceIteratorHelper
aIt( *this );
281 // Release container, in case new entries come while disposing
282 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
283 if( !bIsList
&& aData
.pAsInterface
)
284 aData
.pAsInterface
->release();
285 // set the member to null, use the iterator to delete the values
286 aData
.pAsInterface
= nullptr;
290 while( aIt
.hasMoreElements() )
294 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
296 xLst
->disposing( rEvt
);
298 catch ( RuntimeException
& )
300 // be robust, if e.g. a remote bridge has disposed already.
301 // there is no way to delegate the error to the caller :o(.
307 void OInterfaceContainerHelper::clear()
309 ClearableMutexGuard
aGuard( rMutex
);
310 OInterfaceIteratorHelper
aIt( *this );
311 // Release container, in case new entries come while disposing
312 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
313 if( !bIsList
&& aData
.pAsInterface
)
314 aData
.pAsInterface
->release();
315 // set the member to null, use the iterator to delete the values
316 aData
.pAsInterface
= nullptr;
319 // release mutex before aIt destructor call
323 // specialized class for type
325 typedef std::vector
< std::pair
< Type
, void* > > t_type2ptr
;
327 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex
& rMutex_
)
330 m_pMap
= new t_type2ptr
;
333 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
335 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
336 t_type2ptr::iterator iter
= pMap
->begin();
337 t_type2ptr::iterator end
= pMap
->end();
341 delete static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
342 (*iter
).second
= nullptr;
348 Sequence
< Type
> OMultiTypeInterfaceContainerHelper::getContainedTypes() const
350 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
351 t_type2ptr::size_type nSize
;
353 ::osl::MutexGuard
aGuard( rMutex
);
354 nSize
= pMap
->size();
357 css::uno::Sequence
< Type
> aInterfaceTypes( nSize
);
358 Type
* pArray
= aInterfaceTypes
.getArray();
360 t_type2ptr::iterator iter
= pMap
->begin();
361 t_type2ptr::iterator end
= pMap
->end();
366 // are interfaces added to this container?
367 if( static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->getLength() )
368 // yes, put the type in the array
369 pArray
[i
++] = (*iter
).first
;
372 if( static_cast<t_type2ptr::size_type
>(i
) != nSize
) {
373 // may be empty container, reduce the sequence to the right size
374 aInterfaceTypes
= css::uno::Sequence
< Type
>( pArray
, i
);
376 return aInterfaceTypes
;
378 return css::uno::Sequence
< Type
>();
381 static t_type2ptr::iterator
findType(t_type2ptr
*pMap
, const Type
& rKey
)
383 t_type2ptr::iterator iter
= pMap
->begin();
384 t_type2ptr::iterator end
= pMap
->end();
388 if (iter
->first
== rKey
)
395 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelper::getContainer( const Type
& rKey
) const
397 ::osl::MutexGuard
aGuard( rMutex
);
399 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
400 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
401 if( iter
!= pMap
->end() )
402 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
406 sal_Int32
OMultiTypeInterfaceContainerHelper::addInterface(
407 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
409 ::osl::MutexGuard
aGuard( rMutex
);
410 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
411 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
412 if( iter
== pMap
->end() )
414 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
415 pMap
->push_back(std::pair
<Type
, void*>(rKey
, pLC
));
416 return pLC
->addInterface( rListener
);
418 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->addInterface( rListener
);
421 sal_Int32
OMultiTypeInterfaceContainerHelper::removeInterface(
422 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
424 ::osl::MutexGuard
aGuard( rMutex
);
426 // search container with id nUik
427 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
428 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
430 if( iter
!= pMap
->end() )
431 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
433 // no container with this id. Always return 0
437 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
)
439 t_type2ptr::size_type nSize
= 0;
440 std::unique_ptr
<OInterfaceContainerHelper
*[]> ppListenerContainers
;
442 ::osl::MutexGuard
aGuard( rMutex
);
443 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
444 nSize
= pMap
->size();
447 typedef OInterfaceContainerHelper
* ppp
;
448 ppListenerContainers
.reset(new ppp
[nSize
]);
449 //ppListenerContainers = new (ListenerContainer*)[nSize];
451 t_type2ptr::iterator iter
= pMap
->begin();
452 t_type2ptr::iterator end
= pMap
->end();
454 t_type2ptr::size_type i
= 0;
457 ppListenerContainers
[i
++] = static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
463 // create a copy, because do not fire event in a guarded section
464 for( t_type2ptr::size_type i
= 0;
467 if( ppListenerContainers
[i
] )
468 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
472 void OMultiTypeInterfaceContainerHelper::clear()
474 ::osl::MutexGuard
aGuard( rMutex
);
475 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
476 t_type2ptr::iterator iter
= pMap
->begin();
477 t_type2ptr::iterator end
= pMap
->end();
481 static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->clear();
486 // specialized class for long
488 typedef std::vector
< std::pair
< sal_Int32
, void* > > t_long2ptr
;
490 static t_long2ptr::iterator
findLong(t_long2ptr
*pMap
, sal_Int32 nKey
)
492 t_long2ptr::iterator iter
= pMap
->begin();
493 t_long2ptr::iterator end
= pMap
->end();
497 if (iter
->first
== nKey
)
504 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex
& rMutex_
)
508 // delay pMap allocation until necessary.
511 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
516 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
517 t_long2ptr::iterator iter
= pMap
->begin();
518 t_long2ptr::iterator end
= pMap
->end();
522 delete static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
523 (*iter
).second
= nullptr;
529 Sequence
< sal_Int32
> OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
531 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
532 t_long2ptr::size_type nSize
;
534 ::osl::MutexGuard
aGuard( rMutex
);
535 nSize
= pMap
? pMap
->size() : 0;
538 css::uno::Sequence
< sal_Int32
> aInterfaceTypes( nSize
);
539 sal_Int32
* pArray
= aInterfaceTypes
.getArray();
541 t_long2ptr::iterator iter
= pMap
->begin();
542 t_long2ptr::iterator end
= pMap
->end();
547 // are interfaces added to this container?
548 if( static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->getLength() )
549 // yes, put the type in the array
550 pArray
[i
++] = (*iter
).first
;
553 if( static_cast<t_long2ptr::size_type
>(i
) != nSize
) {
554 // may be empty container, reduce the sequence to the right size
555 aInterfaceTypes
= css::uno::Sequence
< sal_Int32
>( pArray
, i
);
557 return aInterfaceTypes
;
559 return css::uno::Sequence
< sal_Int32
>();
562 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32
& rKey
) const
564 ::osl::MutexGuard
aGuard( rMutex
);
568 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
569 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
570 if( iter
!= pMap
->end() )
571 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
575 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::addInterface(
576 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
578 ::osl::MutexGuard
aGuard( rMutex
);
580 m_pMap
= new t_long2ptr
;
581 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
582 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
583 if( iter
== pMap
->end() )
585 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
586 pMap
->push_back(std::pair
< sal_Int32
, void* >(rKey
, pLC
));
587 return pLC
->addInterface( rListener
);
589 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->addInterface( rListener
);
592 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::removeInterface(
593 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
595 ::osl::MutexGuard
aGuard( rMutex
);
599 // search container with id nUik
600 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
601 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
603 if( iter
!= pMap
->end() )
604 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
606 // no container with this id. Always return 0
610 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject
& rEvt
)
612 t_long2ptr::size_type nSize
= 0;
613 std::unique_ptr
<OInterfaceContainerHelper
*[]> ppListenerContainers
;
615 ::osl::MutexGuard
aGuard( rMutex
);
619 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
620 nSize
= pMap
->size();
623 typedef OInterfaceContainerHelper
* ppp
;
624 ppListenerContainers
.reset(new ppp
[nSize
]);
626 t_long2ptr::iterator iter
= pMap
->begin();
627 t_long2ptr::iterator end
= pMap
->end();
629 t_long2ptr::size_type i
= 0;
632 ppListenerContainers
[i
++] = static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
638 // create a copy, because do not fire event in a guarded section
639 for( t_long2ptr::size_type i
= 0;
642 if( ppListenerContainers
[i
] )
643 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
647 void OMultiTypeInterfaceContainerHelperInt32::clear()
649 ::osl::MutexGuard
aGuard( rMutex
);
652 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
653 t_long2ptr::iterator iter
= pMap
->begin();
654 t_long2ptr::iterator end
= pMap
->end();
658 static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->clear();
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */