Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / cppuhelper / source / interfacecontainer.cxx
blob7b97c315343d110cf17bba847772e66e438eb57b
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/propshlp.hxx>
24 #include <osl/diagnose.h>
25 #include <osl/mutex.hxx>
27 #include <memory>
29 #include <com/sun/star/lang/XEventListener.hpp>
32 using namespace osl;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::lang;
36 namespace cppu
38 /**
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();
49 sal_Int32 i = 0;
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];
54 rSeq = aDestSeq;
57 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
58 : rCont( rCont_ )
60 MutexGuard aGuard( rCont.rMutex );
61 if( rCont.bInUse )
62 // worst case, two iterators at the same time
63 rCont.copyAndResetInUse();
64 bIsList = rCont_.bIsList;
65 aData = rCont_.aData;
66 if( bIsList )
68 rCont.bInUse = true;
69 nRemain = aData.pAsSequence->getLength();
71 else if( aData.pAsInterface )
73 aData.pAsInterface->acquire();
74 nRemain = 1;
76 else
77 nRemain = 0;
80 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
82 bool bShared;
84 MutexGuard aGuard( rCont.rMutex );
85 // bResetInUse protect the iterator against recursion
86 bShared = aData.pAsSequence == rCont.aData.pAsSequence && rCont.bIsList;
87 if( bShared )
89 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
90 rCont.bInUse = false;
94 if( !bShared )
96 if( bIsList )
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()
107 if( nRemain )
109 nRemain--;
110 if( bIsList )
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;
116 // exception
117 return nullptr;
120 void OInterfaceIteratorHelper::remove()
122 if( bIsList )
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 ) );
129 else
131 OSL_ASSERT( 0 == nRemain );
132 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
136 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ )
137 : rMutex( rMutex_ )
138 , bInUse( false )
139 , bIsList( false )
143 OInterfaceContainerHelper::~OInterfaceContainerHelper()
145 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
146 if( bIsList )
147 delete aData.pAsSequence;
148 else if( aData.pAsInterface )
149 aData.pAsInterface->release();
152 sal_Int32 OInterfaceContainerHelper::getLength() const
154 MutexGuard aGuard( rMutex );
155 if( bIsList )
156 return aData.pAsSequence->getLength();
157 if( aData.pAsInterface )
158 return 1;
159 return 0;
162 Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const
164 MutexGuard aGuard( rMutex );
165 if( bIsList )
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" );
178 if( bInUse )
180 // this should be the worst case. If an iterator is active
181 // and a new Listener is added.
182 if( bIsList )
183 aData.pAsSequence = new Sequence< Reference< XInterface > >( *aData.pAsSequence );
184 else if( aData.pAsInterface )
185 aData.pAsInterface->acquire();
187 bInUse = false;
191 sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener )
193 OSL_ASSERT( rListener.is() );
194 MutexGuard aGuard( rMutex );
195 if( bInUse )
196 copyAndResetInUse();
198 if( bIsList )
200 sal_Int32 nLen = aData.pAsSequence->getLength();
201 aData.pAsSequence->realloc( nLen +1 );
202 aData.pAsSequence->getArray()[ nLen ] = rListener;
203 return nLen +1;
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;
213 bIsList = true;
214 return 2;
216 aData.pAsInterface = rListener.get();
217 if( rListener.is() )
218 rListener->acquire();
219 return 1;
222 sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener )
224 OSL_ASSERT( rListener.is() );
225 MutexGuard aGuard( rMutex );
226 if( bInUse )
227 copyAndResetInUse();
229 if( bIsList )
231 const Reference<XInterface> * pL = aData.pAsSequence->getConstArray();
232 sal_Int32 nLen = aData.pAsSequence->getLength();
233 sal_Int32 i;
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 );
240 break;
244 if( i == nLen )
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 );
252 break;
257 if( aData.pAsSequence->getLength() == 1 )
259 XInterface * p = aData.pAsSequence->getConstArray()[0].get();
260 p->acquire();
261 delete aData.pAsSequence;
262 aData.pAsInterface = p;
263 bIsList = false;
264 return 1;
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;
286 bIsList = false;
287 bInUse = false;
288 aGuard.clear();
289 while( aIt.hasMoreElements() )
293 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
294 if( xLst.is() )
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;
316 bIsList = false;
317 bInUse = false;
318 // release mutex before aIt destructor call
319 aGuard.clear();
322 // specialized class for type
324 typedef std::vector< std::pair < Type , void* > > t_type2ptr;
326 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ )
327 : rMutex( 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;
341 delete pMap;
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();
351 if( nSize )
353 css::uno::Sequence< Type > aInterfaceTypes( nSize );
354 Type * pArray = aInterfaceTypes.getArray();
356 sal_Int32 i = 0;
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);
387 return nullptr;
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 );
413 // container found?
414 if( iter != pMap->end() )
415 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
417 // no container with this id. Always return 0
418 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();
429 if( nSize )
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;
445 i < nSize; i++ )
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_ )
474 : m_pMap( nullptr )
475 , rMutex( rMutex_ )
477 // delay pMap allocation until necessary.
480 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
482 if (!m_pMap)
483 return;
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;
492 delete pMap;
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;
502 if( nSize )
504 css::uno::Sequence< sal_Int32 > aInterfaceTypes( nSize );
505 sal_Int32 * pArray = aInterfaceTypes.getArray();
507 sal_Int32 i = 0;
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 );
528 if (!m_pMap)
529 return nullptr;
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);
534 return nullptr;
537 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
538 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
540 ::osl::MutexGuard aGuard( rMutex );
541 if (!m_pMap)
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 );
559 if (!m_pMap)
560 return 0;
561 // search container with id nUik
562 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
563 t_long2ptr::iterator iter = findLong( pMap, rKey );
564 // container found?
565 if( iter != pMap->end() )
566 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
568 // no container with this id. Always return 0
569 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 );
578 if (!m_pMap)
579 return;
581 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
582 nSize = pMap->size();
583 if( nSize )
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;
598 i < nSize; i++ )
600 if( ppListenerContainers[i] )
601 ppListenerContainers[i]->disposeAndClear( rEvt );
605 void OMultiTypeInterfaceContainerHelperInt32::clear()
607 ::osl::MutexGuard aGuard( rMutex );
608 if (!m_pMap)
609 return;
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: */