bump product version to 7.2.5.1
[LibreOffice.git] / cppuhelper / source / interfacecontainer.cxx
blob035f93848bf2836e367c8ff99ac947939f164b3e
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 <osl/diagnose.h>
26 #include <osl/mutex.hxx>
27 #include <sal/log.hxx>
29 #include <memory>
31 #include <com/sun/star/lang/XEventListener.hpp>
34 using namespace osl;
35 using namespace com::sun::star::uno;
36 using namespace com::sun::star::lang;
38 namespace cppu
41 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
42 : rCont( rCont_ )
44 MutexGuard aGuard( rCont.rMutex );
45 if( rCont.bInUse )
46 // worst case, two iterators at the same time
47 rCont.copyAndResetInUse();
48 bIsList = rCont_.bIsList;
49 aData = rCont_.aData;
50 if( bIsList )
52 rCont.bInUse = true;
53 nRemain = aData.pAsVector->size();
55 else if( aData.pAsInterface )
57 aData.pAsInterface->acquire();
58 nRemain = 1;
60 else
61 nRemain = 0;
64 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
66 bool bShared;
68 MutexGuard aGuard( rCont.rMutex );
69 // bResetInUse protect the iterator against recursion
70 bShared = aData.pAsVector == rCont.aData.pAsVector && rCont.bIsList;
71 if( bShared )
73 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
74 rCont.bInUse = false;
78 if( !bShared )
80 if( bIsList )
81 // Sequence owned by the iterator
82 delete aData.pAsVector;
83 else if( aData.pAsInterface )
84 // Interface is acquired by the iterator
85 aData.pAsInterface->release();
89 XInterface * OInterfaceIteratorHelper::next()
91 if( nRemain )
93 nRemain--;
94 if( bIsList )
95 // typecase to const,so the getArray method is faster
96 return (*aData.pAsVector)[nRemain].get();
97 if( aData.pAsInterface )
98 return aData.pAsInterface;
100 // exception
101 return nullptr;
104 void OInterfaceIteratorHelper::remove()
106 if( bIsList )
108 OSL_ASSERT( nRemain >= 0 &&
109 nRemain < static_cast<sal_Int32>(aData.pAsVector->size()) );
110 XInterface * p = (*aData.pAsVector)[nRemain].get();
111 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >( &p ) );
113 else
115 OSL_ASSERT( 0 == nRemain );
116 rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
120 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ )
121 : rMutex( rMutex_ )
122 , bInUse( false )
123 , bIsList( false )
127 OInterfaceContainerHelper::~OInterfaceContainerHelper()
129 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
130 if( bIsList )
131 delete aData.pAsVector;
132 else if( aData.pAsInterface )
133 aData.pAsInterface->release();
136 sal_Int32 OInterfaceContainerHelper::getLength() const
138 MutexGuard aGuard( rMutex );
139 if( bIsList )
140 return aData.pAsVector->size();
141 if( aData.pAsInterface )
142 return 1;
143 return 0;
146 Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const
148 MutexGuard aGuard( rMutex );
149 if( bIsList )
150 return comphelper::containerToSequence(*aData.pAsVector);
151 if( aData.pAsInterface )
153 Reference<XInterface> x( aData.pAsInterface );
154 return Sequence< Reference< XInterface > >( &x, 1 );
156 return Sequence< Reference< XInterface > >();
159 void OInterfaceContainerHelper::copyAndResetInUse()
161 OSL_ENSURE( bInUse, "OInterfaceContainerHelper not in use" );
162 if( bInUse )
164 // this should be the worst case. If an iterator is active
165 // and a new Listener is added.
166 if( bIsList )
167 aData.pAsVector= new std::vector< Reference< XInterface > >( *aData.pAsVector );
168 else if( aData.pAsInterface )
169 aData.pAsInterface->acquire();
171 bInUse = false;
175 sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener )
177 SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
178 MutexGuard aGuard( rMutex );
179 if( bInUse )
180 copyAndResetInUse();
182 if( bIsList )
184 aData.pAsVector->push_back(rListener);
185 return aData.pAsVector->size();
187 if( aData.pAsInterface )
189 Reference<XInterface> tmp(aData.pAsInterface);
190 aData.pAsInterface->release();
191 aData.pAsVector = new std::vector<Reference<XInterface>>(2);
192 (*aData.pAsVector)[0] = std::move(tmp);
193 (*aData.pAsVector)[1] = rListener;
194 bIsList = true;
195 return 2;
197 aData.pAsInterface = rListener.get();
198 if( rListener.is() )
199 rListener->acquire();
200 return 1;
203 sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener )
205 SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
206 MutexGuard aGuard( rMutex );
207 if( bInUse )
208 copyAndResetInUse();
210 if( bIsList )
212 // It is not valid to compare the pointer directly, but it's faster.
213 auto findIt = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
214 [&](const Reference<XInterface>& r)
215 { return r.get() == rListener.get(); });
216 if (findIt != aData.pAsVector->end())
218 aData.pAsVector->erase(findIt);
220 else
222 // interface not found, use the correct compare method
223 for( auto it = aData.pAsVector->begin(); it != aData.pAsVector->end(); ++it )
225 if( *it == rListener )
227 aData.pAsVector->erase(it);
228 break;
233 if( aData.pAsVector->size() == 1 )
235 XInterface * p = (*aData.pAsVector)[0].get();
236 p->acquire();
237 delete aData.pAsVector;
238 aData.pAsInterface = p;
239 bIsList = false;
240 return 1;
242 return aData.pAsVector->size();
244 if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
246 aData.pAsInterface->release();
247 aData.pAsInterface = nullptr;
249 return aData.pAsInterface ? 1 : 0;
252 void OInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
254 ClearableMutexGuard aGuard( rMutex );
255 OInterfaceIteratorHelper aIt( *this );
256 // Release container, in case new entries come while disposing
257 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
258 if( !bIsList && aData.pAsInterface )
259 aData.pAsInterface->release();
260 // set the member to null, use the iterator to delete the values
261 aData.pAsInterface = nullptr;
262 bIsList = false;
263 bInUse = false;
264 aGuard.clear();
265 while( aIt.hasMoreElements() )
269 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
270 if( xLst.is() )
271 xLst->disposing( rEvt );
273 catch ( RuntimeException & )
275 // be robust, if e.g. a remote bridge has disposed already.
276 // there is no way to delegate the error to the caller :o(.
282 void OInterfaceContainerHelper::clear()
284 MutexGuard aGuard( rMutex );
285 // Release container, in case new entries come while disposing
286 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
287 if (bInUse)
288 copyAndResetInUse();
289 if (bIsList)
290 delete aData.pAsVector;
291 else if (aData.pAsInterface)
292 aData.pAsInterface->release();
293 aData.pAsInterface = nullptr;
294 bIsList = false;
297 // specialized class for type
299 typedef std::vector< std::pair < Type , void* > > t_type2ptr;
301 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ )
302 : rMutex( rMutex_ )
304 m_pMap = new t_type2ptr;
307 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
309 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
311 for (auto& rItem : *pMap)
313 delete static_cast<OInterfaceContainerHelper*>(rItem.second);
314 rItem.second = nullptr;
316 delete pMap;
319 Sequence< Type > OMultiTypeInterfaceContainerHelper::getContainedTypes() const
321 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
322 t_type2ptr::size_type nSize;
324 ::osl::MutexGuard aGuard( rMutex );
325 nSize = pMap->size();
326 if( nSize )
328 css::uno::Sequence< Type > aInterfaceTypes( nSize );
329 Type * pArray = aInterfaceTypes.getArray();
331 sal_Int32 i = 0;
332 for (const auto& rItem : *pMap)
334 // are interfaces added to this container?
335 if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
336 // yes, put the type in the array
337 pArray[i++] = rItem.first;
339 if( static_cast<t_type2ptr::size_type>(i) != nSize ) {
340 // may be empty container, reduce the sequence to the right size
341 aInterfaceTypes = css::uno::Sequence< Type >( pArray, i );
343 return aInterfaceTypes;
345 return css::uno::Sequence< Type >();
348 static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type & rKey )
350 return std::find_if(pMap->begin(), pMap->end(),
351 [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
354 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelper::getContainer( const Type & rKey ) const
356 ::osl::MutexGuard aGuard( rMutex );
358 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
359 t_type2ptr::iterator iter = findType( pMap, rKey );
360 if( iter != pMap->end() )
361 return static_cast<OInterfaceContainerHelper*>((*iter).second);
362 return nullptr;
365 sal_Int32 OMultiTypeInterfaceContainerHelper::addInterface(
366 const Type & rKey, const Reference< XInterface > & rListener )
368 ::osl::MutexGuard aGuard( rMutex );
369 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
370 t_type2ptr::iterator iter = findType( pMap, rKey );
371 if( iter == pMap->end() )
373 OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex );
374 pMap->push_back(std::pair<Type, void*>(rKey, pLC));
375 return pLC->addInterface( rListener );
377 return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
380 sal_Int32 OMultiTypeInterfaceContainerHelper::removeInterface(
381 const Type & rKey, const Reference< XInterface > & rListener )
383 ::osl::MutexGuard aGuard( rMutex );
385 // search container with id nUik
386 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
387 t_type2ptr::iterator iter = findType( pMap, rKey );
388 // container found?
389 if( iter != pMap->end() )
390 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
392 // no container with this id. Always return 0
393 return 0;
396 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
398 t_type2ptr::size_type nSize = 0;
399 std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
401 ::osl::MutexGuard aGuard( rMutex );
402 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
403 nSize = pMap->size();
404 if( nSize )
406 typedef OInterfaceContainerHelper* ppp;
407 ppListenerContainers.reset(new ppp[nSize]);
408 //ppListenerContainers = new (ListenerContainer*)[nSize];
410 t_type2ptr::size_type i = 0;
411 for (const auto& rItem : *pMap)
413 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
418 // create a copy, because do not fire event in a guarded section
419 for( t_type2ptr::size_type i = 0;
420 i < nSize; i++ )
422 if( ppListenerContainers[i] )
423 ppListenerContainers[i]->disposeAndClear( rEvt );
427 void OMultiTypeInterfaceContainerHelper::clear()
429 ::osl::MutexGuard aGuard( rMutex );
430 t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
432 for (auto& rItem : *pMap)
434 static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
438 // specialized class for long
440 typedef std::vector< std::pair < sal_Int32 , void* > > t_long2ptr;
442 static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey )
444 return std::find_if(pMap->begin(), pMap->end(),
445 [&nKey](const t_long2ptr::value_type& rItem) { return rItem.first == nKey; });
448 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
449 : m_pMap( nullptr )
450 , rMutex( rMutex_ )
452 // delay pMap allocation until necessary.
455 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
457 if (!m_pMap)
458 return;
460 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
462 for (auto& rItem : *pMap)
464 delete static_cast<OInterfaceContainerHelper*>(rItem.second);
465 rItem.second = nullptr;
467 delete pMap;
470 Sequence< sal_Int32 > OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
472 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
473 t_long2ptr::size_type nSize;
475 ::osl::MutexGuard aGuard( rMutex );
476 nSize = pMap ? pMap->size() : 0;
477 if( nSize )
479 css::uno::Sequence< sal_Int32 > aInterfaceTypes( nSize );
480 sal_Int32 * pArray = aInterfaceTypes.getArray();
482 sal_Int32 i = 0;
483 for (const auto& rItem : *pMap)
485 // are interfaces added to this container?
486 if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
487 // yes, put the type in the array
488 pArray[i++] = rItem.first;
490 if( static_cast<t_long2ptr::size_type>(i) != nSize ) {
491 // may be empty container, reduce the sequence to the right size
492 aInterfaceTypes = css::uno::Sequence< sal_Int32 >( pArray, i );
494 return aInterfaceTypes;
496 return css::uno::Sequence< sal_Int32 >();
499 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32 & rKey ) const
501 ::osl::MutexGuard aGuard( rMutex );
503 if (!m_pMap)
504 return nullptr;
505 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
506 t_long2ptr::iterator iter = findLong( pMap, rKey );
507 if( iter != pMap->end() )
508 return static_cast<OInterfaceContainerHelper*>((*iter).second);
509 return nullptr;
512 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
513 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
515 ::osl::MutexGuard aGuard( rMutex );
516 if (!m_pMap)
517 m_pMap = new t_long2ptr;
518 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
519 t_long2ptr::iterator iter = findLong( pMap, rKey );
520 if( iter == pMap->end() )
522 OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex );
523 pMap->push_back(std::pair< sal_Int32, void* >(rKey, pLC));
524 return pLC->addInterface( rListener );
526 return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
529 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::removeInterface(
530 const sal_Int32 & rKey, const Reference< XInterface > & rListener )
532 ::osl::MutexGuard aGuard( rMutex );
534 if (!m_pMap)
535 return 0;
536 // search container with id nUik
537 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
538 t_long2ptr::iterator iter = findLong( pMap, rKey );
539 // container found?
540 if( iter != pMap->end() )
541 return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
543 // no container with this id. Always return 0
544 return 0;
547 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject & rEvt )
549 t_long2ptr::size_type nSize = 0;
550 std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
552 ::osl::MutexGuard aGuard( rMutex );
553 if (!m_pMap)
554 return;
556 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
557 nSize = pMap->size();
558 if( nSize )
560 typedef OInterfaceContainerHelper* ppp;
561 ppListenerContainers.reset(new ppp[nSize]);
563 t_long2ptr::size_type i = 0;
564 for (const auto& rItem : *pMap)
566 ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
571 // create a copy, because do not fire event in a guarded section
572 for( t_long2ptr::size_type i = 0;
573 i < nSize; i++ )
575 if( ppListenerContainers[i] )
576 ppListenerContainers[i]->disposeAndClear( rEvt );
580 void OMultiTypeInterfaceContainerHelperInt32::clear()
582 ::osl::MutexGuard aGuard( rMutex );
583 if (!m_pMap)
584 return;
585 t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
587 for (auto& rItem : *pMap)
589 static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
595 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */