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 
33 using namespace osl;
34 using namespace com::sun::star::uno;
35 using namespace com::sun::star::lang;
36 
37 namespace comphelper
38 {
39 
40 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont_ )
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 
143 std::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;
229  aData.pAsInterface = p;
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 
258 void 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 
316 std::vector< css::uno::Type > OMultiTypeInterfaceContainerHelper2::getContainedTypes() const
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 
331 OMultiTypeInterfaceContainerHelper2::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 
337 OMultiTypeInterfaceContainerHelper2::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: */
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.
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
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...
bool m_bDetectedRangeSegmentation false