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 <osl/diagnose.h>
26 #include <osl/mutex.hxx>
27 #include <sal/log.hxx>
31 #include <com/sun/star/lang/XEventListener.hpp>
35 using namespace com::sun::star::uno
;
36 using namespace com::sun::star::lang
;
41 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper
& rCont_
)
44 MutexGuard
aGuard( rCont
.rMutex
);
46 // worst case, two iterators at the same time
47 rCont
.copyAndResetInUse();
48 bIsList
= rCont_
.bIsList
;
53 nRemain
= aData
.pAsVector
->size();
55 else if( aData
.pAsInterface
)
57 aData
.pAsInterface
->acquire();
64 OInterfaceIteratorHelper::~OInterfaceIteratorHelper()
68 MutexGuard
aGuard( rCont
.rMutex
);
69 // bResetInUse protect the iterator against recursion
70 bShared
= aData
.pAsVector
== rCont
.aData
.pAsVector
&& rCont
.bIsList
;
73 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper must be in use" );
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()
95 // typecase to const,so the getArray method is faster
96 return (*aData
.pAsVector
)[nRemain
].get();
97 if( aData
.pAsInterface
)
98 return aData
.pAsInterface
;
104 void OInterfaceIteratorHelper::remove()
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
) );
115 OSL_ASSERT( 0 == nRemain
);
116 rCont
.removeInterface( * reinterpret_cast< const Reference
< XInterface
> * >(&aData
.pAsInterface
));
120 OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex
& rMutex_
)
127 OInterfaceContainerHelper::~OInterfaceContainerHelper()
129 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper but is in use" );
131 delete aData
.pAsVector
;
132 else if( aData
.pAsInterface
)
133 aData
.pAsInterface
->release();
136 sal_Int32
OInterfaceContainerHelper::getLength() const
138 MutexGuard
aGuard( rMutex
);
140 return aData
.pAsVector
->size();
141 if( aData
.pAsInterface
)
146 Sequence
< Reference
<XInterface
> > OInterfaceContainerHelper::getElements() const
148 MutexGuard
aGuard( rMutex
);
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" );
164 // this should be the worst case. If an iterator is active
165 // and a new Listener is added.
167 aData
.pAsVector
= new std::vector
< Reference
< XInterface
> >( *aData
.pAsVector
);
168 else if( aData
.pAsInterface
)
169 aData
.pAsInterface
->acquire();
175 sal_Int32
OInterfaceContainerHelper::addInterface( const Reference
<XInterface
> & rListener
)
177 SAL_WARN_IF( !rListener
.is(), "cppuhelper", "rListener is empty" );
178 MutexGuard
aGuard( rMutex
);
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
;
197 aData
.pAsInterface
= rListener
.get();
199 rListener
->acquire();
203 sal_Int32
OInterfaceContainerHelper::removeInterface( const Reference
<XInterface
> & rListener
)
205 SAL_WARN_IF( !rListener
.is(), "cppuhelper", "rListener is empty" );
206 MutexGuard
aGuard( rMutex
);
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
);
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
);
233 if( aData
.pAsVector
->size() == 1 )
235 XInterface
* p
= (*aData
.pAsVector
)[0].get();
237 delete aData
.pAsVector
;
238 aData
.pAsInterface
= p
;
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;
265 while( aIt
.hasMoreElements() )
269 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
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" );
290 delete aData
.pAsVector
;
291 else if (aData
.pAsInterface
)
292 aData
.pAsInterface
->release();
293 aData
.pAsInterface
= nullptr;
297 // specialized class for type
299 typedef std::vector
< std::pair
< Type
, void* > > t_type2ptr
;
301 OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex
& 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;
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();
328 css::uno::Sequence
< Type
> aInterfaceTypes( nSize
);
329 Type
* pArray
= aInterfaceTypes
.getArray();
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
);
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
);
389 if( iter
!= pMap
->end() )
390 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
392 // no container with this id. Always 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();
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;
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_
)
452 // delay pMap allocation until necessary.
455 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
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;
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;
479 css::uno::Sequence
< sal_Int32
> aInterfaceTypes( nSize
);
480 sal_Int32
* pArray
= aInterfaceTypes
.getArray();
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
);
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
);
512 sal_Int32
OMultiTypeInterfaceContainerHelperInt32::addInterface(
513 const sal_Int32
& rKey
, const Reference
< XInterface
> & rListener
)
515 ::osl::MutexGuard
aGuard( rMutex
);
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
);
536 // search container with id nUik
537 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
538 t_long2ptr::iterator iter
= findLong( pMap
, rKey
);
540 if( iter
!= pMap
->end() )
541 return static_cast<OInterfaceContainerHelper
*>((*iter
).second
)->removeInterface( rListener
);
543 // no container with this id. Always 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
);
556 t_long2ptr
* pMap
= static_cast<t_long2ptr
*>(m_pMap
);
557 nSize
= pMap
->size();
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;
575 if( ppListenerContainers
[i
] )
576 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
580 void OMultiTypeInterfaceContainerHelperInt32::clear()
582 ::osl::MutexGuard
aGuard( rMutex
);
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: */