LibreOffice Module cppuhelper (master)  1
interfacecontainer.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 
22 #include <cppuhelper/propshlp.hxx>
23 #include <comphelper/sequence.hxx>
24 
25 #include <o3tl/safeint.hxx>
26 #include <osl/diagnose.h>
27 #include <osl/mutex.hxx>
28 #include <sal/log.hxx>
29 
30 #include <memory>
31 
32 #include <com/sun/star/lang/XEventListener.hpp>
33 
34 
35 using namespace osl;
36 using namespace com::sun::star::uno;
37 using namespace com::sun::star::lang;
38 
39 namespace cppu
40 {
41 
42 OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ )
43  : rCont( rCont_ )
44 {
45  MutexGuard aGuard( rCont.rMutex );
46  if( rCont.bInUse )
47  // worst case, two iterators at the same time
49  bIsList = rCont_.bIsList;
50  aData = rCont_.aData;
51  if( bIsList )
52  {
53  rCont.bInUse = true;
54  nRemain = aData.pAsVector->size();
55  }
56  else if( aData.pAsInterface )
57  {
58  aData.pAsInterface->acquire();
59  nRemain = 1;
60  }
61  else
62  nRemain = 0;
63 }
64 
66 {
67  bool bShared;
68  {
69  MutexGuard aGuard( rCont.rMutex );
70  // bResetInUse protect the iterator against recursion
72  if( bShared )
73  {
74  OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" );
75  rCont.bInUse = false;
76  }
77  }
78 
79  if( !bShared )
80  {
81  if( bIsList )
82  // Sequence owned by the iterator
83  delete aData.pAsVector;
84  else if( aData.pAsInterface )
85  // Interface is acquired by the iterator
86  aData.pAsInterface->release();
87  }
88 }
89 
91 {
92  if( nRemain )
93  {
94  nRemain--;
95  if( bIsList )
96  // typecase to const,so the getArray method is faster
97  return (*aData.pAsVector)[nRemain].get();
98  if( aData.pAsInterface )
99  return aData.pAsInterface;
100  }
101  // exception
102  return nullptr;
103 }
104 
106 {
107  if( bIsList )
108  {
109  OSL_ASSERT( nRemain >= 0 &&
111  XInterface * p = (*aData.pAsVector)[nRemain].get();
112  rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >( &p ) );
113  }
114  else
115  {
116  OSL_ASSERT( 0 == nRemain );
117  rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface));
118  }
119 }
120 
122  : rMutex( rMutex_ )
123  , bInUse( false )
124  , bIsList( false )
125 {
126 }
127 
129 {
130  OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" );
131  if( bIsList )
132  delete aData.pAsVector;
133  else if( aData.pAsInterface )
134  aData.pAsInterface->release();
135 }
136 
138 {
139  MutexGuard aGuard( rMutex );
140  if( bIsList )
141  return aData.pAsVector->size();
142  if( aData.pAsInterface )
143  return 1;
144  return 0;
145 }
146 
148 {
149  MutexGuard aGuard( rMutex );
150  if( bIsList )
152  if( aData.pAsInterface )
153  {
155  return Sequence< Reference< XInterface > >( &x, 1 );
156  }
158 }
159 
161 {
162  OSL_ENSURE( bInUse, "OInterfaceContainerHelper not in use" );
163  if( bInUse )
164  {
165  // this should be the worst case. If an iterator is active
166  // and a new Listener is added.
167  if( bIsList )
168  aData.pAsVector= new std::vector< Reference< XInterface > >( *aData.pAsVector );
169  else if( aData.pAsInterface )
170  aData.pAsInterface->acquire();
171 
172  bInUse = false;
173  }
174 }
175 
177 {
178  SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
179  MutexGuard aGuard( rMutex );
180  if( bInUse )
182 
183  if( bIsList )
184  {
185  aData.pAsVector->push_back(rListener);
186  return aData.pAsVector->size();
187  }
188  if( aData.pAsInterface )
189  {
191  aData.pAsInterface->release();
192  aData.pAsVector = new std::vector<Reference<XInterface>>(2);
193  (*aData.pAsVector)[0] = std::move(tmp);
194  (*aData.pAsVector)[1] = rListener;
195  bIsList = true;
196  return 2;
197  }
198  aData.pAsInterface = rListener.get();
199  if( rListener.is() )
200  rListener->acquire();
201  return 1;
202 }
203 
205 {
206  SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" );
207  MutexGuard aGuard( rMutex );
208  if( bInUse )
210 
211  if( bIsList )
212  {
213  // It is not valid to compare the pointer directly, but it's faster.
214  auto findIt = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
215  [&](const Reference<XInterface>& r)
216  { return r.get() == rListener.get(); });
217  if (findIt != aData.pAsVector->end())
218  {
219  aData.pAsVector->erase(findIt);
220  }
221  else
222  {
223  // interface not found, use the correct compare method
224  for( auto it = aData.pAsVector->begin(); it != aData.pAsVector->end(); ++it )
225  {
226  if( *it == rListener )
227  {
228  aData.pAsVector->erase(it);
229  break;
230  }
231  }
232  }
233 
234  if( aData.pAsVector->size() == 1 )
235  {
236  XInterface * p = (*aData.pAsVector)[0].get();
237  p->acquire();
238  delete aData.pAsVector;
239  aData.pAsInterface = p;
240  bIsList = false;
241  return 1;
242  }
243  return aData.pAsVector->size();
244  }
246  {
247  aData.pAsInterface->release();
248  aData.pAsInterface = nullptr;
249  }
250  return aData.pAsInterface ? 1 : 0;
251 }
252 
253 void OInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
254 {
255  ClearableMutexGuard aGuard( rMutex );
256  OInterfaceIteratorHelper aIt( *this );
257  // Release container, in case new entries come while disposing
258  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
259  if( !bIsList && aData.pAsInterface )
260  aData.pAsInterface->release();
261  // set the member to null, use the iterator to delete the values
262  aData.pAsInterface = nullptr;
263  bIsList = false;
264  bInUse = false;
265  aGuard.clear();
266  while( aIt.hasMoreElements() )
267  {
268  try
269  {
270  Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
271  if( xLst.is() )
272  xLst->disposing( rEvt );
273  }
274  catch ( RuntimeException & )
275  {
276  // be robust, if e.g. a remote bridge has disposed already.
277  // there is no way to delegate the error to the caller :o(.
278  }
279  }
280 }
281 
282 
284 {
285  MutexGuard aGuard( rMutex );
286  // Release container, in case new entries come while disposing
287  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" );
288  if (bInUse)
290  if (bIsList)
291  delete aData.pAsVector;
292  else if (aData.pAsInterface)
293  aData.pAsInterface->release();
294  aData.pAsInterface = nullptr;
295  bIsList = false;
296 }
297 
298 // specialized class for type
299 
300 typedef std::vector< std::pair < Type , void* > > t_type2ptr;
301 
303  : rMutex( rMutex_ )
304 {
305  m_pMap = new t_type2ptr;
306 }
307 
308 OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper()
309 {
310  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
311 
312  for (auto& rItem : *pMap)
313  {
314  delete static_cast<OInterfaceContainerHelper*>(rItem.second);
315  rItem.second = nullptr;
316  }
317  delete pMap;
318 }
319 
320 Sequence< Type > OMultiTypeInterfaceContainerHelper::getContainedTypes() const
321 {
322  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
323  t_type2ptr::size_type nSize;
324 
325  ::osl::MutexGuard aGuard( rMutex );
326  nSize = pMap->size();
327  if( nSize )
328  {
329  css::uno::Sequence< Type > aInterfaceTypes( nSize );
330  Type * pArray = aInterfaceTypes.getArray();
331 
332  sal_Int32 i = 0;
333  for (const auto& rItem : *pMap)
334  {
335  // are interfaces added to this container?
336  if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
337  // yes, put the type in the array
338  pArray[i++] = rItem.first;
339  }
340  if( static_cast<t_type2ptr::size_type>(i) != nSize ) {
341  // may be empty container, reduce the sequence to the right size
342  aInterfaceTypes = css::uno::Sequence< Type >( pArray, i );
343  }
344  return aInterfaceTypes;
345  }
346  return css::uno::Sequence< Type >();
347 }
348 
349 static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type & rKey )
350 {
351  return std::find_if(pMap->begin(), pMap->end(),
352  [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; });
353 }
354 
355 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelper::getContainer( const Type & rKey ) const
356 {
357  ::osl::MutexGuard aGuard( rMutex );
358 
359  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
360  t_type2ptr::iterator iter = findType( pMap, rKey );
361  if( iter != pMap->end() )
362  return static_cast<OInterfaceContainerHelper*>((*iter).second);
363  return nullptr;
364 }
365 
366 sal_Int32 OMultiTypeInterfaceContainerHelper::addInterface(
367  const Type & rKey, const Reference< XInterface > & rListener )
368 {
369  ::osl::MutexGuard aGuard( rMutex );
370  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
371  t_type2ptr::iterator iter = findType( pMap, rKey );
372  if( iter == pMap->end() )
373  {
375  pMap->push_back(std::pair<Type, void*>(rKey, pLC));
376  return pLC->addInterface( rListener );
377  }
378  return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
379 }
380 
381 sal_Int32 OMultiTypeInterfaceContainerHelper::removeInterface(
382  const Type & rKey, const Reference< XInterface > & rListener )
383 {
384  ::osl::MutexGuard aGuard( rMutex );
385 
386  // search container with id nUik
387  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
388  t_type2ptr::iterator iter = findType( pMap, rKey );
389  // container found?
390  if( iter != pMap->end() )
391  return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
392 
393  // no container with this id. Always return 0
394  return 0;
395 }
396 
397 void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt )
398 {
399  t_type2ptr::size_type nSize = 0;
400  std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
401  {
402  ::osl::MutexGuard aGuard( rMutex );
403  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
404  nSize = pMap->size();
405  if( nSize )
406  {
407  typedef OInterfaceContainerHelper* ppp;
408  ppListenerContainers.reset(new ppp[nSize]);
409  //ppListenerContainers = new (ListenerContainer*)[nSize];
410 
411  t_type2ptr::size_type i = 0;
412  for (const auto& rItem : *pMap)
413  {
414  ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
415  }
416  }
417  }
418 
419  // create a copy, because do not fire event in a guarded section
420  for( t_type2ptr::size_type i = 0;
421  i < nSize; i++ )
422  {
423  if( ppListenerContainers[i] )
424  ppListenerContainers[i]->disposeAndClear( rEvt );
425  }
426 }
427 
428 void OMultiTypeInterfaceContainerHelper::clear()
429 {
430  ::osl::MutexGuard aGuard( rMutex );
431  t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap);
432 
433  for (auto& rItem : *pMap)
434  {
435  static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
436  }
437 }
438 
439 // specialized class for long
440 
441 typedef std::vector< std::pair < sal_Int32 , void* > > t_long2ptr;
442 
443 static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey )
444 {
445  return std::find_if(pMap->begin(), pMap->end(),
446  [&nKey](const t_long2ptr::value_type& rItem) { return rItem.first == nKey; });
447 }
448 
449 OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
450  : m_pMap( nullptr )
451  , rMutex( rMutex_ )
452 {
453  // delay pMap allocation until necessary.
454 }
455 
456 OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32()
457 {
458  if (!m_pMap)
459  return;
460 
461  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
462 
463  for (auto& rItem : *pMap)
464  {
465  delete static_cast<OInterfaceContainerHelper*>(rItem.second);
466  rItem.second = nullptr;
467  }
468  delete pMap;
469 }
470 
471 Sequence< sal_Int32 > OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const
472 {
473  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
474  t_long2ptr::size_type nSize;
475 
476  ::osl::MutexGuard aGuard( rMutex );
477  nSize = pMap ? pMap->size() : 0;
478  if( nSize )
479  {
480  css::uno::Sequence< sal_Int32 > aInterfaceTypes( nSize );
481  sal_Int32 * pArray = aInterfaceTypes.getArray();
482 
483  sal_Int32 i = 0;
484  for (const auto& rItem : *pMap)
485  {
486  // are interfaces added to this container?
487  if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() )
488  // yes, put the type in the array
489  pArray[i++] = rItem.first;
490  }
491  if( static_cast<t_long2ptr::size_type>(i) != nSize ) {
492  // may be empty container, reduce the sequence to the right size
493  aInterfaceTypes = css::uno::Sequence< sal_Int32 >( pArray, i );
494  }
495  return aInterfaceTypes;
496  }
497  return css::uno::Sequence< sal_Int32 >();
498 }
499 
500 OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32 & rKey ) const
501 {
502  ::osl::MutexGuard aGuard( rMutex );
503 
504  if (!m_pMap)
505  return nullptr;
506  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
507  t_long2ptr::iterator iter = findLong( pMap, rKey );
508  if( iter != pMap->end() )
509  return static_cast<OInterfaceContainerHelper*>((*iter).second);
510  return nullptr;
511 }
512 
513 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface(
514  const sal_Int32 & rKey, const Reference< XInterface > & rListener )
515 {
516  ::osl::MutexGuard aGuard( rMutex );
517  if (!m_pMap)
518  m_pMap = new t_long2ptr;
519  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
520  t_long2ptr::iterator iter = findLong( pMap, rKey );
521  if( iter == pMap->end() )
522  {
524  pMap->push_back(std::pair< sal_Int32, void* >(rKey, pLC));
525  return pLC->addInterface( rListener );
526  }
527  return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener );
528 }
529 
530 sal_Int32 OMultiTypeInterfaceContainerHelperInt32::removeInterface(
531  const sal_Int32 & rKey, const Reference< XInterface > & rListener )
532 {
533  ::osl::MutexGuard aGuard( rMutex );
534 
535  if (!m_pMap)
536  return 0;
537  // search container with id nUik
538  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
539  t_long2ptr::iterator iter = findLong( pMap, rKey );
540  // container found?
541  if( iter != pMap->end() )
542  return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener );
543 
544  // no container with this id. Always return 0
545  return 0;
546 }
547 
548 void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject & rEvt )
549 {
550  t_long2ptr::size_type nSize = 0;
551  std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers;
552  {
553  ::osl::MutexGuard aGuard( rMutex );
554  if (!m_pMap)
555  return;
556 
557  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
558  nSize = pMap->size();
559  if( nSize )
560  {
561  typedef OInterfaceContainerHelper* ppp;
562  ppListenerContainers.reset(new ppp[nSize]);
563 
564  t_long2ptr::size_type i = 0;
565  for (const auto& rItem : *pMap)
566  {
567  ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second);
568  }
569  }
570  }
571 
572  // create a copy, because do not fire event in a guarded section
573  for( t_long2ptr::size_type i = 0;
574  i < nSize; i++ )
575  {
576  if( ppListenerContainers[i] )
577  ppListenerContainers[i]->disposeAndClear( rEvt );
578  }
579 }
580 
581 void OMultiTypeInterfaceContainerHelperInt32::clear()
582 {
583  ::osl::MutexGuard aGuard( rMutex );
584  if (!m_pMap)
585  return;
586  t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap);
587 
588  for (auto& rItem : *pMap)
589  {
590  static_cast<OInterfaceContainerHelper*>(rItem.second)->clear();
591  }
592 }
593 
594 }
595 
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
~OInterfaceIteratorHelper()
Releases the connection to the container.
OInterfaceContainerHelper & rCont
sal_Bool bInUse
TRUE -> used by an iterator.
OMultiTypeInterfaceContainerHelper(::osl::Mutex &rMutex)
Create a container of interface containers.
std::vector< css::uno::Reference< css::uno::XInterface > > * pAsVector
std::vector< std::pair< Type, void * > > t_type2ptr
static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey)
float x
sal_Int32 SAL_CALL addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Inserts an element into the container.
css::uno::XInterface *SAL_CALL next()
Return the next element of the iterator.
void SAL_CALL disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
OInterfaceContainerHelper(::osl::Mutex &rMutex)
Create an interface container.
This is the iterator of an InterfaceContainerHelper.
css::uno::XInterface * pAsInterface
detail::element_alias aData
bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >, otherwise aData...
void SAL_CALL clear()
Clears the container without calling disposing().
static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type &rKey)
sal_Int32 SAL_CALL removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container.
sal_Int32 SAL_CALL getLength() const
Return the number of Elements in the container.
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Bool bIsList
TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >.
#define SAL_WARN_IF(condition, area, stream)
A container of interfaces.
std::vector< std::pair< sal_Int32, void * > > t_long2ptr
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
~OInterfaceContainerHelper()
Release all interfaces.
void * p
css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > SAL_CALL getElements() const
Return all interfaces added to this container.
void SAL_CALL remove()
Removes the current element (the last one returned by next()) from the underlying container...
bool SAL_CALL hasMoreElements() const
Return true, if there are more elements in the iterator.
bool m_bDetectedRangeSegmentation false