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