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 <osl/diagnose.h>
25 #include <osl/mutex.hxx>
26 
27 #include <memory>
28 
29 #include <com/sun/star/lang/XEventListener.hpp>
30 
31 
32 using namespace osl;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::lang;
35 
36 namespace comphelper
37 {
38 
39 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont_ )
40  : rCont( rCont_ )
41 {
42  MutexGuard aGuard( rCont.rMutex );
43  if( rCont.bInUse )
44  // worst case, two iterators at the same time
46  bIsList = rCont_.bIsList;
47  aData = rCont_.aData;
48  if( bIsList )
49  {
50  rCont.bInUse = true;
51  nRemain = aData.pAsVector->size();
52  }
53  else if( aData.pAsInterface )
54  {
55  aData.pAsInterface->acquire();
56  nRemain = 1;
57  }
58  else
59  nRemain = 0;
60 }
61 
63 {
64  bool bShared;
65  {
66  MutexGuard aGuard( rCont.rMutex );
67  // bResetInUse protect the iterator against recursion
69  if( bShared )
70  {
71  OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper2 must be in use" );
72  rCont.bInUse = false;
73  }
74  }
75 
76  if( !bShared )
77  {
78  if( bIsList )
79  // Sequence owned by the iterator
80  delete aData.pAsVector;
81  else if( aData.pAsInterface )
82  // Interface is acquired by the iterator
83  aData.pAsInterface->release();
84  }
85 }
86 
88 {
89  if( nRemain )
90  {
91  nRemain--;
92  if( bIsList )
93  return (*aData.pAsVector)[nRemain].get();
94  else if( aData.pAsInterface )
95  return aData.pAsInterface;
96  }
97  // exception
98  return nullptr;
99 }
100 
102 {
103  if( bIsList )
104  {
105  OSL_ASSERT( nRemain >= 0 &&
106  nRemain < static_cast<sal_Int32>(aData.pAsVector->size()) );
108  }
109  else
110  {
111  OSL_ASSERT( 0 == nRemain );
113  }
114 }
115 
117  : rMutex( rMutex_ )
118  , bInUse( false )
119  , bIsList( false )
120 {
121 }
122 
124 {
125  OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper2 but is in use" );
126  if( bIsList )
127  delete aData.pAsVector;
128  else if( aData.pAsInterface )
129  aData.pAsInterface->release();
130 }
131 
133 {
134  MutexGuard aGuard( rMutex );
135  if( bIsList )
136  return aData.pAsVector->size();
137  else if( aData.pAsInterface )
138  return 1;
139  return 0;
140 }
141 
142 std::vector< Reference<XInterface> > OInterfaceContainerHelper2::getElements() const
143 {
144  std::vector< Reference<XInterface> > rVec;
145  MutexGuard aGuard( rMutex );
146  if( bIsList )
147  rVec = *aData.pAsVector;
148  else if( aData.pAsInterface )
149  {
150  rVec.emplace_back( aData.pAsInterface );
151  }
152  return rVec;
153 }
154 
156 {
157  OSL_ENSURE( bInUse, "OInterfaceContainerHelper2 not in use" );
158  if( bInUse )
159  {
160  // this should be the worst case. If an iterator is active
161  // and a new Listener is added.
162  if( bIsList )
163  aData.pAsVector = new std::vector< Reference< XInterface > >( *aData.pAsVector );
164  else if( aData.pAsInterface )
165  aData.pAsInterface->acquire();
166 
167  bInUse = false;
168  }
169 }
170 
172 {
173  OSL_ASSERT( rListener.is() );
174  MutexGuard aGuard( rMutex );
175  if( bInUse )
177 
178  if( bIsList )
179  {
180  aData.pAsVector->push_back( rListener );
181  return aData.pAsVector->size();
182  }
183  else if( aData.pAsInterface )
184  {
185  std::vector< Reference< XInterface > > * pVec = new std::vector< Reference< XInterface > >( 2 );
186  (*pVec)[0] = aData.pAsInterface;
187  (*pVec)[1] = rListener;
188  aData.pAsInterface->release();
189  aData.pAsVector = pVec;
190  bIsList = true;
191  return 2;
192  }
193  else
194  {
195  aData.pAsInterface = rListener.get();
196  if( rListener.is() )
197  rListener->acquire();
198  return 1;
199  }
200 }
201 
203 {
204  OSL_ASSERT( rListener.is() );
205  MutexGuard aGuard( rMutex );
206  if( bInUse )
208 
209  if( bIsList )
210  {
211  // It is not valid to compare the pointer directly, but it's faster.
212  auto it = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
213  [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
214  return rItem.get() == rListener.get(); });
215 
216  // interface not found, use the correct compare method
217  if (it == aData.pAsVector->end())
218  it = std::find(aData.pAsVector->begin(), aData.pAsVector->end(), rListener);
219 
220  if (it != aData.pAsVector->end())
221  aData.pAsVector->erase(it);
222 
223  if( aData.pAsVector->size() == 1 )
224  {
225  XInterface * p = (*aData.pAsVector)[0].get();
226  p->acquire();
227  delete aData.pAsVector;
228  aData.pAsInterface = p;
229  bIsList = false;
230  return 1;
231  }
232  else
233  return aData.pAsVector->size();
234  }
235  else if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
236  {
237  aData.pAsInterface->release();
238  aData.pAsInterface = nullptr;
239  }
240  return aData.pAsInterface ? 1 : 0;
241 }
242 
244 {
245  MutexGuard aGuard( rMutex );
246 
247  if( bIsList )
248  return (*aData.pAsVector)[nIndex];
249  else if( aData.pAsInterface )
250  {
251  if (nIndex == 0)
252  return aData.pAsInterface;
253  }
254  throw std::out_of_range("index out of range");
255 }
256 
257 void OInterfaceContainerHelper2::disposeAndClear( const EventObject & rEvt )
258 {
259  ClearableMutexGuard aGuard( rMutex );
260  OInterfaceIteratorHelper2 aIt( *this );
261  // Release container, in case new entries come while disposing
262  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
263  if( !bIsList && aData.pAsInterface )
264  aData.pAsInterface->release();
265  // set the member to null, use the iterator to delete the values
266  aData.pAsInterface = nullptr;
267  bIsList = false;
268  bInUse = false;
269  aGuard.clear();
270  while( aIt.hasMoreElements() )
271  {
272  try
273  {
274  Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
275  if( xLst.is() )
276  xLst->disposing( rEvt );
277  }
278  catch ( RuntimeException & )
279  {
280  // be robust, if e.g. a remote bridge has disposed already.
281  // there is no way to delegate the error to the caller :o(.
282  }
283  }
284 }
285 
286 
288 {
289  MutexGuard aGuard( rMutex );
290  // Release container, in case new entries come while disposing
291  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
292  if (bInUse)
294  if (bIsList)
295  delete aData.pAsVector;
296  else if (aData.pAsInterface)
297  aData.pAsInterface->release();
298  aData.pAsInterface = nullptr;
299  bIsList = false;
300 }
301 
302 
303 
304 // specialized class for type
305 
307  : rMutex( rMutex_ )
308 {
309 }
310 
312 {
313 }
314 
315 std::vector< css::uno::Type > OMultiTypeInterfaceContainerHelper2::getContainedTypes() const
316 {
317  ::osl::MutexGuard aGuard( rMutex );
318  std::vector< Type > aInterfaceTypes;
319  aInterfaceTypes.reserve( m_aMap.size() );
320  for (const auto& rItem : m_aMap)
321  {
322  // are interfaces added to this container?
323  if( rItem.second->getLength() )
324  // yes, put the type in the array
325  aInterfaceTypes.push_back(rItem.first);
326  }
327  return aInterfaceTypes;
328 }
329 
330 OMultiTypeInterfaceContainerHelper2::t_type2ptr::iterator OMultiTypeInterfaceContainerHelper2::findType(const Type & rKey )
331 {
332  return std::find_if(m_aMap.begin(), m_aMap.end(),
333  [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
334 }
335 
336 OMultiTypeInterfaceContainerHelper2::t_type2ptr::const_iterator OMultiTypeInterfaceContainerHelper2::findType(const Type & rKey ) const
337 {
338  return std::find_if(m_aMap.begin(), m_aMap.end(),
339  [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
340 }
341 
343 {
344  ::osl::MutexGuard aGuard( rMutex );
345 
346  auto iter = findType( rKey );
347  if( iter != m_aMap.end() )
348  return (*iter).second.get();
349  return nullptr;
350 }
351 
353  const Type & rKey, const Reference< XInterface > & rListener )
354 {
355  ::osl::MutexGuard aGuard( rMutex );
356  auto iter = findType( rKey );
357  if( iter == m_aMap.end() )
358  {
360  m_aMap.emplace_back(rKey, pLC);
361  return pLC->addInterface( rListener );
362  }
363  return (*iter).second->addInterface( rListener );
364 }
365 
367  const Type & rKey, const Reference< XInterface > & rListener )
368 {
369  ::osl::MutexGuard aGuard( rMutex );
370 
371  // search container with id nUik
372  auto iter = findType( rKey );
373  // container found?
374  if( iter != m_aMap.end() )
375  return (*iter).second->removeInterface( rListener );
376 
377  // no container with this id. Always return 0
378  return 0;
379 }
380 
382 {
383  t_type2ptr::size_type nSize = 0;
384  std::unique_ptr<OInterfaceContainerHelper2 *[]> ppListenerContainers;
385  {
386  ::osl::MutexGuard aGuard( rMutex );
387  nSize = m_aMap.size();
388  if( nSize )
389  {
390  typedef OInterfaceContainerHelper2* ppp;
391  ppListenerContainers.reset(new ppp[nSize]);
392 
393  t_type2ptr::size_type i = 0;
394  for (const auto& rItem : m_aMap)
395  {
396  ppListenerContainers[i++] = rItem.second.get();
397  }
398  }
399  }
400 
401  // create a copy, because do not fire event in a guarded section
402  for( t_type2ptr::size_type i = 0; i < nSize; i++ )
403  {
404  if( ppListenerContainers[i] )
405  ppListenerContainers[i]->disposeAndClear( rEvt );
406  }
407 }
408 
410 {
411  ::osl::MutexGuard aGuard( rMutex );
412 
413  for (auto& rItem : m_aMap)
414  rItem.second->clear();
415 }
416 
417 
418 }
419 
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
OMultiTypeInterfaceContainerHelper2(::osl::Mutex &rMutex)
Create a container of interface containers.
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
sal_Int32 addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Inserts an element into the container.
void disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
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.
sal_Int32 removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container.
~OInterfaceIteratorHelper2()
Releases the connection to the container.
~OInterfaceContainerHelper2()
Release all interfaces.
bool bInUse
TRUE -> used by an iterator.
void clear()
Remove all elements of all containers.
OInterfaceContainerHelper2(::osl::Mutex &rMutex)
Create an interface container.
t_type2ptr::iterator findType(const css::uno::Type &rKey)
std::vector< css::uno::Reference< css::uno::XInterface > > * pAsVector
int i
void disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
void clear()
Clears the container without calling disposing().
std::vector< css::uno::Reference< css::uno::XInterface > > getElements() const
Return all interfaces added to this container.
detail::element_alias2 aData
bIsList == TRUE -> aData.pAsVector of type vector< XInterfaceSequence >, otherwise aData...
This is the iterator of an OInterfaceContainerHelper2.
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
css::uno::Reference< css::uno::XInterface > getInterface(sal_Int32 nIndex) const
Return an interface by index.
std::vector< css::uno::Type > getContainedTypes() const
Return all id's under which at least one interface is added.
OInterfaceContainerHelper2 * getContainer(const css::uno::Type &rKey) const
Return the container created under this key.
void * p
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.
bool bIsList
TRUE -> aData.pAsVector is of type Sequence< XInterfaceSequence >.
sal_Int32 getLength() const
Return the number of Elements in the container.
css::uno::XInterface * next()
Return the next element of the iterator.
void remove()
Removes the current element (the last one returned by next()) from the underlying container...