bump product version to 6.4.0.3
[LibreOffice.git] / comphelper / source / container / interfacecontainer2.cxx
blob36141f7a7e19cc6742cdb69708c1fb145600c57b
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>
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
26 #include <memory>
28 #include <com/sun/star/lang/XEventListener.hpp>
31 using namespace osl;
32 using namespace com::sun::star::uno;
33 using namespace com::sun::star::lang;
35 namespace comphelper
38 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont_ )
39 : rCont( rCont_ ),
40 bIsList( rCont_.bIsList )
42 MutexGuard aGuard( rCont.rMutex );
43 if( rCont.bInUse )
44 // worst case, two iterators at the same time
45 rCont.copyAndResetInUse();
46 aData = rCont_.aData;
47 if( bIsList )
49 rCont.bInUse = true;
50 nRemain = aData.pAsVector->size();
52 else if( aData.pAsInterface )
54 aData.pAsInterface->acquire();
55 nRemain = 1;
57 else
58 nRemain = 0;
61 OInterfaceIteratorHelper2::~OInterfaceIteratorHelper2()
63 bool bShared;
65 MutexGuard aGuard( rCont.rMutex );
66 // bResetInUse protect the iterator against recursion
67 bShared = aData.pAsVector == rCont.aData.pAsVector && rCont.bIsList;
68 if( bShared )
70 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper2 must be in use" );
71 rCont.bInUse = false;
75 if( !bShared )
77 if( bIsList )
78 // Sequence owned by the iterator
79 delete aData.pAsVector;
80 else if( aData.pAsInterface )
81 // Interface is acquired by the iterator
82 aData.pAsInterface->release();
86 XInterface * OInterfaceIteratorHelper2::next()
88 if( nRemain )
90 nRemain--;
91 if( bIsList )
92 return (*aData.pAsVector)[nRemain].get();
93 else if( aData.pAsInterface )
94 return aData.pAsInterface;
96 // exception
97 return nullptr;
100 void OInterfaceIteratorHelper2::remove()
102 if( bIsList )
104 OSL_ASSERT( nRemain >= 0 &&
105 nRemain < static_cast<sal_Int32>(aData.pAsVector->size()) );
106 rCont.removeInterface( (*aData.pAsVector)[nRemain] );
108 else
110 OSL_ASSERT( 0 == nRemain );
111 rCont.removeInterface( aData.pAsInterface );
115 OInterfaceContainerHelper2::OInterfaceContainerHelper2( Mutex & rMutex_ )
116 : rMutex( rMutex_ )
117 , bInUse( false )
118 , bIsList( false )
122 OInterfaceContainerHelper2::~OInterfaceContainerHelper2()
124 OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper2 but is in use" );
125 if( bIsList )
126 delete aData.pAsVector;
127 else if( aData.pAsInterface )
128 aData.pAsInterface->release();
131 sal_Int32 OInterfaceContainerHelper2::getLength() const
133 MutexGuard aGuard( rMutex );
134 if( bIsList )
135 return aData.pAsVector->size();
136 else if( aData.pAsInterface )
137 return 1;
138 return 0;
141 std::vector< Reference<XInterface> > OInterfaceContainerHelper2::getElements() const
143 std::vector< Reference<XInterface> > rVec;
144 MutexGuard aGuard( rMutex );
145 if( bIsList )
146 rVec = *aData.pAsVector;
147 else if( aData.pAsInterface )
149 rVec.emplace_back( aData.pAsInterface );
151 return rVec;
154 void OInterfaceContainerHelper2::copyAndResetInUse()
156 OSL_ENSURE( bInUse, "OInterfaceContainerHelper2 not in use" );
157 if( bInUse )
159 // this should be the worst case. If an iterator is active
160 // and a new Listener is added.
161 if( bIsList )
162 aData.pAsVector = new std::vector< Reference< XInterface > >( *aData.pAsVector );
163 else if( aData.pAsInterface )
164 aData.pAsInterface->acquire();
166 bInUse = false;
170 sal_Int32 OInterfaceContainerHelper2::addInterface( const Reference<XInterface> & rListener )
172 OSL_ASSERT( rListener.is() );
173 MutexGuard aGuard( rMutex );
174 if( bInUse )
175 copyAndResetInUse();
177 if( bIsList )
179 aData.pAsVector->push_back( rListener );
180 return aData.pAsVector->size();
182 else if( aData.pAsInterface )
184 std::vector< Reference< XInterface > > * pVec = new std::vector< Reference< XInterface > >( 2 );
185 (*pVec)[0] = aData.pAsInterface;
186 (*pVec)[1] = rListener;
187 aData.pAsInterface->release();
188 aData.pAsVector = pVec;
189 bIsList = true;
190 return 2;
192 else
194 aData.pAsInterface = rListener.get();
195 if( rListener.is() )
196 rListener->acquire();
197 return 1;
201 sal_Int32 OInterfaceContainerHelper2::removeInterface( const Reference<XInterface> & rListener )
203 OSL_ASSERT( rListener.is() );
204 MutexGuard aGuard( rMutex );
205 if( bInUse )
206 copyAndResetInUse();
208 if( bIsList )
210 // It is not valid to compare the pointer directly, but it's faster.
211 auto it = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
212 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
213 return rItem.get() == rListener.get(); });
215 // interface not found, use the correct compare method
216 if (it == aData.pAsVector->end())
217 it = std::find(aData.pAsVector->begin(), aData.pAsVector->end(), rListener);
219 if (it != aData.pAsVector->end())
220 aData.pAsVector->erase(it);
222 if( aData.pAsVector->size() == 1 )
224 XInterface * p = (*aData.pAsVector)[0].get();
225 p->acquire();
226 delete aData.pAsVector;
227 aData.pAsInterface = p;
228 bIsList = false;
229 return 1;
231 else
232 return aData.pAsVector->size();
234 else if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
236 aData.pAsInterface->release();
237 aData.pAsInterface = nullptr;
239 return aData.pAsInterface ? 1 : 0;
242 void OInterfaceContainerHelper2::disposeAndClear( const EventObject & rEvt )
244 ClearableMutexGuard aGuard( rMutex );
245 OInterfaceIteratorHelper2 aIt( *this );
246 // Release container, in case new entries come while disposing
247 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
248 if( !bIsList && aData.pAsInterface )
249 aData.pAsInterface->release();
250 // set the member to null, use the iterator to delete the values
251 aData.pAsInterface = nullptr;
252 bIsList = false;
253 bInUse = false;
254 aGuard.clear();
255 while( aIt.hasMoreElements() )
259 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
260 if( xLst.is() )
261 xLst->disposing( rEvt );
263 catch ( RuntimeException & )
265 // be robust, if e.g. a remote bridge has disposed already.
266 // there is no way to delegate the error to the caller :o(.
272 void OInterfaceContainerHelper2::clear()
274 ClearableMutexGuard aGuard( rMutex );
275 OInterfaceIteratorHelper2 aIt( *this );
276 // Release container, in case new entries come while disposing
277 OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
278 if( !bIsList && aData.pAsInterface )
279 aData.pAsInterface->release();
280 // set the member to null, use the iterator to delete the values
281 aData.pAsInterface = nullptr;
282 bIsList = false;
283 bInUse = false;
284 // release mutex before aIt destructor call
285 aGuard.clear();
291 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */