/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: */ |