summaryrefslogtreecommitdiffstats
path: root/comphelper/source/container/enumerablemap.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /comphelper/source/container/enumerablemap.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comphelper/source/container/enumerablemap.cxx')
-rw-r--r--comphelper/source/container/enumerablemap.cxx713
1 files changed, 713 insertions, 0 deletions
diff --git a/comphelper/source/container/enumerablemap.cxx b/comphelper/source/container/enumerablemap.cxx
new file mode 100644
index 0000000000..ae78223a20
--- /dev/null
+++ b/comphelper/source/container/enumerablemap.cxx
@@ -0,0 +1,713 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <comphelper/anytostring.hxx>
+#include <comphelper/anycompare.hxx>
+#include <comphelper/componentbase.hxx>
+
+#include <com/sun/star/container/XEnumerableMap.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/Pair.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <typelib/typedescription.hxx>
+
+#include <cmath>
+#include <map>
+#include <memory>
+#include <optional>
+#include <utility>
+
+namespace comphelper
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::container::XEnumerableMap;
+ using ::com::sun::star::lang::NoSupportException;
+ using ::com::sun::star::beans::IllegalTypeException;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::lang::XInitialization;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+ using ::com::sun::star::beans::Pair;
+ using ::com::sun::star::uno::TypeClass;
+ using ::com::sun::star::uno::TypeClass_VOID;
+ using ::com::sun::star::uno::TypeClass_UNKNOWN;
+ using ::com::sun::star::uno::TypeClass_ANY;
+ using ::com::sun::star::uno::TypeClass_EXCEPTION;
+ using ::com::sun::star::uno::TypeClass_STRUCT;
+ using ::com::sun::star::uno::TypeClass_FLOAT;
+ using ::com::sun::star::uno::TypeClass_DOUBLE;
+ using ::com::sun::star::uno::TypeClass_INTERFACE;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::uno::TypeDescription;
+ using ::com::sun::star::lang::DisposedException;
+
+ namespace {
+
+ class MapEnumerator;
+
+ }
+
+ typedef std::map< Any, Any, LessPredicateAdapter > KeyedValues;
+
+ namespace {
+
+ struct MapData
+ {
+ Type m_aKeyType;
+ Type m_aValueType;
+ std::optional< KeyedValues > m_pValues;
+ std::shared_ptr< IKeyPredicateLess > m_pKeyCompare;
+ bool m_bMutable;
+ std::vector< MapEnumerator* > m_aModListeners;
+
+ MapData()
+ :m_bMutable( true )
+ {
+ }
+
+ MapData( const MapData& _source )
+ :m_aKeyType( _source.m_aKeyType )
+ ,m_aValueType( _source.m_aValueType )
+ ,m_pKeyCompare( _source.m_pKeyCompare )
+ ,m_bMutable( false )
+ {
+ m_pValues.emplace( *_source.m_pValues );
+ }
+ private:
+ MapData& operator=( const MapData& _source ) = delete;
+ };
+
+ }
+
+ static void lcl_registerMapModificationListener( MapData& _mapData, MapEnumerator& _listener )
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ for ( const MapEnumerator* lookup : _mapData.m_aModListeners )
+ {
+ OSL_ENSURE( lookup != &_listener, "lcl_registerMapModificationListener: this listener is already registered!" );
+ }
+ #endif
+ _mapData.m_aModListeners.push_back( &_listener );
+ }
+
+
+ static void lcl_revokeMapModificationListener( MapData& _mapData, MapEnumerator& _listener )
+ {
+ auto lookup = std::find(_mapData.m_aModListeners.begin(), _mapData.m_aModListeners.end(), &_listener);
+ if (lookup != _mapData.m_aModListeners.end())
+ {
+ _mapData.m_aModListeners.erase( lookup );
+ return;
+ }
+ OSL_FAIL( "lcl_revokeMapModificationListener: the listener is not registered!" );
+ }
+
+
+ static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData );
+
+
+ // EnumerableMap
+
+ typedef ::cppu::WeakComponentImplHelper < XInitialization
+ , XEnumerableMap
+ , XServiceInfo
+ > Map_IFace;
+
+ namespace {
+
+ class EnumerableMap: public Map_IFace, public ComponentBase
+ {
+ public:
+ EnumerableMap();
+ protected:
+ virtual ~EnumerableMap() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XEnumerableMap
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createKeyEnumeration( sal_Bool Isolated ) override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createValueEnumeration( sal_Bool Isolated ) override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createElementEnumeration( sal_Bool Isolated ) override;
+
+ // XMap
+ virtual Type SAL_CALL getKeyType() override;
+ virtual Type SAL_CALL getValueType() override;
+ virtual void SAL_CALL clear( ) override;
+ virtual sal_Bool SAL_CALL containsKey( const Any& _key ) override;
+ virtual sal_Bool SAL_CALL containsValue( const Any& _value ) override;
+ virtual Any SAL_CALL get( const Any& _key ) override;
+ virtual Any SAL_CALL put( const Any& _key, const Any& _value ) override;
+ virtual Any SAL_CALL remove( const Any& _key ) override;
+
+ // XElementAccess (base of XMap)
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ private:
+ void impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues );
+
+ /// throws an IllegalTypeException if the given value is not compatible with our ValueType
+ void impl_checkValue_throw( const Any& _value ) const;
+ void impl_checkKey_throw( const Any& _key ) const;
+ void impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const;
+ void impl_checkMutable_throw() const;
+
+ private:
+ ::osl::Mutex m_aMutex;
+ MapData m_aData;
+ };
+
+ enum EnumerationType
+ {
+ eKeys, eValues, eBoth
+ };
+
+ class MapEnumerator final
+ {
+ public:
+ MapEnumerator( ::cppu::OWeakObject& _rParent, MapData& _mapData, const EnumerationType _type )
+ :m_rParent( _rParent )
+ ,m_rMapData( _mapData )
+ ,m_eType( _type )
+ ,m_mapPos( _mapData.m_pValues->begin() )
+ ,m_disposed( false )
+ {
+ lcl_registerMapModificationListener( m_rMapData, *this );
+ }
+
+ ~MapEnumerator()
+ {
+ dispose();
+ }
+
+ void dispose()
+ {
+ if ( !m_disposed )
+ {
+ lcl_revokeMapModificationListener( m_rMapData, *this );
+ m_disposed = true;
+ }
+ }
+
+ // noncopyable
+ MapEnumerator(const MapEnumerator&) = delete;
+ const MapEnumerator& operator=(const MapEnumerator&) = delete;
+
+ // XEnumeration equivalents
+ bool hasMoreElements();
+ Any nextElement();
+
+ /// called when the map was modified
+ void mapModified();
+
+ private:
+ ::cppu::OWeakObject& m_rParent;
+ MapData& m_rMapData;
+ const EnumerationType m_eType;
+ KeyedValues::const_iterator m_mapPos;
+ bool m_disposed;
+ };
+
+ }
+
+ static void lcl_notifyMapDataListeners_nothrow( const MapData& _mapData )
+ {
+ for ( MapEnumerator* loop : _mapData.m_aModListeners )
+ {
+ loop->mapModified();
+ }
+ }
+
+ typedef ::cppu::WeakImplHelper < XEnumeration
+ > MapEnumeration_Base;
+
+ namespace {
+
+ class MapEnumeration :public ComponentBase
+ ,public MapEnumeration_Base
+ {
+ public:
+ MapEnumeration( ::cppu::OWeakObject& _parentMap, MapData& _mapData, ::cppu::OBroadcastHelper& _rBHelper,
+ const EnumerationType _type, const bool _isolated )
+ :ComponentBase( _rBHelper, ComponentBase::NoInitializationNeeded() )
+ ,m_xKeepMapAlive( _parentMap )
+ ,m_pMapDataCopy( _isolated ? new MapData( _mapData ) : nullptr )
+ ,m_aEnumerator( *this, _isolated ? *m_pMapDataCopy : _mapData, _type )
+ {
+ }
+
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual Any SAL_CALL nextElement( ) override;
+
+ protected:
+ virtual ~MapEnumeration() override
+ {
+ acquire();
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ m_aEnumerator.dispose();
+ m_pMapDataCopy.reset();
+ }
+ }
+
+ private:
+ // since we share our mutex with the main map, we need to keep it alive as long as we live
+ Reference< XInterface > m_xKeepMapAlive;
+ std::unique_ptr< MapData > m_pMapDataCopy;
+ MapEnumerator m_aEnumerator;
+ };
+
+ }
+
+ EnumerableMap::EnumerableMap()
+ :Map_IFace( m_aMutex )
+ ,ComponentBase( Map_IFace::rBHelper )
+ {
+ }
+
+
+ EnumerableMap::~EnumerableMap()
+ {
+ if ( !impl_isDisposed() )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+
+ void SAL_CALL EnumerableMap::initialize( const Sequence< Any >& _arguments )
+ {
+ ComponentMethodGuard aGuard( *this, ComponentMethodGuard::MethodType::WithoutInit );
+ if ( impl_isInitialized_nothrow() )
+ throw AlreadyInitializedException();
+
+ sal_Int32 nArgumentCount = _arguments.getLength();
+ if ( ( nArgumentCount != 2 ) && ( nArgumentCount != 3 ) )
+ throw IllegalArgumentException("wrong number of args", static_cast<cppu::OWeakObject*>(this), 1);
+
+ Type aKeyType, aValueType;
+ if ( !( _arguments[0] >>= aKeyType ) )
+ throw IllegalArgumentException("com.sun.star.uno.Type expected.", *this, 1 );
+ if ( !( _arguments[1] >>= aValueType ) )
+ throw IllegalArgumentException("com.sun.star.uno.Type expected.", *this, 2 );
+
+ Sequence< Pair< Any, Any > > aInitialValues;
+ bool bMutable = true;
+ if ( nArgumentCount == 3 )
+ {
+ if ( !( _arguments[2] >>= aInitialValues ) )
+ throw IllegalArgumentException("[]com.sun.star.beans.Pair<any,any> expected.", *this, 2 );
+ bMutable = false;
+ }
+
+ // for the value, anything is allowed, except VOID
+ if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
+ throw IllegalTypeException("Unsupported value type.", *this );
+
+ // create the comparator for the KeyType, and throw if the type is not supported
+ std::unique_ptr< IKeyPredicateLess > pComparator( getStandardLessPredicate( aKeyType, nullptr ) );
+ if (!pComparator)
+ throw IllegalTypeException("Unsupported key type.", *this );
+
+ // init members
+ m_aData.m_aKeyType = aKeyType;
+ m_aData.m_aValueType = aValueType;
+ m_aData.m_pKeyCompare = std::move(pComparator);
+ m_aData.m_pValues.emplace( *m_aData.m_pKeyCompare );
+ m_aData.m_bMutable = bMutable;
+
+ if ( aInitialValues.hasElements() )
+ impl_initValues_throw( aInitialValues );
+
+ setInitialized();
+ }
+
+
+ void EnumerableMap::impl_initValues_throw( const Sequence< Pair< Any, Any > >& _initialValues )
+ {
+ OSL_PRECOND( m_aData.m_pValues && m_aData.m_pValues->empty(), "EnumerableMap::impl_initValues_throw: illegal call!" );
+ if (!m_aData.m_pValues || !m_aData.m_pValues->empty())
+ throw RuntimeException();
+
+ const Pair< Any, Any >* mapping = _initialValues.getConstArray();
+ const Pair< Any, Any >* mappingEnd = mapping + _initialValues.getLength();
+ for ( ; mapping != mappingEnd; ++mapping )
+ {
+ impl_checkValue_throw( mapping->Second );
+ (*m_aData.m_pValues)[ mapping->First ] = mapping->Second;
+ }
+ }
+
+
+ void EnumerableMap::impl_checkValue_throw( const Any& _value ) const
+ {
+ if ( !_value.hasValue() )
+ // nothing to do, NULL values are always allowed, regardless of the ValueType
+ return;
+
+ TypeClass eAllowedTypeClass = m_aData.m_aValueType.getTypeClass();
+ bool bValid = false;
+
+ switch ( eAllowedTypeClass )
+ {
+ default:
+ bValid = ( _value.getValueTypeClass() == eAllowedTypeClass );
+ break;
+ case TypeClass_ANY:
+ bValid = true;
+ break;
+ case TypeClass_INTERFACE:
+ {
+ // special treatment: _value might contain the proper type, but the interface
+ // might actually be NULL. Which is still valid ...
+ if ( m_aData.m_aValueType.isAssignableFrom( _value.getValueType() ) )
+ // this also catches the special case where XFoo is our value type,
+ // and _value contains a NULL-reference to XFoo, or a derived type
+ bValid = true;
+ else
+ {
+ Reference< XInterface > xValue( _value, UNO_QUERY );
+ if ( xValue.is() )
+ // XInterface is not-NULL, but is X(ValueType) not-NULL, too?
+ xValue.set( xValue->queryInterface( m_aData.m_aValueType ), UNO_QUERY );
+ bValid = xValue.is();
+ }
+ }
+ break;
+ case TypeClass_EXCEPTION:
+ case TypeClass_STRUCT:
+ {
+ // values are accepted if and only if their type equals, or is derived from, our value type
+
+ if ( _value.getValueTypeClass() != eAllowedTypeClass )
+ bValid = false;
+ else
+ {
+ const TypeDescription aValueTypeDesc( _value.getValueType() );
+ const TypeDescription aRequiredTypeDesc( m_aData.m_aValueType );
+
+ const _typelib_CompoundTypeDescription* pValueCompoundTypeDesc =
+ reinterpret_cast< const _typelib_CompoundTypeDescription* >( aValueTypeDesc.get() );
+
+ while ( pValueCompoundTypeDesc )
+ {
+ if ( typelib_typedescription_equals( &pValueCompoundTypeDesc->aBase, aRequiredTypeDesc.get() ) )
+ break;
+ pValueCompoundTypeDesc = pValueCompoundTypeDesc->pBaseTypeDescription;
+ }
+ bValid = ( pValueCompoundTypeDesc != nullptr );
+ }
+ }
+ break;
+ }
+
+ if ( !bValid )
+ {
+ throw IllegalTypeException(
+ "Incompatible value type. Found '" + _value.getValueTypeName()
+ + "', where '" + m_aData.m_aValueType.getTypeName()
+ + "' (or compatible type) is expected.",
+ *const_cast< EnumerableMap* >( this ) );
+ }
+
+ impl_checkNaN_throw( _value, m_aData.m_aValueType );
+ }
+
+
+ void EnumerableMap::impl_checkNaN_throw( const Any& _keyOrValue, const Type& _keyOrValueType ) const
+ {
+ if ( ( _keyOrValueType.getTypeClass() == TypeClass_DOUBLE )
+ || ( _keyOrValueType.getTypeClass() == TypeClass_FLOAT )
+ )
+ {
+ double nValue(0);
+ if ( _keyOrValue >>= nValue )
+ if ( std::isnan( nValue ) )
+ throw IllegalArgumentException(
+ "NaN (not-a-number) not supported by this implementation.",
+ *const_cast< EnumerableMap* >( this ), 0 );
+ // (note that the case of _key not containing a float/double value is handled in the
+ // respective IKeyPredicateLess implementation, so there's no need to handle this here.)
+ }
+ }
+
+
+ void EnumerableMap::impl_checkKey_throw( const Any& _key ) const
+ {
+ if ( !_key.hasValue() )
+ throw IllegalArgumentException(
+ "NULL keys not supported by this implementation.",
+ *const_cast< EnumerableMap* >( this ), 0 );
+
+ impl_checkNaN_throw( _key, m_aData.m_aKeyType );
+ }
+
+
+ void EnumerableMap::impl_checkMutable_throw() const
+ {
+ if ( !m_aData.m_bMutable )
+ throw NoSupportException(
+ "The map is immutable.",
+ *const_cast< EnumerableMap* >( this ) );
+ }
+
+
+ Reference< XEnumeration > SAL_CALL EnumerableMap::createKeyEnumeration( sal_Bool Isolated )
+ {
+ ComponentMethodGuard aGuard( *this );
+ return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eKeys, Isolated );
+ }
+
+
+ Reference< XEnumeration > SAL_CALL EnumerableMap::createValueEnumeration( sal_Bool Isolated )
+ {
+ ComponentMethodGuard aGuard( *this );
+ return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eValues, Isolated );
+ }
+
+
+ Reference< XEnumeration > SAL_CALL EnumerableMap::createElementEnumeration( sal_Bool Isolated )
+ {
+ ComponentMethodGuard aGuard( *this );
+ return new MapEnumeration( *this, m_aData, getBroadcastHelper(), eBoth, Isolated );
+ }
+
+
+ Type SAL_CALL EnumerableMap::getKeyType()
+ {
+ ComponentMethodGuard aGuard( *this );
+ return m_aData.m_aKeyType;
+ }
+
+
+ Type SAL_CALL EnumerableMap::getValueType()
+ {
+ ComponentMethodGuard aGuard( *this );
+ return m_aData.m_aValueType;
+ }
+
+
+ void SAL_CALL EnumerableMap::clear( )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkMutable_throw();
+
+ m_aData.m_pValues->clear();
+
+ lcl_notifyMapDataListeners_nothrow( m_aData );
+ }
+
+
+ sal_Bool SAL_CALL EnumerableMap::containsKey( const Any& _key )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkKey_throw( _key );
+
+ KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
+ return ( pos != m_aData.m_pValues->end() );
+ }
+
+
+ sal_Bool SAL_CALL EnumerableMap::containsValue( const Any& _value )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkValue_throw( _value );
+ for (auto const& value : *m_aData.m_pValues)
+ {
+ if ( value.second == _value )
+ return true;
+ }
+ return false;
+ }
+
+
+ Any SAL_CALL EnumerableMap::get( const Any& _key )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkKey_throw( _key );
+
+ KeyedValues::const_iterator pos = m_aData.m_pValues->find( _key );
+ if ( pos == m_aData.m_pValues->end() )
+ throw NoSuchElementException( anyToString( _key ), *this );
+
+ return pos->second;
+ }
+
+
+ Any SAL_CALL EnumerableMap::put( const Any& _key, const Any& _value )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkMutable_throw();
+ impl_checkKey_throw( _key );
+ impl_checkValue_throw( _value );
+
+ Any previousValue;
+
+ KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
+ if ( pos != m_aData.m_pValues->end() )
+ {
+ previousValue = pos->second;
+ pos->second = _value;
+ }
+ else
+ {
+ (*m_aData.m_pValues)[ _key ] = _value;
+ }
+
+ lcl_notifyMapDataListeners_nothrow( m_aData );
+
+ return previousValue;
+ }
+
+
+ Any SAL_CALL EnumerableMap::remove( const Any& _key )
+ {
+ ComponentMethodGuard aGuard( *this );
+ impl_checkMutable_throw();
+ impl_checkKey_throw( _key );
+
+ Any previousValue;
+
+ KeyedValues::iterator pos = m_aData.m_pValues->find( _key );
+ if ( pos != m_aData.m_pValues->end() )
+ {
+ previousValue = pos->second;
+ m_aData.m_pValues->erase( pos );
+ }
+
+ lcl_notifyMapDataListeners_nothrow( m_aData );
+
+ return previousValue;
+ }
+
+
+ Type SAL_CALL EnumerableMap::getElementType()
+ {
+ return ::cppu::UnoType< Pair< Any, Any > >::get();
+ }
+
+
+ sal_Bool SAL_CALL EnumerableMap::hasElements()
+ {
+ ComponentMethodGuard aGuard( *this );
+ return m_aData.m_pValues->empty();
+ }
+
+
+ OUString SAL_CALL EnumerableMap::getImplementationName( )
+ {
+ return "org.openoffice.comp.comphelper.EnumerableMap";
+ }
+
+ sal_Bool SAL_CALL EnumerableMap::supportsService( const OUString& _serviceName )
+ {
+ return cppu::supportsService(this, _serviceName);
+ }
+
+
+ Sequence< OUString > SAL_CALL EnumerableMap::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.container.EnumerableMap" };
+ }
+
+ bool MapEnumerator::hasMoreElements()
+ {
+ if ( m_disposed )
+ throw DisposedException( OUString(), m_rParent );
+ return m_mapPos != m_rMapData.m_pValues->end();
+ }
+
+
+ Any MapEnumerator::nextElement()
+ {
+ if ( m_disposed )
+ throw DisposedException( OUString(), m_rParent );
+ if ( m_mapPos == m_rMapData.m_pValues->end() )
+ throw NoSuchElementException("No more elements.", m_rParent );
+
+ Any aNextElement;
+ switch ( m_eType )
+ {
+ case eKeys: aNextElement = m_mapPos->first; break;
+ case eValues: aNextElement = m_mapPos->second; break;
+ case eBoth: aNextElement <<= Pair< Any, Any >( m_mapPos->first, m_mapPos->second ); break;
+ }
+ ++m_mapPos;
+ return aNextElement;
+ }
+
+
+ void MapEnumerator::mapModified()
+ {
+ m_disposed = true;
+ }
+
+
+ sal_Bool SAL_CALL MapEnumeration::hasMoreElements( )
+ {
+ ComponentMethodGuard aGuard( *this );
+ return m_aEnumerator.hasMoreElements();
+ }
+
+
+ Any SAL_CALL MapEnumeration::nextElement( )
+ {
+ ComponentMethodGuard aGuard( *this );
+ return m_aEnumerator.nextElement();
+ }
+
+
+} // namespace comphelper
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_comphelper_EnumerableMap(
+ css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new comphelper::EnumerableMap());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */