Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/cppuhelper/interfacecontainer.h
Line
Count
Source
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
/*
21
 * This file is part of LibreOffice published API.
22
 */
23
#ifndef INCLUDED_CPPUHELPER_INTERFACECONTAINER_H
24
#define INCLUDED_CPPUHELPER_INTERFACECONTAINER_H
25
26
#include "sal/config.h"
27
28
#include <cstddef>
29
#include <functional>
30
#include <vector>
31
#include <utility>
32
33
#include "osl/diagnose.h"
34
#include "osl/mutex.hxx"
35
#include "rtl/alloc.h"
36
#include "com/sun/star/uno/Sequence.hxx"
37
#include "com/sun/star/lang/EventObject.hpp"
38
39
#include "com/sun/star/lang/DisposedException.hpp"
40
#include "cppuhelper/cppuhelperdllapi.h"
41
42
namespace com { namespace sun { namespace star { namespace uno { class XInterface; } } } }
43
44
namespace cppu
45
{
46
47
namespace detail {
48
49
    /**
50
      This is here to optimise space in the common case that there are zero or one
51
      listeners.
52
    */
53
    union element_alias
54
    {
55
        std::vector< css::uno::Reference< css::uno::XInterface > > *pAsVector;
56
        css::uno::XInterface * pAsInterface;
57
57.7k
        element_alias() : pAsInterface(NULL) {}
58
    };
59
60
}
61
62
63
class OInterfaceContainerHelper;
64
/**
65
  This is the iterator of an InterfaceContainerHelper. Typically
66
  one constructs an instance on the stack for one firing session.
67
  It is not allowed to assign or copy an instance of this class.
68
69
  @see OInterfaceContainerHelper
70
 */
71
class CPPUHELPER_DLLPUBLIC OInterfaceIteratorHelper
72
{
73
public:
74
    /**
75
       Create an iterator over the elements of the container. The iterator
76
       copies the elements of the container. A change to the container
77
       during the lifetime of an iterator is allowed and does not
78
       affect the iterator-instance. The iterator and the container take cares
79
       themself for concurrent access, no additional guarding is necessary.
80
81
       Remark: The copy is on demand. The iterator copy the elements only if the container
82
       change the contents. It is not allowed to destroy the container as long
83
       as an iterator exist.
84
85
       @param rCont the container of the elements.
86
     */
87
    OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont );
88
89
    /**
90
      Releases the connection to the container.
91
     */
92
    ~OInterfaceIteratorHelper();
93
94
    /** Return true, if there are more elements in the iterator. */
95
    bool SAL_CALL hasMoreElements() const
96
48.3k
        { return nRemain != 0; }
97
    /** Return the next element of the iterator. Calling this method if
98
        hasMoreElements() has returned false, is an error. Cast the
99
        returned pointer to the
100
     */
101
    css::uno::XInterface * SAL_CALL next();
102
103
    /** Removes the current element (the last one returned by next())
104
        from the underlying container. Calling this method before
105
        next() has been called or calling it twice with no next()
106
        inbetween is an error.
107
    */
108
    void SAL_CALL remove();
109
110
private:
111
    OInterfaceContainerHelper & rCont;
112
    sal_Bool                    bIsList;
113
114
    detail::element_alias aData;
115
116
    sal_Int32                   nRemain;
117
118
    OInterfaceIteratorHelper( const OInterfaceIteratorHelper & )
119
        SAL_DELETED_FUNCTION;
120
    OInterfaceIteratorHelper &  operator = ( const OInterfaceIteratorHelper & )
121
        SAL_DELETED_FUNCTION;
122
};
123
124
125
/**
126
  A container of interfaces. To access the elements use an iterator.
127
  This implementation is thread save.
128
129
  @see OInterfaceIteratorHelper
130
 */
131
class SAL_WARN_UNUSED CPPUHELPER_DLLPUBLIC OInterfaceContainerHelper
132
{
133
public:
134
    // these are here to force memory de/allocation to sal lib.
135
    static void * SAL_CALL operator new( size_t nSize )
136
28.9k
        { return ::rtl_allocateMemory( nSize ); }
137
    static void SAL_CALL operator delete( void * pMem )
138
28.7k
        { ::rtl_freeMemory( pMem ); }
139
    static void * SAL_CALL operator new( size_t, void * pMem )
140
0
        { return pMem; }
141
    static void SAL_CALL operator delete( void *, void * )
142
0
        {}
143
144
    /**
145
       Create an interface container.
146
147
       @param rMutex    the mutex to protect multi thread access.
148
       The lifetime must be longer than the lifetime
149
       of this object.
150
     */
151
    OInterfaceContainerHelper( ::osl::Mutex & rMutex );
152
    /**
153
      Release all interfaces. All iterators must be destroyed before
154
      the container is destructed.
155
     */
156
    ~OInterfaceContainerHelper();
157
    /**
158
      Return the number of Elements in the container. Only useful if you have acquired
159
      the mutex.
160
     */
161
    sal_Int32 SAL_CALL getLength() const;
162
163
    /**
164
      Return all interfaces added to this container.
165
     **/
166
    css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > SAL_CALL getElements() const;
167
168
    /** Inserts an element into the container.  The position is not specified, thus it is not
169
        specified in which order events are fired.
170
171
        @attention
172
        If you add the same interface more than once, then it will be added to the elements list
173
        more than once and thus if you want to remove that interface from the list, you have to call
174
        removeInterface() the same number of times.
175
        In the latter case, you will also get events fired more than once (if the interface is a
176
        listener interface).
177
178
        @param rxIFace
179
               interface to be added; it is allowed to insert null or
180
               the same interface more than once
181
        @return
182
                the new count of elements in the container
183
    */
184
    sal_Int32 SAL_CALL addInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
185
    /** Removes an element from the container.  It uses interface equality to remove the interface.
186
187
        @param rxIFace
188
               interface to be removed
189
        @return
190
                the new count of elements in the container
191
    */
192
    sal_Int32 SAL_CALL removeInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
193
    /**
194
      Call disposing on all object in the container that
195
      support XEventListener. Then clear the container.
196
     */
197
    void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
198
    /**
199
      Clears the container without calling disposing().
200
     */
201
    void SAL_CALL clear();
202
203
    /** Executes a functor for each contained listener of specified type, e.g.
204
        <code>forEach<awt::XPaintListener>(...</code>.
205
206
        If a css::lang::DisposedException occurs which relates to
207
        the called listener, then that listener is removed from the container.
208
209
        @tparam ListenerT listener type
210
        @tparam FuncT unary functor type, let your compiler deduce this for you
211
        @param func unary functor object expecting an argument of type
212
                    css::uno::Reference<ListenerT>
213
    */
214
    template <typename ListenerT, typename FuncT>
215
    inline void forEach( FuncT const& func );
216
217
    /** Calls a UNO listener method for each contained listener.
218
219
        The listener method must take a single argument of type EventT,
220
        and return <code>void</code>.
221
222
        If a css::lang::DisposedException occurs which relates to
223
        the called listener, then that listener is removed from the container.
224
225
        @tparam ListenerT UNO event listener type, let your compiler deduce this for you
226
        @tparam EventT event type, let your compiler deduce this for you
227
        @param NotificationMethod
228
            Pointer to a method of a ListenerT interface.
229
        @param Event
230
            Event to notify to all contained listeners
231
232
        Example:
233
@code
234
    awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
235
    listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
236
@endcode
237
    */
238
    template< typename ListenerT, typename EventT >
239
    inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event );
240
241
private:
242
friend class OInterfaceIteratorHelper;
243
    /**
244
      bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >,
245
      otherwise aData.pAsInterface == of type (XEventListener *)
246
     */
247
    detail::element_alias   aData;
248
    ::osl::Mutex &          rMutex;
249
    /** TRUE -> used by an iterator. */
250
    sal_Bool                bInUse;
251
    /** TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >. */
252
    sal_Bool                bIsList;
253
254
    OInterfaceContainerHelper( const OInterfaceContainerHelper & )
255
        SAL_DELETED_FUNCTION;
256
    OInterfaceContainerHelper & operator = ( const OInterfaceContainerHelper & )
257
        SAL_DELETED_FUNCTION;
258
259
    /*
260
      Duplicate content of the container and release the old one without destroying.
261
      The mutex must be locked and the memberbInUse must be true.
262
     */
263
    void copyAndResetInUse();
264
265
private:
266
    template< typename ListenerT, typename EventT >
267
    class NotifySingleListener
268
    {
269
    private:
270
        typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
271
        NotificationMethod  m_pMethod;
272
        const EventT&       m_rEvent;
273
    public:
274
        NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
275
276
        void operator()( const css::uno::Reference<ListenerT>& listener ) const
277
        {
278
            (listener.get()->*m_pMethod)( m_rEvent );
279
        }
280
    };
281
};
282
283
template <typename ListenerT, typename FuncT>
284
inline void OInterfaceContainerHelper::forEach( FuncT const& func )
285
0
{
286
0
    OInterfaceIteratorHelper iter( *this );
287
0
    while (iter.hasMoreElements()) {
288
0
        css::uno::Reference<ListenerT> const xListener( iter.next(), css::uno::UNO_QUERY );
289
0
        if (xListener.is()) {
290
0
            try {
291
0
                func( xListener );
292
0
            }
293
0
            catch (css::lang::DisposedException const& exc) {
294
0
                if (exc.Context == xListener)
295
0
                    iter.remove();
296
0
            }
297
0
        }
298
0
    }
299
0
}
Unexecuted instantiation: dp_extensionmanager.cxx:void cppu::OInterfaceContainerHelper::forEach<com::sun::star::util::XModifyListener, dp_manager::ExtensionManager::fireModified()::$_0>(dp_manager::ExtensionManager::fireModified()::$_0 const&)
Unexecuted instantiation: dp_manager.cxx:void cppu::OInterfaceContainerHelper::forEach<com::sun::star::util::XModifyListener, dp_manager::PackageManagerImpl::fireModified()::$_0>(dp_manager::PackageManagerImpl::fireModified()::$_0 const&)
300
301
template< typename ListenerT, typename EventT >
302
inline void OInterfaceContainerHelper::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event )
303
{
304
    forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) );
305
}
306
307
308
/**
309
  A helper class to store interface references of different types.
310
311
  @see OInterfaceIteratorHelper
312
  @see OInterfaceContainerHelper
313
 */
314
template< class key, class hashImpl = void, class equalImpl = std::equal_to<key> >
315
class OMultiTypeInterfaceContainerHelperVar
316
{
317
public:
318
    // these are here to force memory de/allocation to sal lib.
319
    static void * SAL_CALL operator new( size_t nSize )
320
0
        { return ::rtl_allocateMemory( nSize ); }
321
    static void SAL_CALL operator delete( void * pMem )
322
0
        { ::rtl_freeMemory( pMem ); }
323
    static void * SAL_CALL operator new( size_t, void * pMem )
324
        { return pMem; }
325
    static void SAL_CALL operator delete( void *, void * )
326
        {}
327
328
    /**
329
      Create a container of interface containers.
330
331
      @param rMutex the mutex to protect multi thread access.
332
                         The lifetime must be longer than the lifetime
333
                         of this object.
334
     */
335
    inline OMultiTypeInterfaceContainerHelperVar( ::osl::Mutex & rMutex );
336
    /**
337
      Deletes all containers.
338
     */
339
    inline ~OMultiTypeInterfaceContainerHelperVar();
340
341
    /**
342
      Return all id's under which at least one interface is added.
343
     */
344
    inline css::uno::Sequence< key > SAL_CALL getContainedTypes() const;
345
346
    /**
347
      Return the container created under this key.
348
      The InterfaceContainerHelper exists until the whole MultiTypeContainer is destroyed.
349
      @return the container created under this key. If the container
350
                 was not created, null was returned.
351
     */
352
    inline OInterfaceContainerHelper * SAL_CALL getContainer( const key & ) const;
353
354
    /** Inserts an element into the container with the specified key.
355
        The position is not specified, thus it is not specified in which order events are fired.
356
357
        @attention
358
        If you add the same interface more than once, then it will be added to the elements list
359
        more than once and thus if you want to remove that interface from the list, you have to call
360
        removeInterface() the same number of times.
361
        In the latter case, you will also get events fired more than once (if the interface is a
362
        listener interface).
363
364
        @param rKey
365
               the id of the container
366
        @param r
367
               interface to be added; it is allowed, to insert null or
368
               the same interface more than once
369
        @return
370
                the new count of elements in the container
371
    */
372
    inline sal_Int32 SAL_CALL addInterface(
373
        const key & rKey,
374
        const css::uno::Reference< css::uno::XInterface > & r );
375
376
    /** Removes an element from the container with the specified key.
377
        It uses interface equality to remove the interface.
378
379
        @param rKey
380
               the id of the container
381
        @param rxIFace
382
               interface to be removed
383
        @return
384
                the new count of elements in the container
385
    */
386
    inline sal_Int32 SAL_CALL removeInterface(
387
        const key & rKey,
388
        const css::uno::Reference< css::uno::XInterface > & rxIFace );
389
390
    /**
391
      Call disposing on all references in the container, that
392
      support XEventListener. Then clears the container.
393
      @param rEvt the event object which is passed during disposing() call
394
     */
395
    inline void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
396
    /**
397
      Remove all elements of all containers. Does not delete the container.
398
     */
399
    inline void SAL_CALL clear();
400
401
    typedef key keyType;
402
private:
403
    typedef ::std::vector< std::pair < key , void* > > InterfaceMap;
404
    InterfaceMap *m_pMap;
405
    ::osl::Mutex &  rMutex;
406
407
    typename InterfaceMap::iterator find(const key &rKey) const
408
0
    {
409
0
        typename InterfaceMap::iterator iter = m_pMap->begin();
410
0
        typename InterfaceMap::iterator end = m_pMap->end();
411
412
0
        while( iter != end )
413
0
        {
414
0
            equalImpl equal;
415
0
            if( equal( iter->first, rKey ) )
416
0
                break;
417
0
            ++iter;
418
0
        }
419
0
        return iter;
420
0
    }
421
422
    OMultiTypeInterfaceContainerHelperVar( const OMultiTypeInterfaceContainerHelperVar & ) SAL_DELETED_FUNCTION;
423
    OMultiTypeInterfaceContainerHelperVar & operator = ( const OMultiTypeInterfaceContainerHelperVar & ) SAL_DELETED_FUNCTION;
424
};
425
426
427
428
429
/**
430
  This struct contains the standard variables of a broadcaster. Helper
431
  classes only know a reference to this struct instead of references
432
  to the four members. The access to the members must be guarded with
433
  rMutex.
434
435
  The additional template parameter keyType has been added, because gcc
436
  can't compile addListener( const container::keyType &key ).
437
 */
438
template < class container , class keyType >
439
struct SAL_WARN_UNUSED OBroadcastHelperVar
440
{
441
    /** The shared mutex. */
442
    ::osl::Mutex &                      rMutex;
443
    /** ListenerContainer class is thread safe. */
444
    container   aLC;
445
    /** Dispose call ready. */
446
    sal_Bool                            bDisposed;
447
    /** In dispose call. */
448
    sal_Bool                            bInDispose;
449
450
    /**
451
      Initialize the structure. bDispose and bInDispose are set to false.
452
      @param rMutex_ the mutex reference.
453
     */
454
    OBroadcastHelperVar( ::osl::Mutex & rMutex_ )
455
3.66M
        : rMutex( rMutex_ )
456
3.66M
        , aLC( rMutex_ )
457
3.66M
        , bDisposed( false )
458
3.66M
        , bInDispose( false )
459
3.66M
    {}
460
461
    /**
462
      adds a listener threadsafe.
463
     **/
464
    void addListener(
465
        const keyType &key,
466
        const css::uno::Reference < css::uno::XInterface > &r )
467
48.4k
    {
468
48.4k
        ::osl::MutexGuard guard( rMutex );
469
48.4k
        OSL_ENSURE( !bInDispose, "do not add listeners in the dispose call" );
470
48.4k
        OSL_ENSURE( !bDisposed, "object is disposed" );
471
48.4k
        if( ! bInDispose && ! bDisposed  )
472
48.4k
            aLC.addInterface( key , r );
473
48.4k
    }
474
475
    /**
476
      removes a listener threadsafe
477
     **/
478
    void removeListener(
479
        const keyType &key,
480
        const css::uno::Reference < css::uno::XInterface > & r )
481
28.7k
    {
482
28.7k
        ::osl::MutexGuard guard( rMutex );
483
28.7k
        if( ! bInDispose && ! bDisposed  )
484
28.7k
            aLC.removeInterface( key , r );
485
28.7k
    }
486
487
    /**
488
      Return the container created under this key.
489
      @return the container created under this key. If the container
490
                was not created, null was returned. This can be used to optimize
491
              performance ( construction of an event object can be avoided ).
492
     ***/
493
    OInterfaceContainerHelper * SAL_CALL getContainer( const keyType &key ) const
494
0
        { return aLC.getContainer( key ); }
495
};
496
497
/*------------------------------------------
498
*
499
* In general, the above templates are used with a Type as key.
500
* Therefore a default declaration is given ( OMultiTypeInterfaceContainerHelper and OBroadcastHelper )
501
*
502
*------------------------------------------*/
503
504
// helper function call class
505
struct hashType_Impl
506
{
507
    size_t operator()(const css::uno::Type & s) const
508
0
    { return static_cast<size_t>(s.getTypeName().hashCode()); }
509
};
510
511
512
/** Specialized class for key type css::uno::Type,
513
    without explicit usage of STL symbols.
514
*/
515
class CPPUHELPER_DLLPUBLIC OMultiTypeInterfaceContainerHelper
516
{
517
public:
518
    // these are here to force memory de/allocation to sal lib.
519
    static void * SAL_CALL operator new( size_t nSize )
520
0
        { return ::rtl_allocateMemory( nSize ); }
521
    static void SAL_CALL operator delete( void * pMem )
522
0
        { ::rtl_freeMemory( pMem ); }
523
    static void * SAL_CALL operator new( size_t, void * pMem )
524
0
        { return pMem; }
525
    static void SAL_CALL operator delete( void *, void * )
526
0
        {}
527
528
    /**
529
      Create a container of interface containers.
530
531
      @param rMutex the mutex to protect multi thread access.
532
                         The lifetime must be longer than the lifetime
533
                         of this object.
534
     */
535
    OMultiTypeInterfaceContainerHelper( ::osl::Mutex & rMutex );
536
    /**
537
      Delete all containers.
538
     */
539
    ~OMultiTypeInterfaceContainerHelper();
540
541
    /**
542
      Return all id's under which at least one interface is added.
543
     */
544
    css::uno::Sequence< css::uno::Type > SAL_CALL getContainedTypes() const;
545
546
    /**
547
      Return the container created under this key.
548
      @return the container created under this key. If the container
549
                 was not created, null was returned.
550
     */
551
    OInterfaceContainerHelper * SAL_CALL getContainer( const css::uno::Type & rKey ) const;
552
553
    /** Inserts an element into the container with the specified key.
554
        The position is not specified, thus it is not specified in which order events are fired.
555
556
        @attention
557
        If you add the same interface more than once, then it will be added to the elements list
558
        more than once and thus if you want to remove that interface from the list, you have to call
559
        removeInterface() the same number of times.
560
        In the latter case, you will also get events fired more than once (if the interface is a
561
        listener interface).
562
563
        @param rKey
564
               the id of the container
565
        @param r
566
               interface to be added; it is allowed, to insert null or
567
               the same interface more than once
568
        @return
569
                the new count of elements in the container
570
    */
571
    sal_Int32 SAL_CALL addInterface(
572
        const css::uno::Type & rKey,
573
        const css::uno::Reference< css::uno::XInterface > & r );
574
575
    /** Removes an element from the container with the specified key.
576
        It uses interface equality to remove the interface.
577
578
        @param rKey
579
               the id of the container
580
        @param rxIFace
581
               interface to be removed
582
        @return
583
                the new count of elements in the container
584
    */
585
    sal_Int32 SAL_CALL removeInterface(
586
        const css::uno::Type & rKey,
587
        const css::uno::Reference< css::uno::XInterface > & rxIFace );
588
589
    /**
590
      Call disposing on all object in the container that
591
      support XEventListener. Then clear the container.
592
     */
593
    void SAL_CALL disposeAndClear( const css::lang::EventObject & rEvt );
594
    /**
595
      Remove all elements of all containers. Does not delete the container.
596
     */
597
    void SAL_CALL clear();
598
599
    typedef css::uno::Type keyType;
600
private:
601
    void *          m_pMap;
602
    ::osl::Mutex &  rMutex;
603
604
    OMultiTypeInterfaceContainerHelper( const OMultiTypeInterfaceContainerHelper & ) SAL_DELETED_FUNCTION;
605
    OMultiTypeInterfaceContainerHelper & operator = ( const OMultiTypeInterfaceContainerHelper & ) SAL_DELETED_FUNCTION;
606
};
607
608
typedef OBroadcastHelperVar< OMultiTypeInterfaceContainerHelper , OMultiTypeInterfaceContainerHelper::keyType > OBroadcastHelper;
609
610
}
611
612
#endif
613
614
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */