Bump version to 4.3-4
[LibreOffice.git] / cppuhelper / source / interfacecontainer.cxx
blobfb59703ca42d916d3f21ecaf1e01674d92cd6b91
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 <boost/unordered_map.hpp>
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 * Reallocate the sequence.
42 static void realloc( Sequence< Reference< XInterface > > & rSeq, sal_Int32 nNewLen )
43 SAL_THROW(())
45 rSeq.realloc( nNewLen );
48 /**
49 * Remove an element from an interface sequence.
51 static void sequenceRemoveElementAt( Sequence< Reference< XInterface > > & rSeq, sal_Int32 index )
52 SAL_THROW(())
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();
60 sal_Int32 i = 0;
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];
65 rSeq = aDestSeq;
68 #ifdef _MSC_VER
69 #pragma warning( disable: 4786 )
70 #endif
72 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
73 SAL_THROW(())
74 : rCont( rCont_ )
76 MutexGuard aGuard( rCont.rMutex );
77 if( rCont.bInUse )
78 // worst case, two iterators at the same time
79 rCont.copyAndResetInUse();
80 bIsList = rCont_.bIsList;
81 aData = rCont_.aData;
82 if( bIsList )
84 rCont.bInUse = sal_True;
85 nRemain = aData.pAsSequence->getLength();
87 else if( aData.pAsInterface )
89 aData.pAsInterface->acquire();
90 nRemain = 1;
92 else
93 nRemain = 0;
96 OInterfaceIteratorHelper::~OInterfaceIteratorHelper() SAL_THROW(())
98 bool bShared;
100 MutexGuard aGuard( rCont.rMutex );
101 // bResetInUse protect the iterator against recursion
102 bShared = aData.pAsSequence == rCont.aData.pAsSequence && rCont.bIsList;
103 if( bShared )
105 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
106 rCont.bInUse = sal_False;
110 if( !bShared )
112 if( bIsList )
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(())
123 if( nRemain )
125 nRemain--;
126 if( bIsList )
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;
132 // exception
133 return 0;
136 void OInterfaceIteratorHelper::remove() SAL_THROW(())
138 if( bIsList )
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 ) );
145 else
147 OSL_ASSERT( 0 == nRemain );
148 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
152 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ ) SAL_THROW(())
153 : rMutex( rMutex_ )
154 , bInUse( sal_False )
155 , bIsList( sal_False )
159 OInterfaceContainerHelper::~OInterfaceContainerHelper() SAL_THROW(())
161 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
162 if( bIsList )
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 );
171 if( bIsList )
172 return aData.pAsSequence->getLength();
173 else if( aData.pAsInterface )
174 return 1;
175 return 0;
178 Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const SAL_THROW(())
180 MutexGuard aGuard( rMutex );
181 if( bIsList )
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" );
194 if( bInUse )
196 // this should be the worst case. If a iterator is active
197 // and a new Listener is added.
198 if( bIsList )
199 aData.pAsSequence = new Sequence< Reference< XInterface > >( *aData.pAsSequence );
200 else if( aData.pAsInterface )
201 aData.pAsInterface->acquire();
203 bInUse = sal_False;
207 sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener ) SAL_THROW(())
209 OSL_ASSERT( rListener.is() );
210 MutexGuard aGuard( rMutex );
211 if( bInUse )
212 copyAndResetInUse();
214 if( bIsList )
216 sal_Int32 nLen = aData.pAsSequence->getLength();
217 realloc( *aData.pAsSequence, nLen +1 );
218 aData.pAsSequence->getArray()[ nLen ] = rListener;
219 return nLen +1;
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;
229 bIsList = sal_True;
230 return 2;
232 else
234 aData.pAsInterface = rListener.get();
235 if( rListener.is() )
236 rListener->acquire();
237 return 1;
241 sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener ) SAL_THROW(())
243 OSL_ASSERT( rListener.is() );
244 MutexGuard aGuard( rMutex );
245 if( bInUse )
246 copyAndResetInUse();
248 if( bIsList )
250 const Reference<XInterface> * pL = aData.pAsSequence->getConstArray();
251 sal_Int32 nLen = aData.pAsSequence->getLength();
252 sal_Int32 i;
253 for( i = 0; i < nLen; i++ )
255 // It is not valid to compare the Pointer direkt, but is is is much
256 // more faster.
257 if( pL[i].get() == rListener.get() )
259 sequenceRemoveElementAt( *aData.pAsSequence, i );
260 break;
264 if( i == nLen )
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 );
272 break;
277 if( aData.pAsSequence->getLength() == 1 )
279 XInterface * p = aData.pAsSequence->getConstArray()[0].get();
280 p->acquire();
281 delete aData.pAsSequence;
282 aData.pAsInterface = p;
283 bIsList = sal_False;
284 return 1;
286 else
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;
307 bIsList = sal_False;
308 bInUse = sal_False;
309 aGuard.clear();
310 while( aIt.hasMoreElements() )
314 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
315 if( xLst.is() )
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;
337 bIsList = sal_False;
338 bInUse = sal_False;
339 // release mutex before aIt destructor call
340 aGuard.clear();
343 // specialized class for type
345 typedef ::std::vector< std::pair < Type , void* > > t_type2ptr;
347 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ )
348 SAL_THROW(())
349 : rMutex( rMutex_ )
351 m_pMap = new t_type2ptr();
353 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
354 SAL_THROW(())
356 t_type2ptr * pMap = (t_type2ptr *)m_pMap;
357 t_type2ptr::iterator iter = pMap->begin();
358 t_type2ptr::iterator end = pMap->end();
360 while( iter != end )
362 delete (OInterfaceContainerHelper*)(*iter).second;
363 (*iter).second = 0;
364 ++iter;
366 delete pMap;
368 Sequence< Type > OMultiTypeInterfaceContainerHelper::getContainedTypes() const
369 SAL_THROW(())
371 t_type2ptr * pMap = (t_type2ptr *)m_pMap;
372 t_type2ptr::size_type nSize;
374 ::osl::MutexGuard aGuard( rMutex );
375 nSize = pMap->size();
376 if( nSize )
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();
384 sal_Int32 i = 0;
385 while( iter != 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;
391 ++iter;
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();
407 while( iter != end )
409 if (iter->first == rKey)
410 break;
411 ++iter;
413 return iter;
416 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelper::getContainer( const Type & rKey ) const
417 SAL_THROW(())
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;
425 return 0;
427 sal_Int32 OMultiTypeInterfaceContainerHelper::addInterface(
428 const Type & rKey, const Reference< XInterface > & rListener )
429 SAL_THROW(())
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 );
440 else
441 return ((OInterfaceContainerHelper*)(*iter).second)->addInterface( rListener );
443 sal_Int32 OMultiTypeInterfaceContainerHelper::removeInterface(
444 const Type & rKey, const Reference< XInterface > & rListener )
445 SAL_THROW(())
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 );
452 // container found?
453 if( iter != pMap->end() )
454 return ((OInterfaceContainerHelper*)(*iter).second)->removeInterface( rListener );
456 // no container with this id. Always return 0
457 return 0;
459 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
460 SAL_THROW(())
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();
468 if( nSize )
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;
478 while( iter != end )
480 ppListenerContainers[i++] = (OInterfaceContainerHelper*)(*iter).second;
481 ++iter;
486 // create a copy, because do not fire event in a guarded section
487 for( t_type2ptr::size_type i = 0;
488 i < nSize; i++ )
490 if( ppListenerContainers[i] )
491 ppListenerContainers[i]->disposeAndClear( rEvt );
494 delete [] ppListenerContainers;
496 void OMultiTypeInterfaceContainerHelper::clear()
497 SAL_THROW(())
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();
504 while( iter != end )
506 ((OInterfaceContainerHelper*)(*iter).second)->clear();
507 ++iter;
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();
520 while( iter != end )
522 if (iter->first == nKey)
523 break;
524 ++iter;
526 return iter;
529 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
530 SAL_THROW(())
531 : m_pMap( NULL )
532 , rMutex( rMutex_ )
534 // delay pMap allocation until necessary.
536 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
537 SAL_THROW(())
539 if (!m_pMap)
540 return;
542 t_long2ptr * pMap = (t_long2ptr *)m_pMap;
543 t_long2ptr::iterator iter = pMap->begin();
544 t_long2ptr::iterator end = pMap->end();
546 while( iter != end )
548 delete (OInterfaceContainerHelper*)(*iter).second;
549 (*iter).second = 0;
550 ++iter;
552 delete pMap;
554 Sequence< sal_Int32 > OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
555 SAL_THROW(())
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;
562 if( nSize )
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();
570 sal_Int32 i = 0;
571 while( iter != 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;
577 ++iter;
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
588 SAL_THROW(())
590 ::osl::MutexGuard aGuard( rMutex );
592 if (!m_pMap)
593 return 0;
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;
598 return 0;
600 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
601 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
602 SAL_THROW(())
604 ::osl::MutexGuard aGuard( rMutex );
605 if (!m_pMap)
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 );
615 else
616 return ((OInterfaceContainerHelper*)(*iter).second)->addInterface( rListener );
618 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::removeInterface(
619 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
620 SAL_THROW(())
622 ::osl::MutexGuard aGuard( rMutex );
624 if (!m_pMap)
625 return 0;
626 // search container with id nUik
627 t_long2ptr * pMap = (t_long2ptr *)m_pMap;
628 t_long2ptr::iterator iter = findLong( pMap, rKey );
629 // container found?
630 if( iter != pMap->end() )
631 return ((OInterfaceContainerHelper*)(*iter).second)->removeInterface( rListener );
633 // no container with this id. Always return 0
634 return 0;
636 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject & rEvt )
637 SAL_THROW(())
639 t_long2ptr::size_type nSize = 0;
640 OInterfaceContainerHelper ** ppListenerContainers = NULL;
642 ::osl::MutexGuard aGuard( rMutex );
643 if (!m_pMap)
644 return;
646 t_long2ptr * pMap = (t_long2ptr *)m_pMap;
647 nSize = pMap->size();
648 if( nSize )
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;
657 while( iter != end )
659 ppListenerContainers[i++] = (OInterfaceContainerHelper*)(*iter).second;
660 ++iter;
665 // create a copy, because do not fire event in a guarded section
666 for( t_long2ptr::size_type i = 0;
667 i < nSize; i++ )
669 if( ppListenerContainers[i] )
670 ppListenerContainers[i]->disposeAndClear( rEvt );
673 delete [] ppListenerContainers;
675 void OMultiTypeInterfaceContainerHelperInt32::clear()
676 SAL_THROW(())
678 ::osl::MutexGuard aGuard( rMutex );
679 if (!m_pMap)
680 return;
681 t_long2ptr * pMap = (t_long2ptr *)m_pMap;
682 t_long2ptr::iterator iter = pMap->begin();
683 t_long2ptr::iterator end = pMap->end();
685 while( iter != end )
687 ((OInterfaceContainerHelper*)(*iter).second)->clear();
688 ++iter;
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */