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