Bump version to 24.04.3.4
[LibreOffice.git] / cppuhelper / source / interfacecontainer.cxx
blobc97a8ba9908c8d8a1a2bb9fd521c1475aebcb474
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>
23 #include <comphelper/sequence.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <osl/diagnose.h>
27 #include <osl/mutex.hxx>
28 #include <sal/log.hxx>
30 #include <memory>
32 #include <com/sun/star/lang/XEventListener.hpp>
35 using namespace osl;
36 using namespace com::sun::star::uno;
37 using namespace com::sun::star::lang;
39 namespace cppu
42 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
43 : rCont( rCont_ )
45 MutexGuard aGuard( rCont.rMutex );
46 if( rCont.bInUse )
47 // worst case, two iterators at the same time
48 rCont.copyAndResetInUse();
49 bIsList = rCont_.bIsList;
50 aData = rCont_.aData;
51 if( bIsList )
53 rCont.bInUse = true;
54 nRemain = aData.pAsVector->size();
56 else if( aData.pAsInterface )
58 aData.pAsInterface->acquire();
59 nRemain = 1;
61 else
62 nRemain = 0;
65 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
67 bool bShared;
69 MutexGuard aGuard( rCont.rMutex );
70 // bResetInUse protect the iterator against recursion
71 bShared = aData.pAsVector == rCont.aData.pAsVector && rCont.bIsList;
72 if( bShared )
74 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
75 rCont.bInUse = false;
79 if( !bShared )
81 if( bIsList )
82 // Sequence owned by the iterator
83 delete aData.pAsVector;
84 else if( aData.pAsInterface )
85 // Interface is acquired by the iterator
86 aData.pAsInterface->release();
90 XInterface * OInterfaceIteratorHelper::next()
92 if( nRemain )
94 nRemain--;
95 if( bIsList )
96 // typecase to const,so the getArray method is faster
97 return (*aData.pAsVector)[nRemain].get();
98 if( aData.pAsInterface )
99 return aData.pAsInterface;
101 // exception
102 return nullptr;
105 void OInterfaceIteratorHelper::remove()
107 if( bIsList )
109 OSL_ASSERT( nRemain >= 0 &&
110 o3tl::make_unsigned(nRemain) < aData.pAsVector->size() );
111 XInterface * p = (*aData.pAsVector)[nRemain].get();
112 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >( &p ) );
114 else
116 OSL_ASSERT( 0 == nRemain );
117 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
121 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ )
122 : rMutex( rMutex_ )
123 , bInUse( false )
124 , bIsList( false )
128 OInterfaceContainerHelper::~OInterfaceContainerHelper()
130 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
131 if( bIsList )
132 delete aData.pAsVector;
133 else if( aData.pAsInterface )
134 aData.pAsInterface->release();
137 sal_Int32 OInterfaceContainerHelper::getLength() const
139 MutexGuard aGuard( rMutex );
140 if( bIsList )
141 return aData.pAsVector->size();
142 if( aData.pAsInterface )
143 return 1;
144 return 0;
147 Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const
149 MutexGuard aGuard( rMutex );
150 if( bIsList )
151 return comphelper::containerToSequence(*aData.pAsVector);
152 if( aData.pAsInterface )
154 Reference<XInterface> x( aData.pAsInterface );
155 return Sequence< Reference< XInterface > >( &x, 1 );
157 return Sequence< Reference< XInterface > >();
160 void OInterfaceContainerHelper::copyAndResetInUse()
162 OSL_ENSURE( bInUse, "OInterfaceContainerHelper not in use" );
163 if( bInUse )
165 // this should be the worst case. If an iterator is active
166 // and a new Listener is added.
167 if( bIsList )
168 aData.pAsVector= new std::vector< Reference< XInterface > >( *aData.pAsVector );
169 else if( aData.pAsInterface )
170 aData.pAsInterface->acquire();
172 bInUse = false;
176 sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener )
178 SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
179 MutexGuard aGuard( rMutex );
180 if( bInUse )
181 copyAndResetInUse();
183 if( bIsList )
185 aData.pAsVector->push_back(rListener);
186 return aData.pAsVector->size();
188 if( aData.pAsInterface )
190 Reference<XInterface> tmp(aData.pAsInterface);
191 aData.pAsInterface->release();
192 aData.pAsVector = new std::vector<Reference<XInterface>>(2);
193 (*aData.pAsVector)[0] = std::move(tmp);
194 (*aData.pAsVector)[1] = rListener;
195 bIsList = true;
196 return 2;
198 aData.pAsInterface = rListener.get();
199 if( rListener.is() )
200 rListener->acquire();
201 return 1;
204 sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener )
206 SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
207 MutexGuard aGuard( rMutex );
208 if( bInUse )
209 copyAndResetInUse();
211 if( bIsList )
213 // It is not valid to compare the pointer directly, but it's faster.
214 auto findIt = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
215 [&](const Reference<XInterface>& r)
216 { return r.get() == rListener.get(); });
217 if (findIt != aData.pAsVector->end())
219 aData.pAsVector->erase(findIt);
221 else
223 // interface not found, use the correct compare method
224 for( auto it = aData.pAsVector->begin(); it != aData.pAsVector->end(); ++it )
226 if( *it == rListener )
228 aData.pAsVector->erase(it);
229 break;
234 if( aData.pAsVector->size() == 1 )
236 XInterface * p = (*aData.pAsVector)[0].get();
237 p->acquire();
238 delete aData.pAsVector;
239 aData.pAsInterface = p;
240 bIsList = false;
241 return 1;
243 return aData.pAsVector->size();
245 if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
247 aData.pAsInterface->release();
248 aData.pAsInterface = nullptr;
250 return aData.pAsInterface ? 1 : 0;
253 void OInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
255 ClearableMutexGuard aGuard( rMutex );
256 OInterfaceIteratorHelper aIt( *this );
257 // Release container, in case new entries come while disposing
258 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
259 if( !bIsList && aData.pAsInterface )
260 aData.pAsInterface->release();
261 // set the member to null, use the iterator to delete the values
262 aData.pAsInterface = nullptr;
263 bIsList = false;
264 bInUse = false;
265 aGuard.clear();
266 while( aIt.hasMoreElements() )
270 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
271 if( xLst.is() )
272 xLst->disposing( rEvt );
274 catch ( RuntimeException & )
276 // be robust, if e.g. a remote bridge has disposed already.
277 // there is no way to delegate the error to the caller :o(.
283 void OInterfaceContainerHelper::clear()
285 MutexGuard aGuard( rMutex );
286 // Release container, in case new entries come while disposing
287 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
288 if (bInUse)
289 copyAndResetInUse();
290 if (bIsList)
291 delete aData.pAsVector;
292 else if (aData.pAsInterface)
293 aData.pAsInterface->release();
294 aData.pAsInterface = nullptr;
295 bIsList = false;
298 // specialized class for type
300 typedef std::vector< std::pair < Type , void* > > t_type2ptr;
302 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ )
303 : rMutex( rMutex_ )
305 m_pMap = new t_type2ptr;
308 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
310 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
312 for (auto& rItem : *pMap)
314 delete static_cast<OInterfaceContainerHelper*>(rItem.second);
315 rItem.second = nullptr;
317 delete pMap;
320 Sequence< Type > OMultiTypeInterfaceContainerHelper::getContainedTypes() const
322 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
323 t_type2ptr::size_type nSize;
325 ::osl::MutexGuard aGuard( rMutex );
326 nSize = pMap->size();
327 if( nSize )
329 css::uno::Sequence< Type > aInterfaceTypes( nSize );
330 Type * pArray = aInterfaceTypes.getArray();
332 sal_Int32 i = 0;
333 for (const auto& rItem : *pMap)
335 // are interfaces added to this container?
336 if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
337 // yes, put the type in the array
338 pArray[i++] = rItem.first;
340 if( static_cast<t_type2ptr::size_type>(i) != nSize ) {
341 // may be empty container, reduce the sequence to the right size
342 aInterfaceTypes = css::uno::Sequence< Type >( pArray, i );
344 return aInterfaceTypes;
346 return css::uno::Sequence< Type >();
349 static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type & rKey )
351 return std::find_if(pMap->begin(), pMap->end(),
352 [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
355 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelper::getContainer( const Type & rKey ) const
357 ::osl::MutexGuard aGuard( rMutex );
359 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
360 t_type2ptr::iterator iter = findType( pMap, rKey );
361 if( iter != pMap->end() )
362 return static_cast<OInterfaceContainerHelper*>((*iter).second);
363 return nullptr;
366 sal_Int32 OMultiTypeInterfaceContainerHelper::addInterface(
367 const Type & rKey, const Reference< XInterface > & rListener )
369 ::osl::MutexGuard aGuard( rMutex );
370 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
371 t_type2ptr::iterator iter = findType( pMap, rKey );
372 if( iter == pMap->end() )
374 OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex );
375 pMap->push_back(std::pair<Type, void*>(rKey, pLC));
376 return pLC->addInterface( rListener );
378 return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
381 sal_Int32 OMultiTypeInterfaceContainerHelper::removeInterface(
382 const Type & rKey, const Reference< XInterface > & rListener )
384 ::osl::MutexGuard aGuard( rMutex );
386 // search container with id nUik
387 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
388 t_type2ptr::iterator iter = findType( pMap, rKey );
389 // container found?
390 if( iter != pMap->end() )
391 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
393 // no container with this id. Always return 0
394 return 0;
397 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
399 t_type2ptr::size_type nSize = 0;
400 std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
402 ::osl::MutexGuard aGuard( rMutex );
403 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
404 nSize = pMap->size();
405 if( nSize )
407 typedef OInterfaceContainerHelper* ppp;
408 ppListenerContainers.reset(new ppp[nSize]);
409 //ppListenerContainers = new (ListenerContainer*)[nSize];
411 t_type2ptr::size_type i = 0;
412 for (const auto& rItem : *pMap)
414 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
419 // create a copy, because do not fire event in a guarded section
420 for( t_type2ptr::size_type i = 0;
421 i < nSize; i++ )
423 if( ppListenerContainers[i] )
424 ppListenerContainers[i]->disposeAndClear( rEvt );
428 void OMultiTypeInterfaceContainerHelper::clear()
430 ::osl::MutexGuard aGuard( rMutex );
431 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
433 for (auto& rItem : *pMap)
435 static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
439 // specialized class for long
441 typedef std::vector< std::pair < sal_Int32 , void* > > t_long2ptr;
443 static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey )
445 return std::find_if(pMap->begin(), pMap->end(),
446 [&nKey](const t_long2ptr::value_type& rItem) { return rItem.first == nKey; });
449 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
450 : m_pMap( nullptr )
451 , rMutex( rMutex_ )
453 // delay pMap allocation until necessary.
456 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
458 if (!m_pMap)
459 return;
461 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
463 for (auto& rItem : *pMap)
465 delete static_cast<OInterfaceContainerHelper*>(rItem.second);
466 rItem.second = nullptr;
468 delete pMap;
471 Sequence< sal_Int32 > OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
473 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
474 t_long2ptr::size_type nSize;
476 ::osl::MutexGuard aGuard( rMutex );
477 nSize = pMap ? pMap->size() : 0;
478 if( nSize )
480 css::uno::Sequence< sal_Int32 > aInterfaceTypes( nSize );
481 sal_Int32 * pArray = aInterfaceTypes.getArray();
483 sal_Int32 i = 0;
484 for (const auto& rItem : *pMap)
486 // are interfaces added to this container?
487 if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
488 // yes, put the type in the array
489 pArray[i++] = rItem.first;
491 if( static_cast<t_long2ptr::size_type>(i) != nSize ) {
492 // may be empty container, reduce the sequence to the right size
493 aInterfaceTypes = css::uno::Sequence< sal_Int32 >( pArray, i );
495 return aInterfaceTypes;
497 return css::uno::Sequence< sal_Int32 >();
500 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32 & rKey ) const
502 ::osl::MutexGuard aGuard( rMutex );
504 if (!m_pMap)
505 return nullptr;
506 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
507 t_long2ptr::iterator iter = findLong( pMap, rKey );
508 if( iter != pMap->end() )
509 return static_cast<OInterfaceContainerHelper*>((*iter).second);
510 return nullptr;
513 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
514 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
516 ::osl::MutexGuard aGuard( rMutex );
517 if (!m_pMap)
518 m_pMap = new t_long2ptr;
519 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
520 t_long2ptr::iterator iter = findLong( pMap, rKey );
521 if( iter == pMap->end() )
523 OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex );
524 pMap->push_back(std::pair< sal_Int32, void* >(rKey, pLC));
525 return pLC->addInterface( rListener );
527 return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
530 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::removeInterface(
531 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
533 ::osl::MutexGuard aGuard( rMutex );
535 if (!m_pMap)
536 return 0;
537 // search container with id nUik
538 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
539 t_long2ptr::iterator iter = findLong( pMap, rKey );
540 // container found?
541 if( iter != pMap->end() )
542 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
544 // no container with this id. Always return 0
545 return 0;
548 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject & rEvt )
550 t_long2ptr::size_type nSize = 0;
551 std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
553 ::osl::MutexGuard aGuard( rMutex );
554 if (!m_pMap)
555 return;
557 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
558 nSize = pMap->size();
559 if( nSize )
561 typedef OInterfaceContainerHelper* ppp;
562 ppListenerContainers.reset(new ppp[nSize]);
564 t_long2ptr::size_type i = 0;
565 for (const auto& rItem : *pMap)
567 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
572 // create a copy, because do not fire event in a guarded section
573 for( t_long2ptr::size_type i = 0;
574 i < nSize; i++ )
576 if( ppListenerContainers[i] )
577 ppListenerContainers[i]->disposeAndClear( rEvt );
581 void OMultiTypeInterfaceContainerHelperInt32::clear()
583 ::osl::MutexGuard aGuard( rMutex );
584 if (!m_pMap)
585 return;
586 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
588 for (auto& rItem : *pMap)
590 static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */