1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
32 #include <com/sun/star/lang/XEventListener.hpp>
36 using namespace com::sun::star::uno
;
37 using namespace com::sun::star::lang
;
42 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper
& rCont_
)
45 MutexGuard
aGuard( rCont
.rMutex
);
47 // worst case, two iterators at the same time
48 rCont
.copyAndResetInUse();
49 bIsList
= rCont_
.bIsList
;
54 nRemain
= aData
.pAsVector
->size();
56 else if( aData
.pAsInterface
)
58 aData
.pAsInterface
->acquire();
65 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
69 MutexGuard
aGuard( rCont
.rMutex
);
70 // bResetInUse protect the iterator against recursion
71 bShared
= aData
.pAsVector
== rCont
.aData
.pAsVector
&& rCont
.bIsList
;
74 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper must be in use" );
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()
96 // typecase to const,so the getArray method is faster
97 return (*aData
.pAsVector
)[nRemain
].get();
98 if( aData
.pAsInterface
)
99 return aData
.pAsInterface
;
105 void OInterfaceIteratorHelper::remove()
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
) );
116 OSL_ASSERT( 0 == nRemain
);
117 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >(&aData
.pAsInterface
));
121 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex
& rMutex_
)
128 OInterfaceContainerHelper::~OInterfaceContainerHelper()
130 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper but is in use" );
132 delete aData
.pAsVector
;
133 else if( aData
.pAsInterface
)
134 aData
.pAsInterface
->release();
137 sal_Int32
OInterfaceContainerHelper::getLength() const
139 MutexGuard
aGuard( rMutex
);
141 return aData
.pAsVector
->size();
142 if( aData
.pAsInterface
)
147 Sequence
< Reference
<XInterface
> > OInterfaceContainerHelper::getElements() const
149 MutexGuard
aGuard( rMutex
);
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" );
165 // this should be the worst case. If an iterator is active
166 // and a new Listener is added.
168 aData
.pAsVector
= new std::vector
< Reference
< XInterface
> >( *aData
.pAsVector
);
169 else if( aData
.pAsInterface
)
170 aData
.pAsInterface
->acquire();
176 sal_Int32
OInterfaceContainerHelper::addInterface( const Reference
<XInterface
> & rListener
)
178 SAL_WARN_IF( !rListener
.is(), "cppuhelper", "rListener is empty" );
179 MutexGuard
aGuard( rMutex
);
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
;
198 aData
.pAsInterface
= rListener
.get();
200 rListener
->acquire();
204 sal_Int32
OInterfaceContainerHelper::removeInterface( const Reference
<XInterface
> & rListener
)
206 SAL_WARN_IF( !rListener
.is(), "cppuhelper", "rListener is empty" );
207 MutexGuard
aGuard( rMutex
);
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
);
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
);
234 if( aData
.pAsVector
->size() == 1 )
236 XInterface
* p
= (*aData
.pAsVector
)[0].get();
238 delete aData
.pAsVector
;
239 aData
.pAsInterface
= p
;
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;
266 while( aIt
.hasMoreElements() )
270 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
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" );
291 delete aData
.pAsVector
;
292 else if (aData
.pAsInterface
)
293 aData
.pAsInterface
->release();
294 aData
.pAsInterface
= nullptr;
298 // specialized class for type
300 typedef std::vector
< std::pair
< Type
, void* > > t_type2ptr
;
302 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex
& 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;
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();
329 css::uno::Sequence
< Type
> aInterfaceTypes( nSize
);
330 Type
* pArray
= aInterfaceTypes
.getArray();
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
);
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
);
390 if( iter
!= pMap
->end() )
391 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
393 // no container with this id. Always 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();
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;
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_
)
453 // delay pMap allocation until necessary.
456 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
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;
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;
480 css::uno::Sequence
< sal_Int32
> aInterfaceTypes( nSize
);
481 sal_Int32
* pArray
= aInterfaceTypes
.getArray();
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
);
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
);
513 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::addInterface(
514 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
516 ::osl::MutexGuard
aGuard( rMutex
);
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
);
537 // search container with id nUik
538 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
539 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
541 if( iter
!= pMap
->end() )
542 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
544 // no container with this id. Always 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
);
557 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
558 nSize
= pMap
->size();
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;
576 if( ppListenerContainers
[i
] )
577 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
581 void OMultiTypeInterfaceContainerHelperInt32::clear()
583 ::osl::MutexGuard
aGuard( rMutex
);
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: */