Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/comphelper/source/container/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 23 kB image not shown  

Quelle  enumerablemap.cxx   Sprache: C

 
/* -*- 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&&nbsp;_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&&nbsp;_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(u"wrong number of args"_ustr, static_cast<cppu::OWeakObject*>(this), 1);

        Type aKeyType, aValueType;
        if ( !( _arguments[0] >>= aKeyType ) )
            throw IllegalArgumentException(u"com.sun.star.uno.Type expected."_ustr, *this, 1 );
        if ( !( _arguments[1] >>= aValueType ) )
            throw IllegalArgumentException(u"com.sun.star.uno.Type expected."_ustr, *this, 2 );

        Sequence< Pair< Any, Any > > aInitialValues;
        bool bMutable = true;
        if ( nArgumentCount == 3 )
        {
            if ( !( _arguments[2] >>= aInitialValues ) )
                throw IllegalArgumentException(u"[]com.sun.star.beans.Pair expected."_ustr, *this2 );
            bMutable = false;
        }

        // for the value, anything is allowed, except VOID
        if ( ( aValueType.getTypeClass() == TypeClass_VOID ) || ( aValueType.getTypeClass() == TypeClass_UNKNOWN ) )
            throw IllegalTypeException(u"Unsupported value type."_ustr, *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(u"Unsupported key type."_ustr, *this );

        // init members
        m_aData.m_aKeyType = std::move(aKeyType);
        m_aData.m_aValueType = std::move(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("EnumerableMap m_aData container is invalid or not empty.", *this);
        }
        for (auto& mapping : _initialValues)
        {
            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_castconst _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(
                        u"NaN (not-a-number) not supported by this implementation."_ustr,
                        *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(
                u"NULL keys not supported by this implementation."_ustr,
                *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(
                    u"The map is immutable."_ustr,
                    *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 u"org.openoffice.comp.comphelper.EnumerableMap"_ustr;
    }

    sal_Bool SAL_CALL EnumerableMap::supportsService( const OUString& _serviceName )
    {
        return cppu::supportsService(this, _serviceName);
    }


    Sequence< OUString > SAL_CALL EnumerableMap::getSupportedServiceNames(  )
    {
        return { u"com.sun.star.container.EnumerableMap"_ustr };
    }

    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(u"No more elements."_ustr, 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: */

Messung V0.5
C=91 H=92 G=91

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.