Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/container/enumerablemap.cxx
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
#include <comphelper/anytostring.hxx>
22
#include <comphelper/anycompare.hxx>
23
#include <comphelper/componentbase.hxx>
24
25
#include <com/sun/star/container/XEnumerableMap.hpp>
26
#include <com/sun/star/lang/NoSupportException.hpp>
27
#include <com/sun/star/lang/XInitialization.hpp>
28
#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
29
#include <com/sun/star/beans/IllegalTypeException.hpp>
30
#include <com/sun/star/beans/Pair.hpp>
31
#include <com/sun/star/lang/XServiceInfo.hpp>
32
#include <com/sun/star/uno/XComponentContext.hpp>
33
34
#include <cppuhelper/compbase.hxx>
35
#include <cppuhelper/implbase.hxx>
36
#include <cppuhelper/supportsservice.hxx>
37
#include <typelib/typedescription.hxx>
38
39
#include <cmath>
40
#include <map>
41
#include <memory>
42
#include <optional>
43
#include <utility>
44
45
namespace comphelper
46
{
47
48
49
    using ::com::sun::star::uno::Reference;
50
    using ::com::sun::star::uno::XInterface;
51
    using ::com::sun::star::uno::UNO_QUERY;
52
    using ::com::sun::star::uno::RuntimeException;
53
    using ::com::sun::star::uno::Any;
54
    using ::com::sun::star::uno::Sequence;
55
    using ::com::sun::star::uno::Type;
56
    using ::com::sun::star::container::XEnumerableMap;
57
    using ::com::sun::star::lang::NoSupportException;
58
    using ::com::sun::star::beans::IllegalTypeException;
59
    using ::com::sun::star::container::NoSuchElementException;
60
    using ::com::sun::star::lang::IllegalArgumentException;
61
    using ::com::sun::star::lang::XInitialization;
62
    using ::com::sun::star::ucb::AlreadyInitializedException;
63
    using ::com::sun::star::beans::Pair;
64
    using ::com::sun::star::uno::TypeClass;
65
    using ::com::sun::star::uno::TypeClass_VOID;
66
    using ::com::sun::star::uno::TypeClass_UNKNOWN;
67
    using ::com::sun::star::uno::TypeClass_ANY;
68
    using ::com::sun::star::uno::TypeClass_EXCEPTION;
69
    using ::com::sun::star::uno::TypeClass_STRUCT;
70
    using ::com::sun::star::uno::TypeClass_FLOAT;
71
    using ::com::sun::star::uno::TypeClass_DOUBLE;
72
    using ::com::sun::star::uno::TypeClass_INTERFACE;
73
    using ::com::sun::star::lang::XServiceInfo;
74
    using ::com::sun::star::uno::XComponentContext;
75
    using ::com::sun::star::container::XEnumeration;
76
    using ::com::sun::star::uno::TypeDescription;
77
    using ::com::sun::star::lang::DisposedException;
78
79
    namespace {
80
81
    class MapEnumerator;
82
83
    }
84
85
    typedef std::map< Any, Any, LessPredicateAdapter > KeyedValues;
86
87
    namespace {
88
89
    struct MapData
90
    {
91
        Type                                        m_aKeyType;
92
        Type                                        m_aValueType;
93
        std::optional< KeyedValues >                m_pValues;
94
        std::shared_ptr< IKeyPredicateLess >      m_pKeyCompare;
95
        bool                                        m_bMutable;
96
        std::vector< MapEnumerator* >             m_aModListeners;
97
98
        MapData()
99
0
            :m_bMutable( true )
100
0
        {
101
0
        }
102
103
        MapData( const MapData& _source )
104
0
            :m_aKeyType( _source.m_aKeyType )
105
0
            ,m_aValueType( _source.m_aValueType )
106
0
            ,m_pKeyCompare( _source.m_pKeyCompare )
107
0
            ,m_bMutable( false )
108
0
        {
109
0
            m_pValues.emplace( *_source.m_pValues );
110
0
        }
111
    private:
112
        MapData& operator=( const MapData& _source ) = delete;
113
    };
114
115
    }
116
117
    static void lcl_registerMapModificationListener( MapData& _mapData, MapEnumerator& _listener )
118
0
    {
119
    #if OSL_DEBUG_LEVEL > 0
120
        for ( const MapEnumerator* lookup : _mapData.m_aModListeners )
121
        {
122
            OSL_ENSURE( lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" );
123
        }
124
    #endif
125
0
        _mapData.m_aModListeners.push_back( &_listener );
126
0
    }
127
128
129
    static void lcl_revokeMapModificationListener( MapData& _mapData, MapEnumerator& _listener )
130
0
    {
131
0
        auto lookup = std::find(_mapData.m_aModListeners.begin(), _mapData.m_aModListeners.end(), &_listener);
132
0
        if (lookup != _mapData.m_aModListeners.end())
133
0
        {
134
0
            _mapData.m_aModListeners.erase( lookup );
135
0
            return;
136
0
        }
137
0
        OSL_FAIL( "lcl_revokeMapModificationListener: the listener is not registered!" );
138
0
    }
139
140
141
    static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData );
142
143
144
    // EnumerableMap
145
146
    typedef ::cppu::WeakComponentImplHelper <   XInitialization
147
                                                ,   XEnumerableMap
148
                                                ,   XServiceInfo
149
                                                > Map_IFace;
150
151
    namespace {
152
153
    class EnumerableMap: public Map_IFace, public ComponentBase
154
    {
155
    public:
156
        EnumerableMap();
157
    protected:
158
        virtual ~EnumerableMap() override;
159
160
        // XInitialization
161
        virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
162
163
        // XEnumerableMap
164
        virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createKeyEnumeration( sal_Bool Isolated ) override;
165
        virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createValueEnumeration( sal_Bool Isolated ) override;
166
        virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createElementEnumeration( sal_Bool Isolated ) override;
167
168
        // XMap
169
        virtual Type SAL_CALL getKeyType() override;
170
        virtual Type SAL_CALL getValueType() override;
171
        virtual void SAL_CALL clear(  ) override;
172
        virtual sal_Bool SAL_CALL containsKey( const Any& _key ) override;
173
        virtual sal_Bool SAL_CALL containsValue( const Any& _value ) override;
174
        virtual Any SAL_CALL get( const Any& _key ) override;
175
        virtual Any SAL_CALL put( const Any& _key, const Any& _value ) override;
176
        virtual Any SAL_CALL remove( const Any& _key ) override;
177
178
        // XElementAccess (base of XMap)
179
        virtual Type SAL_CALL getElementType() override;
180
        virtual sal_Bool SAL_CALL hasElements() override;
181
182
        // XServiceInfo
183
        virtual OUString SAL_CALL getImplementationName(  ) override;
184
        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
185
        virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) override;
186
187
    private:
188
        void    impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues );
189
190
        /// throws an IllegalTypeException if the given value is not compatible with our ValueType
191
        void    impl_checkValue_throw( const Any& _value ) const;
192
        void    impl_checkKey_throw( const Any& _key ) const;
193
        void    impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const;
194
        void    impl_checkMutable_throw() const;
195
196
    private:
197
        ::osl::Mutex        m_aMutex;
198
        MapData             m_aData;
199
    };
200
201
    enum EnumerationType
202
    {
203
        eKeys, eValues, eBoth
204
    };
205
206
    class MapEnumerator final
207
    {
208
    public:
209
        MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type )
210
0
            :m_rParent( _rParent )
211
0
            ,m_rMapData( _mapData )
212
0
            ,m_eType( _type )
213
0
            ,m_mapPos( _mapData.m_pValues->begin() )
214
0
            ,m_disposed( false )
215
0
        {
216
0
            lcl_registerMapModificationListener( m_rMapData, *this );
217
0
        }
218
219
        ~MapEnumerator()
220
0
        {
221
0
            dispose();
222
0
        }
223
224
        void dispose()
225
0
        {
226
0
            if ( !m_disposed )
227
0
            {
228
0
                lcl_revokeMapModificationListener( m_rMapData, *this );
229
0
                m_disposed = true;
230
0
            }
231
0
        }
232
233
        // noncopyable
234
        MapEnumerator(const MapEnumerator&) = delete;
235
        const MapEnumerator& operator=(const MapEnumerator&) = delete;
236
237
        // XEnumeration equivalents
238
        bool hasMoreElements();
239
        Any nextElement();
240
241
        /// called when the map was modified
242
        void mapModified();
243
244
    private:
245
        ::cppu::OWeakObject&        m_rParent;
246
        MapData&                    m_rMapData;
247
        const EnumerationType       m_eType;
248
        KeyedValues::const_iterator m_mapPos;
249
        bool                        m_disposed;
250
    };
251
252
    }
253
254
    static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData )
255
0
    {
256
0
        for ( MapEnumerator* loop : _mapData.m_aModListeners )
257
0
        {
258
0
            loop->mapModified();
259
0
        }
260
0
    }
261
262
    typedef ::cppu::WeakImplHelper <   XEnumeration
263
                                   >   MapEnumeration_Base;
264
265
    namespace {
266
267
    class MapEnumeration :public ComponentBase
268
                         ,public MapEnumeration_Base
269
    {
270
    public:
271
        MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper,
272
                        const EnumerationType _type, const bool _isolated )
273
0
            :ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() )
274
0
            ,m_xKeepMapAlive( _parentMap )
275
0
            ,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : nullptr )
276
0
            ,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type )
277
0
        {
278
0
        }
279
280
        // XEnumeration
281
        virtual sal_Bool SAL_CALL hasMoreElements(  ) override;
282
        virtual Any SAL_CALL nextElement(  ) override;
283
284
    protected:
285
        virtual ~MapEnumeration() override
286
0
        {
287
0
            acquire();
288
0
            {
289
0
                ::osl::MutexGuard aGuard( getMutex() );
290
0
                m_aEnumerator.dispose();
291
0
                m_pMapDataCopy.reset();
292
0
            }
293
0
        }
294
295
    private:
296
        // since we share our mutex with the main map, we need to keep it alive as long as we live
297
        Reference< XInterface >     m_xKeepMapAlive;
298
        std::unique_ptr< MapData > m_pMapDataCopy;
299
        MapEnumerator               m_aEnumerator;
300
    };
301
302
    }
303
304
    EnumerableMap::EnumerableMap()
305
0
        :Map_IFace( m_aMutex )
306
0
        ,ComponentBase( Map_IFace::rBHelper )
307
0
    {
308
0
    }
309
310
311
    EnumerableMap::~EnumerableMap()
312
0
    {
313
0
        if ( !impl_isDisposed() )
314
0
        {
315
0
            acquire();
316
0
            dispose();
317
0
        }
318
0
    }
319
320
321
    void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments )
322
0
    {
323
0
        ComponentMethodGuard aGuard( *this, ComponentMethodGuard::MethodType::WithoutInit );
324
0
        if ( impl_isInitialized_nothrow() )
325
0
            throw AlreadyInitializedException();
326
327
0
        sal_Int32 nArgumentCount = _arguments.getLength();
328
0
        if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) )
329
0
            throw IllegalArgumentException(u"wrong number of args"_ustr, static_cast<cppu::OWeakObject*>(this), 1);
330
331
0
        Type aKeyType, aValueType;
332
0
        if ( !( _arguments[0] >>= aKeyType ) )
333
0
            throw IllegalArgumentException(u"com.sun.star.uno.Type expected."_ustr, *this, 1 );
334
0
        if ( !( _arguments[1] >>= aValueType ) )
335
0
            throw IllegalArgumentException(u"com.sun.star.uno.Type expected."_ustr, *this, 2 );
336
337
0
        Sequence< Pair< Any, Any > > aInitialValues;
338
0
        bool bMutable = true;
339
0
        if ( nArgumentCount == 3 )
340
0
        {
341
0
            if ( !( _arguments[2] >>= aInitialValues ) )
342
0
                throw IllegalArgumentException(u"[]com.sun.star.beans.Pair<any,any> expected."_ustr, *this, 2 );
343
0
            bMutable = false;
344
0
        }
345
346
        // for the value, anything is allowed, except VOID
347
0
        if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
348
0
            throw IllegalTypeException(u"Unsupported value type."_ustr, *this );
349
350
        // create the comparator for the KeyType, and throw if the type is not supported
351
0
        std::unique_ptr< IKeyPredicateLess > pComparator( getStandardLessPredicate( aKeyType, nullptr ) );
352
0
        if (!pComparator)
353
0
            throw IllegalTypeException(u"Unsupported key type."_ustr, *this );
354
355
        // init members
356
0
        m_aData.m_aKeyType = std::move(aKeyType);
357
0
        m_aData.m_aValueType = std::move(aValueType);
358
0
        m_aData.m_pKeyCompare = std::move(pComparator);
359
0
        m_aData.m_pValues.emplace( *m_aData.m_pKeyCompare );
360
0
        m_aData.m_bMutable = bMutable;
361
362
0
        if ( aInitialValues.hasElements() )
363
0
            impl_initValues_throw( aInitialValues );
364
365
0
        setInitialized();
366
0
    }
367
368
369
    void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues )
370
0
    {
371
0
        OSL_PRECOND( m_aData.m_pValues && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" );
372
0
        if (!m_aData.m_pValues || !m_aData.m_pValues->empty()){
373
0
            throw RuntimeException("EnumerableMap m_aData container is invalid or not empty.", *this);
374
0
        }
375
0
        for (auto& mapping : _initialValues)
376
0
        {
377
0
            impl_checkValue_throw(mapping.Second);
378
0
            (*m_aData.m_pValues)[mapping.First] = mapping.Second;
379
0
        }
380
0
    }
381
382
383
    void EnumerableMap::impl_checkValue_throw( const Any& _value ) const
384
0
    {
385
0
        if ( !_value.hasValue() )
386
            // nothing to do, NULL values are always allowed, regardless of the ValueType
387
0
            return;
388
389
0
        TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass();
390
0
        bool bValid = false;
391
392
0
        switch ( eAllowedTypeClass )
393
0
        {
394
0
        default:
395
0
            bValid = ( _value.getValueTypeClass() == eAllowedTypeClass );
396
0
            break;
397
0
        case TypeClass_ANY:
398
0
            bValid = true;
399
0
            break;
400
0
        case TypeClass_INTERFACE:
401
0
        {
402
            // special treatment: _value might contain the proper type, but the interface
403
            // might actually be NULL. Which is still valid ...
404
0
            if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) )
405
                // this also catches the special case where XFoo is our value type,
406
                // and _value contains a NULL-reference to XFoo, or a derived type
407
0
                bValid = true;
408
0
            else
409
0
            {
410
0
                Reference< XInterface > xValue( _value, UNO_QUERY );
411
0
                if ( xValue.is() )
412
                    // XInterface is not-NULL, but is X(ValueType) not-NULL, too?
413
0
                    xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY );
414
0
                bValid = xValue.is();
415
0
            }
416
0
        }
417
0
        break;
418
0
        case TypeClass_EXCEPTION:
419
0
        case TypeClass_STRUCT:
420
0
        {
421
            // values are accepted if and only if their type equals, or is derived from, our value type
422
423
0
            if ( _value.getValueTypeClass() != eAllowedTypeClass )
424
0
                bValid = false;
425
0
            else
426
0
            {
427
0
                const TypeDescription aValueTypeDesc( _value.getValueType() );
428
0
                const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType );
429
430
0
                const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc =
431
0
                    reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() );
432
433
0
                while ( pValueCompoundTypeDesc )
434
0
                {
435
0
                    if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) )
436
0
                        break;
437
0
                    pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription;
438
0
                }
439
0
                bValid = ( pValueCompoundTypeDesc != nullptr );
440
0
            }
441
0
        }
442
0
        break;
443
0
        }
444
445
0
        if ( !bValid )
446
0
        {
447
0
            throw IllegalTypeException(
448
0
                "Incompatible value type. Found '" + _value.getValueTypeName()
449
0
                + "', where '" + m_aData.m_aValueType.getTypeName()
450
0
                + "' (or compatible type) is expected.",
451
0
                *const_cast< EnumerableMap* >( this ) );
452
0
        }
453
454
0
        impl_checkNaN_throw( _value, m_aData.m_aValueType );
455
0
    }
456
457
458
    void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const
459
0
    {
460
0
        if  (   ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE )
461
0
            ||  ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT )
462
0
            )
463
0
        {
464
0
            double nValue(0);
465
0
            if ( _keyOrValue >>= nValue )
466
0
                if ( std::isnan( nValue ) )
467
0
                    throw IllegalArgumentException(
468
0
                        u"NaN (not-a-number) not supported by this implementation."_ustr,
469
0
                        *const_cast< EnumerableMap* >( this ), 0 );
470
            // (note that the case of _key not containing a float/double value is handled in the
471
            // respective IKeyPredicateLess implementation, so there's no need to handle this here.)
472
0
        }
473
0
    }
474
475
476
    void EnumerableMap::impl_checkKey_throw( const Any& _key ) const
477
0
    {
478
0
        if ( !_key.hasValue() )
479
0
            throw IllegalArgumentException(
480
0
                u"NULL keys not supported by this implementation."_ustr,
481
0
                *const_cast< EnumerableMap* >( this ), 0 );
482
483
0
        impl_checkNaN_throw( _key, m_aData.m_aKeyType );
484
0
    }
485
486
487
    void EnumerableMap::impl_checkMutable_throw() const
488
0
    {
489
0
        if ( !m_aData.m_bMutable )
490
0
            throw NoSupportException(
491
0
                    u"The map is immutable."_ustr,
492
0
                    *const_cast< EnumerableMap* >( this ) );
493
0
    }
494
495
496
    Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( sal_Bool Isolated )
497
0
    {
498
0
        ComponentMethodGuard aGuard( *this );
499
0
        return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, Isolated );
500
0
    }
501
502
503
    Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( sal_Bool Isolated )
504
0
    {
505
0
        ComponentMethodGuard aGuard( *this );
506
0
        return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, Isolated );
507
0
    }
508
509
510
    Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( sal_Bool Isolated )
511
0
    {
512
0
        ComponentMethodGuard aGuard( *this );
513
0
        return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, Isolated );
514
0
    }
515
516
517
    Type SAL_CALL EnumerableMap::getKeyType()
518
0
    {
519
0
        ComponentMethodGuard aGuard( *this );
520
0
        return m_aData.m_aKeyType;
521
0
    }
522
523
524
    Type SAL_CALL EnumerableMap::getValueType()
525
0
    {
526
0
        ComponentMethodGuard aGuard( *this );
527
0
        return m_aData.m_aValueType;
528
0
    }
529
530
531
    void SAL_CALL EnumerableMap::clear(  )
532
0
    {
533
0
        ComponentMethodGuard aGuard( *this );
534
0
        impl_checkMutable_throw();
535
536
0
        m_aData.m_pValues->clear();
537
538
0
        lcl_notifyMapDataListeners_nothrow( m_aData );
539
0
    }
540
541
542
    sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key )
543
0
    {
544
0
        ComponentMethodGuard aGuard( *this );
545
0
        impl_checkKey_throw( _key );
546
547
0
        KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
548
0
        return ( pos != m_aData.m_pValues->end() );
549
0
    }
550
551
552
    sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value )
553
0
    {
554
0
        ComponentMethodGuard aGuard( *this );
555
0
        impl_checkValue_throw( _value );
556
0
        for (auto const& value : *m_aData.m_pValues)
557
0
        {
558
0
            if ( value.second == _value )
559
0
                return true;
560
0
        }
561
0
        return false;
562
0
    }
563
564
565
    Any SAL_CALL EnumerableMap::get( const Any& _key )
566
0
    {
567
0
        ComponentMethodGuard aGuard( *this );
568
0
        impl_checkKey_throw( _key );
569
570
0
        KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
571
0
        if ( pos == m_aData.m_pValues->end() )
572
0
            throw NoSuchElementException( anyToString( _key ), *this );
573
574
0
        return pos->second;
575
0
    }
576
577
578
    Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value )
579
0
    {
580
0
        ComponentMethodGuard aGuard( *this );
581
0
        impl_checkMutable_throw();
582
0
        impl_checkKey_throw( _key );
583
0
        impl_checkValue_throw( _value );
584
585
0
        Any previousValue;
586
587
0
        KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
588
0
        if ( pos != m_aData.m_pValues->end() )
589
0
        {
590
0
            previousValue = pos->second;
591
0
            pos->second = _value;
592
0
        }
593
0
        else
594
0
        {
595
0
            (*m_aData.m_pValues)[ _key ] = _value;
596
0
        }
597
598
0
        lcl_notifyMapDataListeners_nothrow( m_aData );
599
600
0
        return previousValue;
601
0
    }
602
603
604
    Any SAL_CALL EnumerableMap::remove( const Any& _key )
605
0
    {
606
0
        ComponentMethodGuard aGuard( *this );
607
0
        impl_checkMutable_throw();
608
0
        impl_checkKey_throw( _key );
609
610
0
        Any previousValue;
611
612
0
        KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
613
0
        if ( pos != m_aData.m_pValues->end() )
614
0
        {
615
0
            previousValue = pos->second;
616
0
            m_aData.m_pValues->erase( pos );
617
0
        }
618
619
0
        lcl_notifyMapDataListeners_nothrow( m_aData );
620
621
0
        return previousValue;
622
0
    }
623
624
625
    Type SAL_CALL EnumerableMap::getElementType()
626
0
    {
627
0
        return ::cppu::UnoType< Pair< Any, Any > >::get();
628
0
    }
629
630
631
    sal_Bool SAL_CALL EnumerableMap::hasElements()
632
0
    {
633
0
        ComponentMethodGuard aGuard( *this );
634
0
        return m_aData.m_pValues->empty();
635
0
    }
636
637
638
    OUString SAL_CALL EnumerableMap::getImplementationName(  )
639
0
    {
640
0
        return u"org.openoffice.comp.comphelper.EnumerableMap"_ustr;
641
0
    }
642
643
    sal_Bool SAL_CALL EnumerableMap::supportsService( const OUString& _serviceName )
644
0
    {
645
0
        return cppu::supportsService(this, _serviceName);
646
0
    }
647
648
649
    Sequence< OUString > SAL_CALL EnumerableMap::getSupportedServiceNames(  )
650
0
    {
651
0
        return { u"com.sun.star.container.EnumerableMap"_ustr };
652
0
    }
653
654
    bool MapEnumerator::hasMoreElements()
655
0
    {
656
0
        if ( m_disposed )
657
0
            throw DisposedException( OUString(), m_rParent );
658
0
        return m_mapPos != m_rMapData.m_pValues->end();
659
0
    }
660
661
662
    Any MapEnumerator::nextElement()
663
0
    {
664
0
        if ( m_disposed )
665
0
            throw DisposedException( OUString(), m_rParent );
666
0
        if ( m_mapPos == m_rMapData.m_pValues->end() )
667
0
            throw NoSuchElementException(u"No more elements."_ustr, m_rParent );
668
669
0
        Any aNextElement;
670
0
        switch ( m_eType )
671
0
        {
672
0
        case eKeys:     aNextElement = m_mapPos->first; break;
673
0
        case eValues:   aNextElement = m_mapPos->second; break;
674
0
        case eBoth:     aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break;
675
0
        }
676
0
        ++m_mapPos;
677
0
        return aNextElement;
678
0
    }
679
680
681
    void MapEnumerator::mapModified()
682
0
    {
683
0
        m_disposed = true;
684
0
    }
685
686
687
    sal_Bool SAL_CALL MapEnumeration::hasMoreElements(  )
688
0
    {
689
0
        ComponentMethodGuard aGuard( *this );
690
0
        return m_aEnumerator.hasMoreElements();
691
0
    }
692
693
694
    Any SAL_CALL MapEnumeration::nextElement(  )
695
0
    {
696
0
        ComponentMethodGuard aGuard( *this );
697
0
        return m_aEnumerator.nextElement();
698
0
    }
699
700
701
} // namespace comphelper
702
703
704
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
705
org_openoffice_comp_comphelper_EnumerableMap(
706
    css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&)
707
0
{
708
0
    return cppu::acquire(new comphelper::EnumerableMap());
709
0
}
710
711
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */