LibreOffice Module comphelper (master) 1
interfacecontainer2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
23
24#include <o3tl/safeint.hxx>
25#include <osl/diagnose.h>
26#include <osl/mutex.hxx>
27
28#include <memory>
29
30#include <com/sun/star/lang/XEventListener.hpp>
31
32
33using namespace osl;
34using namespace com::sun::star::uno;
35using namespace com::sun::star::lang;
36
37namespace comphelper
38{
39
41 : rCont( rCont_ )
42{
43 MutexGuard aGuard( rCont.rMutex );
44 if( rCont.bInUse )
45 // worst case, two iterators at the same time
47 bIsList = rCont_.bIsList;
48 aData = rCont_.aData;
49 if( bIsList )
50 {
51 rCont.bInUse = true;
52 nRemain = aData.pAsVector->size();
53 }
54 else if( aData.pAsInterface )
55 {
56 aData.pAsInterface->acquire();
57 nRemain = 1;
58 }
59 else
60 nRemain = 0;
61}
62
64{
65 bool bShared;
66 {
67 MutexGuard aGuard( rCont.rMutex );
68 // bResetInUse protect the iterator against recursion
70 if( bShared )
71 {
72 OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper2 must be in use" );
73 rCont.bInUse = false;
74 }
75 }
76
77 if( !bShared )
78 {
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();
85 }
86}
87
89{
90 if( nRemain )
91 {
92 nRemain--;
93 if( bIsList )
94 return (*aData.pAsVector)[nRemain].get();
95 else if( aData.pAsInterface )
96 return aData.pAsInterface;
97 }
98 // exception
99 return nullptr;
100}
101
103{
104 if( bIsList )
105 {
106 OSL_ASSERT( nRemain >= 0 &&
109 }
110 else
111 {
112 OSL_ASSERT( 0 == nRemain );
114 }
115}
116
118 : rMutex( rMutex_ )
119 , bInUse( false )
120 , bIsList( false )
121{
122}
123
125{
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();
131}
132
134{
135 MutexGuard aGuard( rMutex );
136 if( bIsList )
137 return aData.pAsVector->size();
138 else if( aData.pAsInterface )
139 return 1;
140 return 0;
141}
142
143std::vector< Reference<XInterface> > OInterfaceContainerHelper2::getElements() const
144{
145 std::vector< Reference<XInterface> > rVec;
146 MutexGuard aGuard( rMutex );
147 if( bIsList )
148 rVec = *aData.pAsVector;
149 else if( aData.pAsInterface )
150 {
151 rVec.emplace_back( aData.pAsInterface );
152 }
153 return rVec;
154}
155
157{
158 OSL_ENSURE( bInUse, "OInterfaceContainerHelper2 not in use" );
159 if( bInUse )
160 {
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();
167
168 bInUse = false;
169 }
170}
171
173{
174 OSL_ASSERT( rListener.is() );
175 MutexGuard aGuard( rMutex );
176 if( bInUse )
178
179 if( bIsList )
180 {
181 aData.pAsVector->push_back( rListener );
182 return aData.pAsVector->size();
183 }
184 else if( aData.pAsInterface )
185 {
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;
193 }
194 else
195 {
196 aData.pAsInterface = rListener.get();
197 if( rListener.is() )
198 rListener->acquire();
199 return 1;
200 }
201}
202
204{
205 OSL_ASSERT( rListener.is() );
206 MutexGuard aGuard( rMutex );
207 if( bInUse )
209
210 if( bIsList )
211 {
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(); });
216
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);
220
221 if (it != aData.pAsVector->end())
222 aData.pAsVector->erase(it);
223
224 if( aData.pAsVector->size() == 1 )
225 {
226 XInterface * p = (*aData.pAsVector)[0].get();
227 p->acquire();
228 delete aData.pAsVector;
230 bIsList = false;
231 return 1;
232 }
233 else
234 return aData.pAsVector->size();
235 }
236 else if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
237 {
238 aData.pAsInterface->release();
239 aData.pAsInterface = nullptr;
240 }
241 return aData.pAsInterface ? 1 : 0;
242}
243
245{
246 MutexGuard aGuard( rMutex );
247
248 if( bIsList )
249 return (*aData.pAsVector)[nIndex];
250 else if( aData.pAsInterface )
251 {
252 if (nIndex == 0)
253 return aData.pAsInterface;
254 }
255 throw std::out_of_range("index out of range");
256}
257
258void OInterfaceContainerHelper2::disposeAndClear( const EventObject & rEvt )
259{
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() )
272 {
273 try
274 {
275 Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
276 if( xLst.is() )
277 xLst->disposing( rEvt );
278 }
279 catch ( RuntimeException & )
280 {
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(.
283 }
284 }
285}
286
287
289{
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)
295 if (bIsList)
296 delete aData.pAsVector;
297 else if (aData.pAsInterface)
298 aData.pAsInterface->release();
299 aData.pAsInterface = nullptr;
300 bIsList = false;
301}
302
303
304
305// specialized class for type
306
308 : rMutex( rMutex_ )
309{
310}
311
313{
314}
315
317{
318 ::osl::MutexGuard aGuard( rMutex );
319 std::vector< Type > aInterfaceTypes;
320 aInterfaceTypes.reserve( m_aMap.size() );
321 for (const auto& rItem : m_aMap)
322 {
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);
327 }
328 return aInterfaceTypes;
329}
330
331OMultiTypeInterfaceContainerHelper2::t_type2ptr::iterator OMultiTypeInterfaceContainerHelper2::findType(const Type & rKey )
332{
333 return std::find_if(m_aMap.begin(), m_aMap.end(),
334 [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
335}
336
337OMultiTypeInterfaceContainerHelper2::t_type2ptr::const_iterator OMultiTypeInterfaceContainerHelper2::findType(const Type & rKey ) const
338{
339 return std::find_if(m_aMap.begin(), m_aMap.end(),
340 [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
341}
342
344{
345 ::osl::MutexGuard aGuard( rMutex );
346
347 auto iter = findType( rKey );
348 if( iter != m_aMap.end() )
349 return (*iter).second.get();
350 return nullptr;
351}
352
354 const Type & rKey, const Reference< XInterface > & rListener )
355{
356 ::osl::MutexGuard aGuard( rMutex );
357 auto iter = findType( rKey );
358 if( iter == m_aMap.end() )
359 {
361 m_aMap.emplace_back(rKey, pLC);
362 return pLC->addInterface( rListener );
363 }
364 return (*iter).second->addInterface( rListener );
365}
366
368 const Type & rKey, const Reference< XInterface > & rListener )
369{
370 ::osl::MutexGuard aGuard( rMutex );
371
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 );
377
378 // no container with this id. Always return 0
379 return 0;
380}
381
383{
384 t_type2ptr::size_type nSize = 0;
385 std::unique_ptr<OInterfaceContainerHelper2 *[]> ppListenerContainers;
386 {
387 ::osl::MutexGuard aGuard( rMutex );
388 nSize = m_aMap.size();
389 if( nSize )
390 {
391 typedef OInterfaceContainerHelper2* ppp;
392 ppListenerContainers.reset(new ppp[nSize]);
393
394 t_type2ptr::size_type i = 0;
395 for (const auto& rItem : m_aMap)
396 {
397 ppListenerContainers[i++] = rItem.second.get();
398 }
399 }
400 }
401
402 // create a copy, because do not fire event in a guarded section
403 for( t_type2ptr::size_type i = 0; i < nSize; i++ )
404 {
405 if( ppListenerContainers[i] )
406 ppListenerContainers[i]->disposeAndClear( rEvt );
407 }
408}
409
411{
412 ::osl::MutexGuard aGuard( rMutex );
413
414 for (auto& rItem : m_aMap)
415 rItem.second->clear();
416}
417
418
419}
420
421/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool bIsList
TRUE -> aData.pAsVector is of type Sequence< XInterfaceSequence >.
bool bInUse
TRUE -> used by an iterator.
~OInterfaceContainerHelper2()
Release all interfaces.
void disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
sal_Int32 getLength() const
Return the number of Elements in the container.
void clear()
Clears the container without calling disposing().
css::uno::Reference< css::uno::XInterface > getInterface(sal_Int32 nIndex) const
Return an interface by index.
OInterfaceContainerHelper2(::osl::Mutex &rMutex)
Create an interface container.
std::vector< css::uno::Reference< css::uno::XInterface > > getElements() const
Return all interfaces added to this container.
sal_Int32 removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container.
sal_Int32 addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Inserts an element into the container.
detail::element_alias2 aData
bIsList == TRUE -> aData.pAsVector of type vector< XInterfaceSequence >, otherwise aData....
This is the iterator of an OInterfaceContainerHelper2.
OInterfaceIteratorHelper2(OInterfaceContainerHelper2 &rCont)
Create an iterator over the elements of the container.
css::uno::XInterface * next()
Return the next element of the iterator.
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
void remove()
Removes the current element (the last one returned by next()) from the underlying container.
~OInterfaceIteratorHelper2()
Releases the connection to the container.
OInterfaceContainerHelper2 * getContainer(const css::uno::Type &rKey) const
Return the container created under this key.
void clear()
Remove all elements of all containers.
sal_Int32 removeInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container with the specified key.
OMultiTypeInterfaceContainerHelper2(::osl::Mutex &rMutex)
Create a container of interface containers.
sal_Int32 addInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &r)
Inserts an element into the container with the specified key.
void disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
t_type2ptr::iterator findType(const css::uno::Type &rKey)
std::vector< css::uno::Type > getContainedTypes() const
Return all id's under which at least one interface is added.
sal_Int32 nIndex
void * p
Type
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
std::vector< css::uno::Reference< css::uno::XInterface > > * pAsVector