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
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
35using namespace osl;
36using namespace com::sun::star::uno;
37using namespace com::sun::star::lang;
38
39namespace cppu
40{
41
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();
99 return aData.pAsInterface;
100 }
101 // exception
102 return nullptr;
103}
104
106{
107 if( bIsList )
108 {
109 OSL_ASSERT( nRemain >= 0 &&
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;
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
253void 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
300typedef std::vector< std::pair < Type , void* > > t_type2ptr;
301
303 : rMutex( rMutex_ )
304{
305 m_pMap = new t_type2ptr;
306}
307
308OMultiTypeInterfaceContainerHelper::~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
320Sequence< 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
349static 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
355OInterfaceContainerHelper * 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
366sal_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
381sal_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
397void 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
428void 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
441typedef std::vector< std::pair < sal_Int32 , void* > > t_long2ptr;
442
443static 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
449OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ )
450 : m_pMap( nullptr )
451 , rMutex( rMutex_ )
452{
453 // delay pMap allocation until necessary.
454}
455
456OMultiTypeInterfaceContainerHelperInt32::~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
471Sequence< 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
500OInterfaceContainerHelper * 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
513sal_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
530sal_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
548void 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
581void 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: */
A container of interfaces.
sal_Bool bInUse
TRUE -> used by an iterator.
sal_Int32 SAL_CALL getLength() const
Return the number of Elements in the container.
sal_Bool bIsList
TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >.
css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > SAL_CALL getElements() const
Return all interfaces added to this container.
void SAL_CALL disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
sal_Int32 SAL_CALL removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container.
detail::element_alias aData
bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >, otherwise aData....
~OInterfaceContainerHelper()
Release all interfaces.
sal_Int32 SAL_CALL addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Inserts an element into the container.
void SAL_CALL clear()
Clears the container without calling disposing().
OInterfaceContainerHelper(::osl::Mutex &rMutex)
Create an interface container.
This is the iterator of an InterfaceContainerHelper.
OInterfaceContainerHelper & rCont
~OInterfaceIteratorHelper()
Releases the connection to the container.
css::uno::XInterface *SAL_CALL next()
Return the next element of the iterator.
bool SAL_CALL hasMoreElements() const
Return true, if there are more elements in the iterator.
void SAL_CALL remove()
Removes the current element (the last one returned by next()) from the underlying container.
OInterfaceIteratorHelper(OInterfaceContainerHelper &rCont)
Create an iterator over the elements of the container.
OMultiTypeInterfaceContainerHelper(::osl::Mutex &rMutex)
Create a container of interface containers.
float x
void * p
#define SAL_WARN_IF(condition, area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Type
std::vector< std::pair< sal_Int32, void * > > t_long2ptr
static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey)
static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type &rKey)
std::vector< std::pair< Type, void * > > t_type2ptr
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)
std::vector< css::uno::Reference< css::uno::XInterface > > * pAsVector
css::uno::XInterface * pAsInterface