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/propshlp.hxx>
24 #include <osl/diagnose.h>
25 #include <osl/mutex.hxx>
29 #include <com/sun/star/lang/XEventListener.hpp>
33 using namespace com::sun::star::uno
;
34 using namespace com::sun::star::lang
;
39 * Remove an element from an interface sequence.
41 static void sequenceRemoveElementAt( Sequence
< Reference
< XInterface
> > & rSeq
, sal_Int32 index
)
43 sal_Int32 nNewLen
= rSeq
.getLength() - 1;
45 Sequence
< Reference
< XInterface
> > aDestSeq( rSeq
.getLength() - 1 );
46 // getArray on a const sequence is faster
47 const Reference
< XInterface
> * pSource
= rSeq
.getConstArray();
48 Reference
< XInterface
> * pDest
= aDestSeq
.getArray();
50 for( ; i
< index
; i
++ )
51 pDest
[i
] = pSource
[i
];
52 for( sal_Int32 j
= i
; j
< nNewLen
; j
++ )
53 pDest
[j
] = pSource
[j
+1];
57 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper
& rCont_
)
60 MutexGuard
aGuard( rCont
.rMutex
);
62 // worst case, two iterators at the same time
63 rCont
.copyAndResetInUse();
64 bIsList
= rCont_
.bIsList
;
69 nRemain
= aData
.pAsSequence
->getLength();
71 else if( aData
.pAsInterface
)
73 aData
.pAsInterface
->acquire();
80 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
84 MutexGuard
aGuard( rCont
.rMutex
);
85 // bResetInUse protect the iterator against recursion
86 bShared
= aData
.pAsSequence
== rCont
.aData
.pAsSequence
&& rCont
.bIsList
;
89 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper must be in use" );
97 // Sequence owned by the iterator
98 delete aData
.pAsSequence
;
99 else if( aData
.pAsInterface
)
100 // Interface is acquired by the iterator
101 aData
.pAsInterface
->release();
105 XInterface
* OInterfaceIteratorHelper::next()
111 // typecase to const,so the getArray method is faster
112 return aData
.pAsSequence
->getConstArray()[nRemain
].get();
113 if( aData
.pAsInterface
)
114 return aData
.pAsInterface
;
120 void OInterfaceIteratorHelper::remove()
124 OSL_ASSERT( nRemain
>= 0 &&
125 nRemain
< aData
.pAsSequence
->getLength() );
126 XInterface
* p
= aData
.pAsSequence
->getConstArray()[nRemain
].get();
127 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >( &p
) );
131 OSL_ASSERT( 0 == nRemain
);
132 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >(&aData
.pAsInterface
));
136 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex
& rMutex_
)
143 OInterfaceContainerHelper::~OInterfaceContainerHelper()
145 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper but is in use" );
147 delete aData
.pAsSequence
;
148 else if( aData
.pAsInterface
)
149 aData
.pAsInterface
->release();
152 sal_Int32
OInterfaceContainerHelper::getLength() const
154 MutexGuard
aGuard( rMutex
);
156 return aData
.pAsSequence
->getLength();
157 if( aData
.pAsInterface
)
162 Sequence
< Reference
<XInterface
> > OInterfaceContainerHelper::getElements() const
164 MutexGuard
aGuard( rMutex
);
166 return *aData
.pAsSequence
;
167 if( aData
.pAsInterface
)
169 Reference
<XInterface
> x( aData
.pAsInterface
);
170 return Sequence
< Reference
< XInterface
> >( &x
, 1 );
172 return Sequence
< Reference
< XInterface
> >();
175 void OInterfaceContainerHelper::copyAndResetInUse()
177 OSL_ENSURE( bInUse
, "OInterfaceContainerHelper not in use" );
180 // this should be the worst case. If an iterator is active
181 // and a new Listener is added.
183 aData
.pAsSequence
= new Sequence
< Reference
< XInterface
> >( *aData
.pAsSequence
);
184 else if( aData
.pAsInterface
)
185 aData
.pAsInterface
->acquire();
191 sal_Int32
OInterfaceContainerHelper::addInterface( const Reference
<XInterface
> & rListener
)
193 OSL_ASSERT( rListener
.is() );
194 MutexGuard
aGuard( rMutex
);
200 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
201 aData
.pAsSequence
->realloc( nLen
+1 );
202 aData
.pAsSequence
->getArray()[ nLen
] = rListener
;
205 if( aData
.pAsInterface
)
207 Sequence
< Reference
< XInterface
> > * pSeq
= new Sequence
< Reference
< XInterface
> >( 2 );
208 Reference
<XInterface
> * pArray
= pSeq
->getArray();
209 pArray
[0] = aData
.pAsInterface
;
210 pArray
[1] = rListener
;
211 aData
.pAsInterface
->release();
212 aData
.pAsSequence
= pSeq
;
216 aData
.pAsInterface
= rListener
.get();
218 rListener
->acquire();
222 sal_Int32
OInterfaceContainerHelper::removeInterface( const Reference
<XInterface
> & rListener
)
224 OSL_ASSERT( rListener
.is() );
225 MutexGuard
aGuard( rMutex
);
231 const Reference
<XInterface
> * pL
= aData
.pAsSequence
->getConstArray();
232 sal_Int32 nLen
= aData
.pAsSequence
->getLength();
234 for( i
= 0; i
< nLen
; i
++ )
236 // It is not valid to compare the pointer directly, but it's faster.
237 if( pL
[i
].get() == rListener
.get() )
239 sequenceRemoveElementAt( *aData
.pAsSequence
, i
);
246 // interface not found, use the correct compare method
247 for( i
= 0; i
< nLen
; i
++ )
249 if( pL
[i
] == rListener
)
251 sequenceRemoveElementAt(*aData
.pAsSequence
, i
);
257 if( aData
.pAsSequence
->getLength() == 1 )
259 XInterface
* p
= aData
.pAsSequence
->getConstArray()[0].get();
261 delete aData
.pAsSequence
;
262 aData
.pAsInterface
= p
;
266 return aData
.pAsSequence
->getLength();
268 if( aData
.pAsInterface
&& Reference
<XInterface
>( aData
.pAsInterface
) == rListener
)
270 aData
.pAsInterface
->release();
271 aData
.pAsInterface
= nullptr;
273 return aData
.pAsInterface
? 1 : 0;
276 void OInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
)
278 ClearableMutexGuard
aGuard( rMutex
);
279 OInterfaceIteratorHelper
aIt( *this );
280 // Release container, in case new entries come while disposing
281 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
282 if( !bIsList
&& aData
.pAsInterface
)
283 aData
.pAsInterface
->release();
284 // set the member to null, use the iterator to delete the values
285 aData
.pAsInterface
= nullptr;
289 while( aIt
.hasMoreElements() )
293 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
295 xLst
->disposing( rEvt
);
297 catch ( RuntimeException
& )
299 // be robust, if e.g. a remote bridge has disposed already.
300 // there is no way to delegate the error to the caller :o(.
306 void OInterfaceContainerHelper::clear()
308 ClearableMutexGuard
aGuard( rMutex
);
309 OInterfaceIteratorHelper
aIt( *this );
310 // Release container, in case new entries come while disposing
311 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper not in use" );
312 if( !bIsList
&& aData
.pAsInterface
)
313 aData
.pAsInterface
->release();
314 // set the member to null, use the iterator to delete the values
315 aData
.pAsInterface
= nullptr;
318 // release mutex before aIt destructor call
322 // specialized class for type
324 typedef std::vector
< std::pair
< Type
, void* > > t_type2ptr
;
326 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex
& rMutex_
)
329 m_pMap
= new t_type2ptr
;
332 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
334 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
336 for (auto& rItem
: *pMap
)
338 delete static_cast<OInterfaceContainerHelper
*>(rItem
.second
);
339 rItem
.second
= nullptr;
344 Sequence
< Type
> OMultiTypeInterfaceContainerHelper::getContainedTypes() const
346 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
347 t_type2ptr::size_type nSize
;
349 ::osl::MutexGuard
aGuard( rMutex
);
350 nSize
= pMap
->size();
353 css::uno::Sequence
< Type
> aInterfaceTypes( nSize
);
354 Type
* pArray
= aInterfaceTypes
.getArray();
357 for (const auto& rItem
: *pMap
)
359 // are interfaces added to this container?
360 if( static_cast<OInterfaceContainerHelper
*>(rItem
.second
)->getLength() )
361 // yes, put the type in the array
362 pArray
[i
++] = rItem
.first
;
364 if( static_cast<t_type2ptr::size_type
>(i
) != nSize
) {
365 // may be empty container, reduce the sequence to the right size
366 aInterfaceTypes
= css::uno::Sequence
< Type
>( pArray
, i
);
368 return aInterfaceTypes
;
370 return css::uno::Sequence
< Type
>();
373 static t_type2ptr::iterator
findType(t_type2ptr
*pMap
, const Type
& rKey
)
375 return std::find_if(pMap
->begin(), pMap
->end(),
376 [&rKey
](const t_type2ptr::value_type
& rItem
) { return rItem
.first
== rKey
; });
379 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelper::getContainer( const Type
& rKey
) const
381 ::osl::MutexGuard
aGuard( rMutex
);
383 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
384 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
385 if( iter
!= pMap
->end() )
386 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
390 sal_Int32
OMultiTypeInterfaceContainerHelper::addInterface(
391 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
393 ::osl::MutexGuard
aGuard( rMutex
);
394 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
395 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
396 if( iter
== pMap
->end() )
398 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
399 pMap
->push_back(std::pair
<Type
, void*>(rKey
, pLC
));
400 return pLC
->addInterface( rListener
);
402 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->addInterface( rListener
);
405 sal_Int32
OMultiTypeInterfaceContainerHelper::removeInterface(
406 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
408 ::osl::MutexGuard
aGuard( rMutex
);
410 // search container with id nUik
411 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
412 t_type2ptr::iterator iter
= findType( pMap
, rKey
);
414 if( iter
!= pMap
->end() )
415 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
417 // no container with this id. Always return 0
421 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject
& rEvt
)
423 t_type2ptr::size_type nSize
= 0;
424 std::unique_ptr
<OInterfaceContainerHelper
*[]> ppListenerContainers
;
426 ::osl::MutexGuard
aGuard( rMutex
);
427 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
428 nSize
= pMap
->size();
431 typedef OInterfaceContainerHelper
* ppp
;
432 ppListenerContainers
.reset(new ppp
[nSize
]);
433 //ppListenerContainers = new (ListenerContainer*)[nSize];
435 t_type2ptr::size_type i
= 0;
436 for (const auto& rItem
: *pMap
)
438 ppListenerContainers
[i
++] = static_cast<OInterfaceContainerHelper
*>(rItem
.second
);
443 // create a copy, because do not fire event in a guarded section
444 for( t_type2ptr::size_type i
= 0;
447 if( ppListenerContainers
[i
] )
448 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
452 void OMultiTypeInterfaceContainerHelper::clear()
454 ::osl::MutexGuard
aGuard( rMutex
);
455 t_type2ptr
* pMap
= static_cast<t_type2ptr
*>(m_pMap
);
457 for (auto& rItem
: *pMap
)
459 static_cast<OInterfaceContainerHelper
*>(rItem
.second
)->clear();
463 // specialized class for long
465 typedef std::vector
< std::pair
< sal_Int32
, void* > > t_long2ptr
;
467 static t_long2ptr::iterator
findLong(t_long2ptr
*pMap
, sal_Int32 nKey
)
469 return std::find_if(pMap
->begin(), pMap
->end(),
470 [&nKey
](const t_long2ptr::value_type
& rItem
) { return rItem
.first
== nKey
; });
473 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex
& rMutex_
)
477 // delay pMap allocation until necessary.
480 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
485 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
487 for (auto& rItem
: *pMap
)
489 delete static_cast<OInterfaceContainerHelper
*>(rItem
.second
);
490 rItem
.second
= nullptr;
495 Sequence
< sal_Int32
> OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
497 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
498 t_long2ptr::size_type nSize
;
500 ::osl::MutexGuard
aGuard( rMutex
);
501 nSize
= pMap
? pMap
->size() : 0;
504 css::uno::Sequence
< sal_Int32
> aInterfaceTypes( nSize
);
505 sal_Int32
* pArray
= aInterfaceTypes
.getArray();
508 for (const auto& rItem
: *pMap
)
510 // are interfaces added to this container?
511 if( static_cast<OInterfaceContainerHelper
*>(rItem
.second
)->getLength() )
512 // yes, put the type in the array
513 pArray
[i
++] = rItem
.first
;
515 if( static_cast<t_long2ptr::size_type
>(i
) != nSize
) {
516 // may be empty container, reduce the sequence to the right size
517 aInterfaceTypes
= css::uno::Sequence
< sal_Int32
>( pArray
, i
);
519 return aInterfaceTypes
;
521 return css::uno::Sequence
< sal_Int32
>();
524 OInterfaceContainerHelper
* OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32
& rKey
) const
526 ::osl::MutexGuard
aGuard( rMutex
);
530 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
531 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
532 if( iter
!= pMap
->end() )
533 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
);
537 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::addInterface(
538 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
540 ::osl::MutexGuard
aGuard( rMutex
);
542 m_pMap
= new t_long2ptr
;
543 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
544 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
545 if( iter
== pMap
->end() )
547 OInterfaceContainerHelper
* pLC
= new OInterfaceContainerHelper( rMutex
);
548 pMap
->push_back(std::pair
< sal_Int32
, void* >(rKey
, pLC
));
549 return pLC
->addInterface( rListener
);
551 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->addInterface( rListener
);
554 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::removeInterface(
555 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
557 ::osl::MutexGuard
aGuard( rMutex
);
561 // search container with id nUik
562 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
563 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
565 if( iter
!= pMap
->end() )
566 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
568 // no container with this id. Always return 0
572 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject
& rEvt
)
574 t_long2ptr::size_type nSize
= 0;
575 std::unique_ptr
<OInterfaceContainerHelper
*[]> ppListenerContainers
;
577 ::osl::MutexGuard
aGuard( rMutex
);
581 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
582 nSize
= pMap
->size();
585 typedef OInterfaceContainerHelper
* ppp
;
586 ppListenerContainers
.reset(new ppp
[nSize
]);
588 t_long2ptr::size_type i
= 0;
589 for (const auto& rItem
: *pMap
)
591 ppListenerContainers
[i
++] = static_cast<OInterfaceContainerHelper
*>(rItem
.second
);
596 // create a copy, because do not fire event in a guarded section
597 for( t_long2ptr::size_type i
= 0;
600 if( ppListenerContainers
[i
] )
601 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
605 void OMultiTypeInterfaceContainerHelperInt32::clear()
607 ::osl::MutexGuard
aGuard( rMutex
);
610 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
612 for (auto& rItem
: *pMap
)
614 static_cast<OInterfaceContainerHelper
*>(rItem
.second
)->clear();
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */