Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / cppuhelper / source / interfacecontainer.cxx
blobd4627ff943994478cc2298262b166b7eac382043
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <memory>
30 #include <com/sun/star/lang/XEventListener.hpp>
33 using namespace osl;
34 using namespace com::sun::star::uno;
35 using namespace com::sun::star::lang;
37 namespace cppu
39 /**
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();
50 sal_Int32 i = 0;
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];
55 rSeq = aDestSeq;
58 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
59 : rCont( rCont_ )
61 MutexGuard aGuard( rCont.rMutex );
62 if( rCont.bInUse )
63 // worst case, two iterators at the same time
64 rCont.copyAndResetInUse();
65 bIsList = rCont_.bIsList;
66 aData = rCont_.aData;
67 if( bIsList )
69 rCont.bInUse = true;
70 nRemain = aData.pAsSequence->getLength();
72 else if( aData.pAsInterface )
74 aData.pAsInterface->acquire();
75 nRemain = 1;
77 else
78 nRemain = 0;
81 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
83 bool bShared;
85 MutexGuard aGuard( rCont.rMutex );
86 // bResetInUse protect the iterator against recursion
87 bShared = aData.pAsSequence == rCont.aData.pAsSequence && rCont.bIsList;
88 if( bShared )
90 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
91 rCont.bInUse = false;
95 if( !bShared )
97 if( bIsList )
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()
108 if( nRemain )
110 nRemain--;
111 if( bIsList )
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;
117 // exception
118 return nullptr;
121 void OInterfaceIteratorHelper::remove()
123 if( bIsList )
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 ) );
130 else
132 OSL_ASSERT( 0 == nRemain );
133 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
137 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ )
138 : rMutex( rMutex_ )
139 , bInUse( false )
140 , bIsList( false )
144 OInterfaceContainerHelper::~OInterfaceContainerHelper()
146 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
147 if( bIsList )
148 delete aData.pAsSequence;
149 else if( aData.pAsInterface )
150 aData.pAsInterface->release();
153 sal_Int32 OInterfaceContainerHelper::getLength() const
155 MutexGuard aGuard( rMutex );
156 if( bIsList )
157 return aData.pAsSequence->getLength();
158 if( aData.pAsInterface )
159 return 1;
160 return 0;
163 Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const
165 MutexGuard aGuard( rMutex );
166 if( bIsList )
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" );
179 if( bInUse )
181 // this should be the worst case. If a iterator is active
182 // and a new Listener is added.
183 if( bIsList )
184 aData.pAsSequence = new Sequence< Reference< XInterface > >( *aData.pAsSequence );
185 else if( aData.pAsInterface )
186 aData.pAsInterface->acquire();
188 bInUse = false;
192 sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener )
194 OSL_ASSERT( rListener.is() );
195 MutexGuard aGuard( rMutex );
196 if( bInUse )
197 copyAndResetInUse();
199 if( bIsList )
201 sal_Int32 nLen = aData.pAsSequence->getLength();
202 aData.pAsSequence->realloc( nLen +1 );
203 aData.pAsSequence->getArray()[ nLen ] = rListener;
204 return nLen +1;
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;
214 bIsList = true;
215 return 2;
217 aData.pAsInterface = rListener.get();
218 if( rListener.is() )
219 rListener->acquire();
220 return 1;
223 sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener )
225 OSL_ASSERT( rListener.is() );
226 MutexGuard aGuard( rMutex );
227 if( bInUse )
228 copyAndResetInUse();
230 if( bIsList )
232 const Reference<XInterface> * pL = aData.pAsSequence->getConstArray();
233 sal_Int32 nLen = aData.pAsSequence->getLength();
234 sal_Int32 i;
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 );
241 break;
245 if( i == nLen )
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 );
253 break;
258 if( aData.pAsSequence->getLength() == 1 )
260 XInterface * p = aData.pAsSequence->getConstArray()[0].get();
261 p->acquire();
262 delete aData.pAsSequence;
263 aData.pAsInterface = p;
264 bIsList = false;
265 return 1;
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;
287 bIsList = false;
288 bInUse = false;
289 aGuard.clear();
290 while( aIt.hasMoreElements() )
294 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
295 if( xLst.is() )
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;
317 bIsList = false;
318 bInUse = false;
319 // release mutex before aIt destructor call
320 aGuard.clear();
323 // specialized class for type
325 typedef std::vector< std::pair < Type , void* > > t_type2ptr;
327 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ )
328 : rMutex( 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();
339 while( iter != end )
341 delete static_cast<OInterfaceContainerHelper*>((*iter).second);
342 (*iter).second = nullptr;
343 ++iter;
345 delete pMap;
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();
355 if( nSize )
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();
363 sal_Int32 i = 0;
364 while( iter != 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;
370 ++iter;
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();
386 while( iter != end )
388 if (iter->first == rKey)
389 break;
390 ++iter;
392 return iter;
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);
403 return nullptr;
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 );
429 // container found?
430 if( iter != pMap->end() )
431 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
433 // no container with this id. Always return 0
434 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();
445 if( nSize )
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;
455 while( iter != end )
457 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>((*iter).second);
458 ++iter;
463 // create a copy, because do not fire event in a guarded section
464 for( t_type2ptr::size_type i = 0;
465 i < nSize; i++ )
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();
479 while( iter != end )
481 static_cast<OInterfaceContainerHelper*>((*iter).second)->clear();
482 ++iter;
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();
495 while( iter != end )
497 if (iter->first == nKey)
498 break;
499 ++iter;
501 return iter;
504 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
505 : m_pMap( nullptr )
506 , rMutex( rMutex_ )
508 // delay pMap allocation until necessary.
511 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
513 if (!m_pMap)
514 return;
516 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
517 t_long2ptr::iterator iter = pMap->begin();
518 t_long2ptr::iterator end = pMap->end();
520 while( iter != end )
522 delete static_cast<OInterfaceContainerHelper*>((*iter).second);
523 (*iter).second = nullptr;
524 ++iter;
526 delete pMap;
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;
536 if( nSize )
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();
544 sal_Int32 i = 0;
545 while( iter != 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;
551 ++iter;
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 );
566 if (!m_pMap)
567 return nullptr;
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);
572 return nullptr;
575 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
576 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
578 ::osl::MutexGuard aGuard( rMutex );
579 if (!m_pMap)
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 );
597 if (!m_pMap)
598 return 0;
599 // search container with id nUik
600 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
601 t_long2ptr::iterator iter = findLong( pMap, rKey );
602 // container found?
603 if( iter != pMap->end() )
604 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
606 // no container with this id. Always return 0
607 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 );
616 if (!m_pMap)
617 return;
619 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
620 nSize = pMap->size();
621 if( nSize )
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;
630 while( iter != end )
632 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>((*iter).second);
633 ++iter;
638 // create a copy, because do not fire event in a guarded section
639 for( t_long2ptr::size_type i = 0;
640 i < nSize; i++ )
642 if( ppListenerContainers[i] )
643 ppListenerContainers[i]->disposeAndClear( rEvt );
647 void OMultiTypeInterfaceContainerHelperInt32::clear()
649 ::osl::MutexGuard aGuard( rMutex );
650 if (!m_pMap)
651 return;
652 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
653 t_long2ptr::iterator iter = pMap->begin();
654 t_long2ptr::iterator end = pMap->end();
656 while( iter != end )
658 static_cast<OInterfaceContainerHelper*>((*iter).second)->clear();
659 ++iter;
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */