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 <comphelper/interfacecontainer2.hxx>
22 #include <comphelper/multicontainer2.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <osl/diagnose.h>
26 #include <osl/mutex.hxx>
30 #include <com/sun/star/lang/XEventListener.hpp>
34 using namespace com::sun::star::uno
;
35 using namespace com::sun::star::lang
;
40 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2
& rCont_
)
43 MutexGuard
aGuard( rCont
.rMutex
);
45 // worst case, two iterators at the same time
46 rCont
.copyAndResetInUse();
47 bIsList
= rCont_
.bIsList
;
52 nRemain
= aData
.pAsVector
->size();
54 else if( aData
.pAsInterface
)
56 aData
.pAsInterface
->acquire();
63 OInterfaceIteratorHelper2::~OInterfaceIteratorHelper2()
67 MutexGuard
aGuard( rCont
.rMutex
);
68 // bResetInUse protect the iterator against recursion
69 bShared
= aData
.pAsVector
== rCont
.aData
.pAsVector
&& rCont
.bIsList
;
72 OSL_ENSURE( rCont
.bInUse
, "OInterfaceContainerHelper2 must be in use" );
80 // Sequence owned by the iterator
81 delete aData
.pAsVector
;
82 else if( aData
.pAsInterface
)
83 // Interface is acquired by the iterator
84 aData
.pAsInterface
->release();
88 XInterface
* OInterfaceIteratorHelper2::next()
94 return (*aData
.pAsVector
)[nRemain
].get();
95 else if( aData
.pAsInterface
)
96 return aData
.pAsInterface
;
102 void OInterfaceIteratorHelper2::remove()
106 OSL_ASSERT( nRemain
>= 0 &&
107 o3tl::make_unsigned(nRemain
) < aData
.pAsVector
->size() );
108 rCont
.removeInterface( (*aData
.pAsVector
)[nRemain
] );
112 OSL_ASSERT( 0 == nRemain
);
113 rCont
.removeInterface( aData
.pAsInterface
);
117 OInterfaceContainerHelper2::OInterfaceContainerHelper2( Mutex
& rMutex_
)
124 OInterfaceContainerHelper2::~OInterfaceContainerHelper2()
126 OSL_ENSURE( !bInUse
, "~OInterfaceContainerHelper2 but is in use" );
128 delete aData
.pAsVector
;
129 else if( aData
.pAsInterface
)
130 aData
.pAsInterface
->release();
133 sal_Int32
OInterfaceContainerHelper2::getLength() const
135 MutexGuard
aGuard( rMutex
);
137 return aData
.pAsVector
->size();
138 else if( aData
.pAsInterface
)
143 std::vector
< Reference
<XInterface
> > OInterfaceContainerHelper2::getElements() const
145 std::vector
< Reference
<XInterface
> > rVec
;
146 MutexGuard
aGuard( rMutex
);
148 rVec
= *aData
.pAsVector
;
149 else if( aData
.pAsInterface
)
151 rVec
.emplace_back( aData
.pAsInterface
);
156 void OInterfaceContainerHelper2::copyAndResetInUse()
158 OSL_ENSURE( bInUse
, "OInterfaceContainerHelper2 not in use" );
161 // this should be the worst case. If an iterator is active
162 // and a new Listener is added.
164 aData
.pAsVector
= new std::vector
< Reference
< XInterface
> >( *aData
.pAsVector
);
165 else if( aData
.pAsInterface
)
166 aData
.pAsInterface
->acquire();
172 sal_Int32
OInterfaceContainerHelper2::addInterface( const Reference
<XInterface
> & rListener
)
174 OSL_ASSERT( rListener
.is() );
175 MutexGuard
aGuard( rMutex
);
181 aData
.pAsVector
->push_back( rListener
);
182 return aData
.pAsVector
->size();
184 else if( aData
.pAsInterface
)
186 std::vector
< Reference
< XInterface
> > * pVec
= new std::vector
< Reference
< XInterface
> >( 2 );
187 (*pVec
)[0] = aData
.pAsInterface
;
188 (*pVec
)[1] = rListener
;
189 aData
.pAsInterface
->release();
190 aData
.pAsVector
= pVec
;
196 aData
.pAsInterface
= rListener
.get();
198 rListener
->acquire();
203 sal_Int32
OInterfaceContainerHelper2::removeInterface( const Reference
<XInterface
> & rListener
)
205 OSL_ASSERT( rListener
.is() );
206 MutexGuard
aGuard( rMutex
);
212 // It is not valid to compare the pointer directly, but it's faster.
213 auto it
= std::find_if(aData
.pAsVector
->begin(), aData
.pAsVector
->end(),
214 [&rListener
](const css::uno::Reference
<css::uno::XInterface
>& rItem
) {
215 return rItem
.get() == rListener
.get(); });
217 // interface not found, use the correct compare method
218 if (it
== aData
.pAsVector
->end())
219 it
= std::find(aData
.pAsVector
->begin(), aData
.pAsVector
->end(), rListener
);
221 if (it
!= aData
.pAsVector
->end())
222 aData
.pAsVector
->erase(it
);
224 if( aData
.pAsVector
->size() == 1 )
226 XInterface
* p
= (*aData
.pAsVector
)[0].get();
228 delete aData
.pAsVector
;
229 aData
.pAsInterface
= p
;
234 return aData
.pAsVector
->size();
236 else if( aData
.pAsInterface
&& Reference
<XInterface
>( aData
.pAsInterface
) == rListener
)
238 aData
.pAsInterface
->release();
239 aData
.pAsInterface
= nullptr;
241 return aData
.pAsInterface
? 1 : 0;
244 Reference
<XInterface
> OInterfaceContainerHelper2::getInterface( sal_Int32 nIndex
) const
246 MutexGuard
aGuard( rMutex
);
249 return (*aData
.pAsVector
)[nIndex
];
250 else if( aData
.pAsInterface
)
253 return aData
.pAsInterface
;
255 throw std::out_of_range("index out of range");
258 void OInterfaceContainerHelper2::disposeAndClear( const EventObject
& rEvt
)
260 ClearableMutexGuard
aGuard( rMutex
);
261 OInterfaceIteratorHelper2
aIt( *this );
262 // Release container, in case new entries come while disposing
263 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper2 not in use" );
264 if( !bIsList
&& aData
.pAsInterface
)
265 aData
.pAsInterface
->release();
266 // set the member to null, use the iterator to delete the values
267 aData
.pAsInterface
= nullptr;
271 while( aIt
.hasMoreElements() )
275 Reference
<XEventListener
> xLst( aIt
.next(), UNO_QUERY
);
277 xLst
->disposing( rEvt
);
279 catch ( RuntimeException
& )
281 // be robust, if e.g. a remote bridge has disposed already.
282 // there is no way to delegate the error to the caller :o(.
288 void OInterfaceContainerHelper2::clear()
290 MutexGuard
aGuard( rMutex
);
291 // Release container, in case new entries come while disposing
292 OSL_ENSURE( !bIsList
|| bInUse
, "OInterfaceContainerHelper2 not in use" );
296 delete aData
.pAsVector
;
297 else if (aData
.pAsInterface
)
298 aData
.pAsInterface
->release();
299 aData
.pAsInterface
= nullptr;
305 // specialized class for type
307 OMultiTypeInterfaceContainerHelper2::OMultiTypeInterfaceContainerHelper2( Mutex
& rMutex_
)
312 OMultiTypeInterfaceContainerHelper2::~OMultiTypeInterfaceContainerHelper2()
316 std::vector
< css::uno::Type
> OMultiTypeInterfaceContainerHelper2::getContainedTypes() const
318 ::osl::MutexGuard
aGuard( rMutex
);
319 std::vector
< Type
> aInterfaceTypes
;
320 aInterfaceTypes
.reserve( m_aMap
.size() );
321 for (const auto& rItem
: m_aMap
)
323 // are interfaces added to this container?
324 if( rItem
.second
->getLength() )
325 // yes, put the type in the array
326 aInterfaceTypes
.push_back(rItem
.first
);
328 return aInterfaceTypes
;
331 OMultiTypeInterfaceContainerHelper2::t_type2ptr::iterator
OMultiTypeInterfaceContainerHelper2::findType(const Type
& rKey
)
333 return std::find_if(m_aMap
.begin(), m_aMap
.end(),
334 [&rKey
](const t_type2ptr::value_type
& rItem
) { return rItem
.first
== rKey
; });
337 OMultiTypeInterfaceContainerHelper2::t_type2ptr::const_iterator
OMultiTypeInterfaceContainerHelper2::findType(const Type
& rKey
) const
339 return std::find_if(m_aMap
.begin(), m_aMap
.end(),
340 [&rKey
](const t_type2ptr::value_type
& rItem
) { return rItem
.first
== rKey
; });
343 OInterfaceContainerHelper2
* OMultiTypeInterfaceContainerHelper2::getContainer( const Type
& rKey
) const
345 ::osl::MutexGuard
aGuard( rMutex
);
347 auto iter
= findType( rKey
);
348 if( iter
!= m_aMap
.end() )
349 return (*iter
).second
.get();
353 sal_Int32
OMultiTypeInterfaceContainerHelper2::addInterface(
354 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
356 ::osl::MutexGuard
aGuard( rMutex
);
357 auto iter
= findType( rKey
);
358 if( iter
== m_aMap
.end() )
360 OInterfaceContainerHelper2
* pLC
= new OInterfaceContainerHelper2( rMutex
);
361 m_aMap
.emplace_back(rKey
, pLC
);
362 return pLC
->addInterface( rListener
);
364 return (*iter
).second
->addInterface( rListener
);
367 sal_Int32
OMultiTypeInterfaceContainerHelper2::removeInterface(
368 const Type
& rKey
, const Reference
< XInterface
> & rListener
)
370 ::osl::MutexGuard
aGuard( rMutex
);
372 // search container with id nUik
373 auto iter
= findType( rKey
);
375 if( iter
!= m_aMap
.end() )
376 return (*iter
).second
->removeInterface( rListener
);
378 // no container with this id. Always return 0
382 void OMultiTypeInterfaceContainerHelper2::disposeAndClear( const EventObject
& rEvt
)
384 t_type2ptr::size_type nSize
= 0;
385 std::unique_ptr
<OInterfaceContainerHelper2
*[]> ppListenerContainers
;
387 ::osl::MutexGuard
aGuard( rMutex
);
388 nSize
= m_aMap
.size();
391 typedef OInterfaceContainerHelper2
* ppp
;
392 ppListenerContainers
.reset(new ppp
[nSize
]);
394 t_type2ptr::size_type i
= 0;
395 for (const auto& rItem
: m_aMap
)
397 ppListenerContainers
[i
++] = rItem
.second
.get();
402 // create a copy, because do not fire event in a guarded section
403 for( t_type2ptr::size_type i
= 0; i
< nSize
; i
++ )
405 if( ppListenerContainers
[i
] )
406 ppListenerContainers
[i
]->disposeAndClear( rEvt
);
410 void OMultiTypeInterfaceContainerHelper2::clear()
412 ::osl::MutexGuard
aGuard( rMutex
);
414 for (auto& rItem
: m_aMap
)
415 rItem
.second
->clear();
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */