Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / comphelper / source / container / interfacecontainer2.cxx
blob9acff0a7f76199b604a898c1eec19b254385f7b1
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 <comphelper/interfacecontainer2.hxx>
22 #include <comphelper/multicontainer2.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <osl/diagnose.h>
26 #include <osl/mutex.hxx>
28 #include <memory>
30 #include <com/sun/star/lang/XEventListener.hpp>
33 using namespace osl;
34 using namespace com::sun::star::uno;
35 using namespace com::sun::star::lang;
37 namespace comphelper
40 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont_ )
41 : rCont( rCont_ )
43 MutexGuard aGuard( rCont.rMutex );
44 if( rCont.bInUse )
45 // worst case, two iterators at the same time
46 rCont.copyAndResetInUse();
47 bIsList = rCont_.bIsList;
48 aData = rCont_.aData;
49 if( bIsList )
51 rCont.bInUse = true;
52 nRemain = aData.pAsVector->size();
54 else if( aData.pAsInterface )
56 aData.pAsInterface->acquire();
57 nRemain = 1;
59 else
60 nRemain = 0;
63 OInterfaceIteratorHelper2::~OInterfaceIteratorHelper2()
65 bool bShared;
67 MutexGuard aGuard( rCont.rMutex );
68 // bResetInUse protect the iterator against recursion
69 bShared = aData.pAsVector == rCont.aData.pAsVector && rCont.bIsList;
70 if( bShared )
72 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper2 must be in use" );
73 rCont.bInUse = false;
77 if( !bShared )
79 if( bIsList )
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()
90 if( nRemain )
92 nRemain--;
93 if( bIsList )
94 return (*aData.pAsVector)[nRemain].get();
95 else if( aData.pAsInterface )
96 return aData.pAsInterface;
98 // exception
99 return nullptr;
102 void OInterfaceIteratorHelper2::remove()
104 if( bIsList )
106 OSL_ASSERT( nRemain >= 0 &&
107 o3tl::make_unsigned(nRemain) < aData.pAsVector->size() );
108 rCont.removeInterface( (*aData.pAsVector)[nRemain] );
110 else
112 OSL_ASSERT( 0 == nRemain );
113 rCont.removeInterface( aData.pAsInterface );
117 OInterfaceContainerHelper2::OInterfaceContainerHelper2( Mutex & rMutex_ )
118 : rMutex( rMutex_ )
119 , bInUse( false )
120 , bIsList( false )
124 OInterfaceContainerHelper2::~OInterfaceContainerHelper2()
126 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper2 but is in use" );
127 if( bIsList )
128 delete aData.pAsVector;
129 else if( aData.pAsInterface )
130 aData.pAsInterface->release();
133 sal_Int32 OInterfaceContainerHelper2::getLength() const
135 MutexGuard aGuard( rMutex );
136 if( bIsList )
137 return aData.pAsVector->size();
138 else if( aData.pAsInterface )
139 return 1;
140 return 0;
143 std::vector< Reference<XInterface> > OInterfaceContainerHelper2::getElements() const
145 std::vector< Reference<XInterface> > rVec;
146 MutexGuard aGuard( rMutex );
147 if( bIsList )
148 rVec = *aData.pAsVector;
149 else if( aData.pAsInterface )
151 rVec.emplace_back( aData.pAsInterface );
153 return rVec;
156 void OInterfaceContainerHelper2::copyAndResetInUse()
158 OSL_ENSURE( bInUse, "OInterfaceContainerHelper2 not in use" );
159 if( bInUse )
161 // this should be the worst case. If an iterator is active
162 // and a new Listener is added.
163 if( bIsList )
164 aData.pAsVector = new std::vector< Reference< XInterface > >( *aData.pAsVector );
165 else if( aData.pAsInterface )
166 aData.pAsInterface->acquire();
168 bInUse = false;
172 sal_Int32 OInterfaceContainerHelper2::addInterface( const Reference<XInterface> & rListener )
174 OSL_ASSERT( rListener.is() );
175 MutexGuard aGuard( rMutex );
176 if( bInUse )
177 copyAndResetInUse();
179 if( bIsList )
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;
191 bIsList = true;
192 return 2;
194 else
196 aData.pAsInterface = rListener.get();
197 if( rListener.is() )
198 rListener->acquire();
199 return 1;
203 sal_Int32 OInterfaceContainerHelper2::removeInterface( const Reference<XInterface> & rListener )
205 OSL_ASSERT( rListener.is() );
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 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();
227 p->acquire();
228 delete aData.pAsVector;
229 aData.pAsInterface = p;
230 bIsList = false;
231 return 1;
233 else
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 );
248 if( bIsList )
249 return (*aData.pAsVector)[nIndex];
250 else if( aData.pAsInterface )
252 if (nIndex == 0)
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;
268 bIsList = false;
269 bInUse = false;
270 aGuard.clear();
271 while( aIt.hasMoreElements() )
275 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
276 if( xLst.is() )
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" );
293 if (bInUse)
294 copyAndResetInUse();
295 if (bIsList)
296 delete aData.pAsVector;
297 else if (aData.pAsInterface)
298 aData.pAsInterface->release();
299 aData.pAsInterface = nullptr;
300 bIsList = false;
305 // specialized class for type
307 OMultiTypeInterfaceContainerHelper2::OMultiTypeInterfaceContainerHelper2( Mutex & rMutex_ )
308 : rMutex( 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();
350 return nullptr;
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 );
374 // container found?
375 if( iter != m_aMap.end() )
376 return (*iter).second->removeInterface( rListener );
378 // no container with this id. Always return 0
379 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();
389 if( nSize )
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: */