merged tag ooo/OOO330_m14
[LibreOffice.git] / comphelper / source / container / enumerablemap.cxx
blob15241cd72dd6dc8af6fed2734a494fb8e4b1a76b
1 /*************************************************************************
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * Copyright 2000, 2010 Oracle and/or its affiliates.
6 * OpenOffice.org - a multi-platform office productivity suite
8 * This file is part of OpenOffice.org.
10 * OpenOffice.org is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License version 3
12 * only, as published by the Free Software Foundation.
14 * OpenOffice.org is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License version 3 for more details
18 * (a copy is included in the LICENSE file that accompanied this code).
20 * You should have received a copy of the GNU Lesser General Public License
21 * version 3 along with OpenOffice.org. If not, see
22 * <http://www.openoffice.org/license.html>
23 * for a copy of the LGPLv3 License.
25 ************************************************************************/
27 // MARKER(update_precomp.py): autogen include statement, do not remove
28 #include "precompiled_comphelper.hxx"
30 #include "comphelper_module.hxx"
31 #include "comphelper/anytostring.hxx"
32 #include "comphelper/componentbase.hxx"
33 #include "comphelper/componentcontext.hxx"
34 #include "comphelper/extract.hxx"
36 /** === begin UNO includes === **/
37 #include <com/sun/star/container/XEnumerableMap.hpp>
38 #include <com/sun/star/lang/XInitialization.hpp>
39 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
40 #include <com/sun/star/beans/Pair.hpp>
41 #include <com/sun/star/lang/XServiceInfo.hpp>
42 /** === end UNO includes === **/
44 #include <cppuhelper/compbase3.hxx>
45 #include <cppuhelper/implbase1.hxx>
46 #include <rtl/math.hxx>
47 #include <rtl/ustrbuf.hxx>
48 #include <typelib/typedescription.hxx>
50 #include <functional>
51 #include <map>
52 #include <memory>
53 #include <boost/shared_ptr.hpp>
55 //........................................................................
56 namespace comphelper
58 //........................................................................
60 /** === begin UNO using === **/
61 using ::com::sun::star::uno::Reference;
62 using ::com::sun::star::uno::XInterface;
63 using ::com::sun::star::uno::UNO_QUERY;
64 using ::com::sun::star::uno::UNO_QUERY_THROW;
65 using ::com::sun::star::uno::UNO_SET_THROW;
66 using ::com::sun::star::uno::Exception;
67 using ::com::sun::star::uno::RuntimeException;
68 using ::com::sun::star::uno::Any;
69 using ::com::sun::star::uno::makeAny;
70 using ::com::sun::star::uno::Sequence;
71 using ::com::sun::star::uno::Type;
72 using ::com::sun::star::container::XEnumerableMap;
73 using ::com::sun::star::lang::NoSupportException;
74 using ::com::sun::star::beans::IllegalTypeException;
75 using ::com::sun::star::container::NoSuchElementException;
76 using ::com::sun::star::lang::IllegalArgumentException;
77 using ::com::sun::star::lang::XInitialization;
78 using ::com::sun::star::ucb::AlreadyInitializedException;
79 using ::com::sun::star::beans::Pair;
80 using ::com::sun::star::uno::TypeClass;
81 using ::com::sun::star::uno::TypeClass_VOID;
82 using ::com::sun::star::uno::TypeClass_CHAR;
83 using ::com::sun::star::uno::TypeClass_BOOLEAN;
84 using ::com::sun::star::uno::TypeClass_BYTE;
85 using ::com::sun::star::uno::TypeClass_SHORT;
86 using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT;
87 using ::com::sun::star::uno::TypeClass_LONG;
88 using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG;
89 using ::com::sun::star::uno::TypeClass_HYPER;
90 using ::com::sun::star::uno::TypeClass_UNSIGNED_HYPER;
91 using ::com::sun::star::uno::TypeClass_FLOAT;
92 using ::com::sun::star::uno::TypeClass_DOUBLE;
93 using ::com::sun::star::uno::TypeClass_STRING;
94 using ::com::sun::star::uno::TypeClass_TYPE;
95 using ::com::sun::star::uno::TypeClass_ENUM;
96 using ::com::sun::star::uno::TypeClass_INTERFACE;
97 using ::com::sun::star::uno::TypeClass_UNKNOWN;
98 using ::com::sun::star::uno::TypeClass_ANY;
99 using ::com::sun::star::uno::TypeClass_EXCEPTION;
100 using ::com::sun::star::uno::TypeClass_STRUCT;
101 using ::com::sun::star::uno::TypeClass_UNION;
102 using ::com::sun::star::lang::XServiceInfo;
103 using ::com::sun::star::uno::XComponentContext;
104 using ::com::sun::star::container::XEnumeration;
105 using ::com::sun::star::uno::TypeDescription;
106 using ::com::sun::star::lang::WrappedTargetException;
107 using ::com::sun::star::lang::DisposedException;
108 /** === end UNO using === **/
110 //====================================================================
111 //= IKeyPredicateLess
112 //====================================================================
113 class SAL_NO_VTABLE IKeyPredicateLess
115 public:
116 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const = 0;
117 virtual ~IKeyPredicateLess() {}
120 //====================================================================
121 //= LessPredicateAdapter
122 //====================================================================
123 struct LessPredicateAdapter : public ::std::binary_function< Any, Any, bool >
125 LessPredicateAdapter( const IKeyPredicateLess& _predicate )
126 :m_predicate( _predicate )
130 bool operator()( const Any& _lhs, const Any& _rhs ) const
132 return m_predicate.isLess( _lhs, _rhs );
135 private:
136 const IKeyPredicateLess& m_predicate;
138 private:
139 LessPredicateAdapter(); // never implemented
142 //====================================================================
143 //= ScalarPredicateLess
144 //====================================================================
145 template< typename SCALAR >
146 class ScalarPredicateLess : public IKeyPredicateLess
148 public:
149 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
151 SCALAR lhs(0), rhs(0);
152 if ( !( _lhs >>= lhs )
153 || !( _rhs >>= rhs )
155 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
156 return lhs < rhs;
160 //====================================================================
161 //= StringPredicateLess
162 //====================================================================
163 class StringPredicateLess : public IKeyPredicateLess
165 public:
166 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
168 ::rtl::OUString lhs, rhs;
169 if ( !( _lhs >>= lhs )
170 || !( _rhs >>= rhs )
172 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
173 return lhs < rhs;
177 //====================================================================
178 //= TypePredicateLess
179 //====================================================================
180 class TypePredicateLess : public IKeyPredicateLess
182 public:
183 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
185 Type lhs, rhs;
186 if ( !( _lhs >>= lhs )
187 || !( _rhs >>= rhs )
189 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
190 return lhs.getTypeName() < rhs.getTypeName();
194 //====================================================================
195 //= EnumPredicateLess
196 //====================================================================
197 class EnumPredicateLess : public IKeyPredicateLess
199 public:
200 EnumPredicateLess( const Type& _enumType )
201 :m_enumType( _enumType )
205 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
207 sal_Int32 lhs(0), rhs(0);
208 if ( !::cppu::enum2int( lhs, _lhs )
209 || !::cppu::enum2int( rhs, _rhs )
210 || !_lhs.getValueType().equals( m_enumType )
211 || !_rhs.getValueType().equals( m_enumType )
213 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
214 return lhs < rhs;
217 private:
218 const Type m_enumType;
221 //====================================================================
222 //= InterfacePredicateLess
223 //====================================================================
224 class InterfacePredicateLess : public IKeyPredicateLess
226 public:
227 virtual bool isLess( const Any& _lhs, const Any& _rhs ) const
229 if ( ( _lhs.getValueTypeClass() != TypeClass_INTERFACE )
230 || ( _rhs.getValueTypeClass() != TypeClass_INTERFACE )
232 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), NULL, 1 );
234 Reference< XInterface > lhs( _lhs, UNO_QUERY );
235 Reference< XInterface > rhs( _rhs, UNO_QUERY );
236 return lhs.get() < rhs.get();
240 //====================================================================
241 //= MapData
242 //====================================================================
243 class IMapModificationListener;
244 typedef ::std::vector< IMapModificationListener* > MapListeners;
246 typedef ::std::map< Any, Any, LessPredicateAdapter > KeyedValues;
247 struct MapData
249 Type m_aKeyType;
250 Type m_aValueType;
251 ::std::auto_ptr< KeyedValues > m_pValues;
252 ::boost::shared_ptr< IKeyPredicateLess > m_pKeyCompare;
253 bool m_bMutable;
254 MapListeners m_aModListeners;
256 MapData()
257 :m_bMutable( true )
261 MapData( const MapData& _source )
262 :m_aKeyType( _source.m_aKeyType )
263 ,m_aValueType( _source.m_aValueType )
264 ,m_pValues( new KeyedValues( *_source.m_pValues ) )
265 ,m_pKeyCompare( _source.m_pKeyCompare )
266 ,m_bMutable( false )
267 ,m_aModListeners()
270 private:
271 MapData& operator=( const MapData& _source ); // not implemented
274 //====================================================================
275 //= IMapModificationListener
276 //====================================================================
277 /** implemented by components who want to be notified of modifications in the MapData they work with
279 class SAL_NO_VTABLE IMapModificationListener
281 public:
282 /// called when the map was modified
283 virtual void mapModified() = 0;
284 virtual ~IMapModificationListener()
289 //====================================================================
290 //= MapData helpers
291 //====================================================================
292 //--------------------------------------------------------------------
293 static void lcl_registerMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
295 #if OSL_DEBUG_LEVEL > 0
296 for ( MapListeners::const_iterator lookup = _mapData.m_aModListeners.begin();
297 lookup != _mapData.m_aModListeners.end();
298 ++lookup
301 OSL_ENSURE( *lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" );
303 #endif
304 _mapData.m_aModListeners.push_back( &_listener );
307 //--------------------------------------------------------------------
308 static void lcl_revokeMapModificationListener( MapData& _mapData, IMapModificationListener& _listener )
310 for ( MapListeners::iterator lookup = _mapData.m_aModListeners.begin();
311 lookup != _mapData.m_aModListeners.end();
312 ++lookup
315 if ( *lookup == &_listener )
317 _mapData.m_aModListeners.erase( lookup );
318 return;
321 OSL_ENSURE( false, "lcl_revokeMapModificationListener: the listener is not registered!" );
324 //--------------------------------------------------------------------
325 static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData )
327 for ( MapListeners::const_iterator loop = _mapData.m_aModListeners.begin();
328 loop != _mapData.m_aModListeners.end();
329 ++loop
332 (*loop)->mapModified();
336 //====================================================================
337 //= EnumerableMap
338 //====================================================================
339 typedef ::cppu::WeakAggComponentImplHelper3 < XInitialization
340 , XEnumerableMap
341 , XServiceInfo
342 > Map_IFace;
344 class COMPHELPER_DLLPRIVATE EnumerableMap :public Map_IFace
345 ,public ComponentBase
347 protected:
348 EnumerableMap( const ComponentContext& _rContext );
349 virtual ~EnumerableMap();
351 // XInitialization
352 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException);
354 // XEnumerableMap
355 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);
356 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);
357 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);
359 // XMap
360 virtual Type SAL_CALL getKeyType() throw (RuntimeException);
361 virtual Type SAL_CALL getValueType() throw (RuntimeException);
362 virtual void SAL_CALL clear( ) throw (NoSupportException, RuntimeException);
363 virtual ::sal_Bool SAL_CALL containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
364 virtual ::sal_Bool SAL_CALL containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException);
365 virtual Any SAL_CALL get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
366 virtual Any SAL_CALL put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException);
367 virtual Any SAL_CALL remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException);
369 // XElementAccess (base of XMap)
370 virtual Type SAL_CALL getElementType() throw (RuntimeException);
371 virtual ::sal_Bool SAL_CALL hasElements() throw (RuntimeException);
373 // XServiceInfo
374 virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (RuntimeException);
375 virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException);
376 virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException);
378 public:
379 // XServiceInfo, static version (used for component registration)
380 static ::rtl::OUString SAL_CALL getImplementationName_static( );
381 static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static( );
382 static Reference< XInterface > SAL_CALL Create( const Reference< XComponentContext >& );
384 private:
385 void impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues );
387 /// throws a IllegalTypeException if the given value is not compatible with our ValueType
388 void impl_checkValue_throw( const Any& _value ) const;
389 void impl_checkKey_throw( const Any& _key ) const;
390 void impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const;
391 void impl_checkMutable_throw() const;
393 private:
394 ::osl::Mutex m_aMutex;
395 ComponentContext m_aContext;
396 MapData m_aData;
398 ::std::vector< ::com::sun::star::uno::WeakReference< XInterface > >
399 m_aDependentComponents;
402 //====================================================================
403 //= EnumerationType
404 //====================================================================
405 enum EnumerationType
407 eKeys, eValues, eBoth
410 //====================================================================
411 //= MapEnumerator
412 //====================================================================
413 class MapEnumerator : public IMapModificationListener
415 public:
416 MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type )
417 :m_rParent( _rParent )
418 ,m_rMapData( _mapData )
419 ,m_eType( _type )
420 ,m_mapPos( _mapData.m_pValues->begin() )
421 ,m_disposed( false )
423 lcl_registerMapModificationListener( m_rMapData, *this );
426 virtual ~MapEnumerator()
428 dispose();
431 void dispose()
433 if ( !m_disposed )
435 lcl_revokeMapModificationListener( m_rMapData, *this );
436 m_disposed = true;
440 // XEnumeration equivalents
441 ::sal_Bool hasMoreElements();
442 Any nextElement();
444 // IMapModificationListener
445 virtual void mapModified();
447 private:
448 ::cppu::OWeakObject& m_rParent;
449 MapData& m_rMapData;
450 const EnumerationType m_eType;
451 KeyedValues::const_iterator m_mapPos;
452 bool m_disposed;
454 private:
455 MapEnumerator(); // not implemented
456 MapEnumerator( const MapEnumerator& ); // not implemented
457 MapEnumerator& operator=( const MapEnumerator& ); // not implemented
460 //====================================================================
461 //= MapEnumeration
462 //====================================================================
463 typedef ::cppu::WeakImplHelper1 < XEnumeration
464 > MapEnumeration_Base;
465 class MapEnumeration :public ComponentBase
466 ,public MapEnumeration_Base
468 public:
469 MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper,
470 const EnumerationType _type, const bool _isolated )
471 :ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() )
472 ,m_xKeepMapAlive( _parentMap )
473 ,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : NULL )
474 ,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type )
478 // XEnumeration
479 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (RuntimeException);
480 virtual Any SAL_CALL nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException);
482 protected:
483 virtual ~MapEnumeration()
485 acquire();
487 ::osl::MutexGuard aGuard( getMutex() );
488 m_aEnumerator.dispose();
489 m_pMapDataCopy.reset();
493 private:
494 // sicne we share our mutex with the main map, we need to keep it alive as long as we live
495 Reference< XInterface > m_xKeepMapAlive;
496 ::std::auto_ptr< MapData > m_pMapDataCopy;
497 MapEnumerator m_aEnumerator;
500 //====================================================================
501 //= EnumerableMap
502 //====================================================================
503 //--------------------------------------------------------------------
504 EnumerableMap::EnumerableMap( const ComponentContext& _rContext )
505 :Map_IFace( m_aMutex )
506 ,ComponentBase( Map_IFace::rBHelper )
507 ,m_aContext( _rContext )
511 //--------------------------------------------------------------------
512 EnumerableMap::~EnumerableMap()
514 if ( !impl_isDisposed() )
516 acquire();
517 dispose();
521 //--------------------------------------------------------------------
522 void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
524 ComponentMethodGuard aGuard( *this, ComponentMethodGuard::WithoutInit );
525 if ( impl_isInitialized_nothrow() )
526 throw AlreadyInitializedException();
528 sal_Int32 nArgumentCount = _arguments.getLength();
529 if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) )
530 throw IllegalArgumentException();
532 Type aKeyType, aValueType;
533 if ( !( _arguments[0] >>= aKeyType ) )
534 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 1 );
535 if ( !( _arguments[1] >>= aValueType ) )
536 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "com.sun.star.uno.Type expected." ), *this, 2 );
538 Sequence< Pair< Any, Any > > aInitialValues;
539 bool bMutable = true;
540 if ( nArgumentCount == 3 )
542 if ( !( _arguments[2] >>= aInitialValues ) )
543 throw IllegalArgumentException( ::rtl::OUString::createFromAscii( "[]com.sun.star.beans.Pair<any,any> expected." ), *this, 2 );
544 bMutable = false;
547 // for the value, anything is allowed, except VOID
548 if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
549 throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported value type." ) ), *this );
551 // create the comparator for the KeyType, and throw if the type is not supported
552 TypeClass eKeyTypeClass = aKeyType.getTypeClass();
553 ::std::auto_ptr< IKeyPredicateLess > pComparator;
554 switch ( eKeyTypeClass )
556 case TypeClass_CHAR:
557 pComparator.reset( new ScalarPredicateLess< sal_Unicode >() );
558 break;
559 case TypeClass_BOOLEAN:
560 pComparator.reset( new ScalarPredicateLess< sal_Bool >() );
561 break;
562 case TypeClass_BYTE:
563 pComparator.reset( new ScalarPredicateLess< sal_Int8 >() );
564 break;
565 case TypeClass_SHORT:
566 pComparator.reset( new ScalarPredicateLess< sal_Int16 >() );
567 break;
568 case TypeClass_UNSIGNED_SHORT:
569 pComparator.reset( new ScalarPredicateLess< sal_uInt16 >() );
570 break;
571 case TypeClass_LONG:
572 pComparator.reset( new ScalarPredicateLess< sal_Int32 >() );
573 break;
574 case TypeClass_UNSIGNED_LONG:
575 pComparator.reset( new ScalarPredicateLess< sal_uInt32 >() );
576 break;
577 case TypeClass_HYPER:
578 pComparator.reset( new ScalarPredicateLess< sal_Int64 >() );
579 break;
580 case TypeClass_UNSIGNED_HYPER:
581 pComparator.reset( new ScalarPredicateLess< sal_uInt64 >() );
582 break;
583 case TypeClass_FLOAT:
584 pComparator.reset( new ScalarPredicateLess< float >() );
585 break;
586 case TypeClass_DOUBLE:
587 pComparator.reset( new ScalarPredicateLess< double >() );
588 break;
589 case TypeClass_STRING:
590 pComparator.reset( new StringPredicateLess() );
591 break;
592 case TypeClass_TYPE:
593 pComparator.reset( new TypePredicateLess() );
594 break;
595 case TypeClass_ENUM:
596 pComparator.reset( new EnumPredicateLess( aKeyType ) );
597 break;
598 case TypeClass_INTERFACE:
599 pComparator.reset( new InterfacePredicateLess() );
600 break;
601 default:
602 throw IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unsupported key type." ) ), *this );
605 // init members
606 m_aData.m_aKeyType = aKeyType;
607 m_aData.m_aValueType = aValueType;
608 m_aData.m_pKeyCompare = pComparator;
609 m_aData.m_pValues.reset( new KeyedValues( *m_aData.m_pKeyCompare ) );
610 m_aData.m_bMutable = bMutable;
612 if ( aInitialValues.getLength() )
613 impl_initValues_throw( aInitialValues );
615 setInitialized();
618 //--------------------------------------------------------------------
619 void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues )
621 OSL_PRECOND( m_aData.m_pValues.get() && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" );
622 if ( !m_aData.m_pValues.get() || !m_aData.m_pValues->empty() )
623 throw RuntimeException();
625 const Pair< Any, Any >* mapping = _initialValues.getConstArray();
626 const Pair< Any, Any >* mappingEnd = mapping + _initialValues.getLength();
627 Any normalizedValue;
628 for ( ; mapping != mappingEnd; ++mapping )
630 impl_checkValue_throw( mapping->Second );
631 (*m_aData.m_pValues)[ mapping->First ] = mapping->Second;
635 //--------------------------------------------------------------------
636 void EnumerableMap::impl_checkValue_throw( const Any& _value ) const
638 if ( !_value.hasValue() )
639 // nothing to do, NULL values are always allowed, regardless of the ValueType
640 return;
642 TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass();
643 bool bValid = false;
645 switch ( eAllowedTypeClass )
647 default:
648 bValid = ( _value.getValueTypeClass() == eAllowedTypeClass );
649 break;
650 case TypeClass_ANY:
651 bValid = true;
652 break;
653 case TypeClass_INTERFACE:
655 // special treatment: _value might contain the proper type, but the interface
656 // might actually be NULL. Which is still valid ...
657 if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) )
658 // this also catches the special case where XFoo is our value type,
659 // and _value contains a NULL-reference to XFoo, or a derived type
660 bValid = true;
661 else
663 Reference< XInterface > xValue( _value, UNO_QUERY );
664 Any aTypedValue;
665 if ( xValue.is() )
666 // XInterface is not-NULL, but is X(ValueType) not-NULL, too?
667 xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY );
668 bValid = xValue.is();
671 break;
672 case TypeClass_EXCEPTION:
673 case TypeClass_STRUCT:
674 case TypeClass_UNION:
676 // values are accepted if and only if their type equals, or is derived from, our value type
678 if ( _value.getValueTypeClass() != eAllowedTypeClass )
679 bValid = false;
680 else
682 const TypeDescription aValueTypeDesc( _value.getValueType() );
683 const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType );
685 const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc =
686 reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() );
688 while ( pValueCompoundTypeDesc )
690 if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) )
691 break;
692 pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription;
694 bValid = ( pValueCompoundTypeDesc != NULL );
697 break;
700 if ( !bValid )
702 ::rtl::OUStringBuffer aMessage;
703 aMessage.appendAscii( "Incompatible value type. Found '" );
704 aMessage.append( _value.getValueTypeName() );
705 aMessage.appendAscii( "', where '" );
706 aMessage.append( m_aData.m_aValueType.getTypeName() );
707 aMessage.appendAscii( "' (or compatible type) is expected." );
708 throw IllegalTypeException( aMessage.makeStringAndClear(), *const_cast< EnumerableMap* >( this ) );
711 impl_checkNaN_throw( _value, m_aData.m_aValueType );
714 //--------------------------------------------------------------------
715 void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const
717 if ( ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE )
718 || ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT )
721 double nValue(0);
722 if ( _keyOrValue >>= nValue )
723 if ( ::rtl::math::isNan( nValue ) )
724 throw IllegalArgumentException(
725 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NaN (not-a-number) not supported by this implementation." ) ),
726 *const_cast< EnumerableMap* >( this ), 0 );
727 // (note that the case of _key not containing a float/double value is handled in the
728 // respective IKeyPredicateLess implementation, so there's no need to handle this here.)
732 //--------------------------------------------------------------------
733 void EnumerableMap::impl_checkKey_throw( const Any& _key ) const
735 if ( !_key.hasValue() )
736 throw IllegalArgumentException(
737 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "NULL keys not supported by this implementation." ) ),
738 *const_cast< EnumerableMap* >( this ), 0 );
740 impl_checkNaN_throw( _key, m_aData.m_aKeyType );
743 //--------------------------------------------------------------------
744 void EnumerableMap::impl_checkMutable_throw() const
746 if ( !m_aData.m_bMutable )
747 throw NoSupportException(
748 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The map is immutable." ) ),
749 *const_cast< EnumerableMap* >( this ) );
752 //--------------------------------------------------------------------
753 Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
755 ComponentMethodGuard aGuard( *this );
756 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, _Isolated );
759 //--------------------------------------------------------------------
760 Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
762 ComponentMethodGuard aGuard( *this );
763 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, _Isolated );
766 //--------------------------------------------------------------------
767 Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( ::sal_Bool _Isolated ) throw (NoSupportException, RuntimeException)
769 ComponentMethodGuard aGuard( *this );
770 return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, _Isolated );
773 //--------------------------------------------------------------------
774 Type SAL_CALL EnumerableMap::getKeyType() throw (RuntimeException)
776 ComponentMethodGuard aGuard( *this );
777 return m_aData.m_aKeyType;
780 //--------------------------------------------------------------------
781 Type SAL_CALL EnumerableMap::getValueType() throw (RuntimeException)
783 ComponentMethodGuard aGuard( *this );
784 return m_aData.m_aValueType;
787 //--------------------------------------------------------------------
788 void SAL_CALL EnumerableMap::clear( ) throw (NoSupportException, RuntimeException)
790 ComponentMethodGuard aGuard( *this );
791 impl_checkMutable_throw();
793 m_aData.m_pValues->clear();
795 lcl_notifyMapDataListeners_nothrow( m_aData );
798 //--------------------------------------------------------------------
799 ::sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
801 ComponentMethodGuard aGuard( *this );
802 impl_checkKey_throw( _key );
804 KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
805 return ( pos != m_aData.m_pValues->end() );
808 //--------------------------------------------------------------------
809 ::sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value ) throw (IllegalTypeException, IllegalArgumentException, RuntimeException)
811 ComponentMethodGuard aGuard( *this );
812 impl_checkValue_throw( _value );
814 for ( KeyedValues::const_iterator mapping = m_aData.m_pValues->begin();
815 mapping != m_aData.m_pValues->end();
816 ++mapping
819 if ( mapping->second == _value )
820 return sal_True;
822 return sal_False;
825 //--------------------------------------------------------------------
826 Any SAL_CALL EnumerableMap::get( const Any& _key ) throw (IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
828 ComponentMethodGuard aGuard( *this );
829 impl_checkKey_throw( _key );
831 KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
832 if ( pos == m_aData.m_pValues->end() )
833 throw NoSuchElementException( anyToString( _key ), *this );
835 return pos->second;
838 //--------------------------------------------------------------------
839 Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, RuntimeException)
841 ComponentMethodGuard aGuard( *this );
842 impl_checkMutable_throw();
843 impl_checkKey_throw( _key );
844 impl_checkValue_throw( _value );
846 Any previousValue;
848 KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
849 if ( pos != m_aData.m_pValues->end() )
851 previousValue = pos->second;
852 pos->second = _value;
854 else
856 (*m_aData.m_pValues)[ _key ] = _value;
859 lcl_notifyMapDataListeners_nothrow( m_aData );
861 return previousValue;
864 //--------------------------------------------------------------------
865 Any SAL_CALL EnumerableMap::remove( const Any& _key ) throw (NoSupportException, IllegalTypeException, IllegalArgumentException, NoSuchElementException, RuntimeException)
867 ComponentMethodGuard aGuard( *this );
868 impl_checkMutable_throw();
869 impl_checkKey_throw( _key );
871 Any previousValue;
873 KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
874 if ( pos != m_aData.m_pValues->end() )
876 previousValue = pos->second;
877 m_aData.m_pValues->erase( pos );
880 lcl_notifyMapDataListeners_nothrow( m_aData );
882 return previousValue;
885 //--------------------------------------------------------------------
886 Type SAL_CALL EnumerableMap::getElementType() throw (RuntimeException)
888 return ::cppu::UnoType< Pair< Any, Any > >::get();
891 //--------------------------------------------------------------------
892 ::sal_Bool SAL_CALL EnumerableMap::hasElements() throw (RuntimeException)
894 ComponentMethodGuard aGuard( *this );
895 return m_aData.m_pValues->empty();
898 //--------------------------------------------------------------------
899 ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName( ) throw (RuntimeException)
901 return getImplementationName_static();
904 //--------------------------------------------------------------------
905 ::sal_Bool SAL_CALL EnumerableMap::supportsService( const ::rtl::OUString& _serviceName ) throw (RuntimeException)
907 Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() );
908 for ( sal_Int32 i=0; i<aServices.getLength(); ++i )
909 if ( _serviceName == aServices[i] )
910 return sal_True;
911 return sal_False;
914 //--------------------------------------------------------------------
915 Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames( ) throw (RuntimeException)
917 return getSupportedServiceNames_static();
920 //--------------------------------------------------------------------
921 ::rtl::OUString SAL_CALL EnumerableMap::getImplementationName_static( )
923 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.comphelper.EnumerableMap" ) );
926 //--------------------------------------------------------------------
927 Sequence< ::rtl::OUString > SAL_CALL EnumerableMap::getSupportedServiceNames_static( )
929 Sequence< ::rtl::OUString > aServiceNames(1);
930 aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.container.EnumerableMap" ) );
931 return aServiceNames;
934 //--------------------------------------------------------------------
935 Reference< XInterface > SAL_CALL EnumerableMap::Create( const Reference< XComponentContext >& _context )
937 return *new EnumerableMap( ComponentContext( _context ) );
940 //====================================================================
941 //= MapEnumerator
942 //====================================================================
943 //--------------------------------------------------------------------
944 ::sal_Bool MapEnumerator::hasMoreElements()
946 if ( m_disposed )
947 throw DisposedException( ::rtl::OUString(), m_rParent );
948 return m_mapPos != m_rMapData.m_pValues->end();
951 //--------------------------------------------------------------------
952 Any MapEnumerator::nextElement()
954 if ( m_disposed )
955 throw DisposedException( ::rtl::OUString(), m_rParent );
956 if ( m_mapPos == m_rMapData.m_pValues->end() )
957 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "No more elements." ) ), m_rParent );
959 Any aNextElement;
960 switch ( m_eType )
962 case eKeys: aNextElement = m_mapPos->first; break;
963 case eValues: aNextElement = m_mapPos->second; break;
964 case eBoth: aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break;
966 ++m_mapPos;
967 return aNextElement;
970 //--------------------------------------------------------------------
971 void MapEnumerator::mapModified()
973 m_disposed = true;
976 //====================================================================
977 //= MapEnumeration - implementation
978 //====================================================================
979 //--------------------------------------------------------------------
980 ::sal_Bool SAL_CALL MapEnumeration::hasMoreElements( ) throw (RuntimeException)
982 ComponentMethodGuard aGuard( *this );
983 return m_aEnumerator.hasMoreElements();
986 //--------------------------------------------------------------------
987 Any SAL_CALL MapEnumeration::nextElement( ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
989 ComponentMethodGuard aGuard( *this );
990 return m_aEnumerator.nextElement();
993 //........................................................................
994 } // namespace comphelper
995 //........................................................................
997 void createRegistryInfo_Map()
999 ::comphelper::module::OAutoRegistration< ::comphelper::EnumerableMap > aAutoRegistration;