From 752cd07d085ac0aadc99bd512d49072843139032 Mon Sep 17 00:00:00 2001 From: Noel Grandin Date: Tue, 19 Jan 2016 19:45:45 +0200 Subject: InterfaceContainer2 with vector instead of Sequence create an InterfaceContainer2 class to replace InterfaceContainer. It uses a std::vector instead of a Sequence for the mutable listener list, which provides far better performance. Switch all our internal use-sites to the new class. Change-Id: I6b56cfa511ded2395faa22e68fab3b2f16c3cb88 --- comphelper/qa/container/comphelper_ifcontainer.cxx | 212 +++++++++++++++++++++ comphelper/qa/container/testifcontainer.cxx | 145 ++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 comphelper/qa/container/comphelper_ifcontainer.cxx create mode 100644 comphelper/qa/container/testifcontainer.cxx (limited to 'comphelper/qa') diff --git a/comphelper/qa/container/comphelper_ifcontainer.cxx b/comphelper/qa/container/comphelper_ifcontainer.cxx new file mode 100644 index 000000000000..ba9af495eaf0 --- /dev/null +++ b/comphelper/qa/container/comphelper_ifcontainer.cxx @@ -0,0 +1,212 @@ +/* -*- 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +class ContainerListener; + +struct ContainerStats { + int m_nAlive; + int m_nDisposed; + ContainerStats() : m_nAlive(0), m_nDisposed(0) {} +}; + +class ContainerListener : public ::cppu::WeakImplHelper1< XEventListener > +{ + ContainerStats *m_pStats; +public: + explicit ContainerListener(ContainerStats *pStats) + : m_pStats(pStats) { m_pStats->m_nAlive++; } + virtual ~ContainerListener() { m_pStats->m_nAlive--; } + virtual void SAL_CALL disposing( const EventObject& ) + throw (RuntimeException, std::exception) override + { + m_pStats->m_nDisposed++; + } +}; + +namespace comphelper_ifcontainer +{ + static const int nTests = 10; + class IfTest : public CppUnit::TestFixture + { + osl::Mutex m_aGuard; + public: + void testCreateDispose() + { + ContainerStats aStats; + comphelper::OInterfaceContainerHelper2 *pContainer; + + pContainer = new comphelper::OInterfaceContainerHelper2(m_aGuard); + + CPPUNIT_ASSERT_MESSAGE("Empty container not empty", + pContainer->getLength() == 0); + + int i; + for (i = 0; i < nTests; i++) + { + Reference xRef = new ContainerListener(&aStats); + int nNewLen = pContainer->addInterface(xRef); + + CPPUNIT_ASSERT_MESSAGE("addition length mismatch", + nNewLen == i + 1); + CPPUNIT_ASSERT_MESSAGE("addition length mismatch", + pContainer->getLength() == i + 1); + } + CPPUNIT_ASSERT_MESSAGE("alive count mismatch", + aStats.m_nAlive == nTests); + + EventObject aObj; + pContainer->disposeAndClear(aObj); + + CPPUNIT_ASSERT_MESSAGE("dispose count mismatch", + aStats.m_nDisposed == nTests); + CPPUNIT_ASSERT_MESSAGE("leaked container left alive", + aStats.m_nAlive == 0); + + delete pContainer; + } + + void testEnumerate() + { + int i; + ContainerStats aStats; + comphelper::OInterfaceContainerHelper2 *pContainer; + pContainer = new comphelper::OInterfaceContainerHelper2(m_aGuard); + + std::vector< Reference< XEventListener > > aListeners; + for (i = 0; i < nTests; i++) + { + Reference xRef = new ContainerListener(&aStats); + pContainer->addInterface(xRef); + aListeners.push_back(xRef); + } + std::vector< Reference< XInterface > > aElements = pContainer->getElements(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("query contents", + (int)aElements.size(), nTests); + if ((int)aElements.size() == nTests) + { + for (i = 0; i < nTests; i++) + { + CPPUNIT_ASSERT_MESSAGE("mismatching elements", + aElements[i] == aListeners[i]); + } + } + pContainer->clear(); + + CPPUNIT_ASSERT_MESSAGE("non-empty container post clear", + pContainer->getLength() == 0); + delete pContainer; + } + + template < typename ContainerType, typename ContainedType > + void doContainerTest(const ContainedType *pTypes) + { + ContainerStats aStats; + ContainerType *pContainer; + pContainer = new ContainerType(m_aGuard); + + int i; + Reference xRefs[nTests * 2]; + + // add these interfaces + for (i = 0; i < nTests * 2; i++) + { + xRefs[i] = new ContainerListener(&aStats); + pContainer->addInterface(pTypes[i / 2], xRefs[i]); + } + + // check it is all there + for (i = 0; i < nTests; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 2); + CPPUNIT_ASSERT_MESSAGE("match", aSeq[0] == xRefs[i*2]); + CPPUNIT_ASSERT_MESSAGE("match", aSeq[1] == xRefs[i*2+1]); + } + + // remove every other interface + for (i = 0; i < nTests; i++) + pContainer->removeInterface(pTypes[i], xRefs[i*2+1]); + + // check it is half there + for (i = 0; i < nTests; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 1); + CPPUNIT_ASSERT_MESSAGE("match", aSeq[0] == xRefs[i*2]); + } + + // remove the 1st half of the rest + for (i = 0; i < nTests / 2; i++) + pContainer->removeInterface(pTypes[i], xRefs[i*2]); + + // check it is half there + for (i = 0; i < nTests / 2; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 0); + } + + delete pContainer; + } + + // Automatic registration code + CPPUNIT_TEST_SUITE(IfTest); + CPPUNIT_TEST(testCreateDispose); + CPPUNIT_TEST(testEnumerate); + CPPUNIT_TEST_SUITE_END(); + }; +} // namespace cppu_ifcontainer + +CPPUNIT_TEST_SUITE_REGISTRATION(comphelper_ifcontainer::IfTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/comphelper/qa/container/testifcontainer.cxx b/comphelper/qa/container/testifcontainer.cxx new file mode 100644 index 000000000000..7533695640d0 --- /dev/null +++ b/comphelper/qa/container/testifcontainer.cxx @@ -0,0 +1,145 @@ +/* -*- 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 + +#include +#include + +#include + +using namespace ::cppu; +using namespace ::osl; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + + +class TestListener : public WeakImplHelper1< XVetoableChangeListener > +{ +public: + // Methods + virtual void SAL_CALL disposing( const css::lang::EventObject& /*Source*/ ) throw(css::uno::RuntimeException) + { + + } + + virtual void SAL_CALL vetoableChange( const css::beans::PropertyChangeEvent& /*aEvent*/ ) + throw(css::beans::PropertyVetoException, css::uno::RuntimeException) + { + + } +}; + +void test_interfacecontainer() +{ + Mutex mutex; + + { + OInterfaceContainerHelper helper( mutex ); + + Reference< XVetoableChangeListener > r1 = new TestListener(); + Reference< XVetoableChangeListener > r2 = new TestListener(); + Reference< XVetoableChangeListener > r3 = new TestListener(); + + helper.addInterface( r1 ); + helper.addInterface( r2 ); + helper.addInterface( r3 ); + + helper.disposeAndClear( EventObject() ); + } + + { + OInterfaceContainerHelper helper( mutex ); + + Reference< XVetoableChangeListener > r1 = new TestListener(); + Reference< XVetoableChangeListener > r2 = new TestListener(); + Reference< XVetoableChangeListener > r3 = new TestListener(); + + helper.addInterface( r1 ); + helper.addInterface( r2 ); + helper.addInterface( r3 ); + + OInterfaceIteratorHelper iterator( helper ); + + while( iterator.hasMoreElements() ) + ((XVetoableChangeListener*)iterator.next())->vetoableChange( PropertyChangeEvent() ); + + helper.disposeAndClear( EventObject() ); + } + + { + OInterfaceContainerHelper helper( mutex ); + + Reference< XVetoableChangeListener > r1 = new TestListener(); + Reference< XVetoableChangeListener > r2 = new TestListener(); + Reference< XVetoableChangeListener > r3 = new TestListener(); + + helper.addInterface( r1 ); + helper.addInterface( r2 ); + helper.addInterface( r3 ); + + OInterfaceIteratorHelper iterator( helper ); + + ((XVetoableChangeListener*)iterator.next())->vetoableChange( PropertyChangeEvent() ); + iterator.remove(); + ((XVetoableChangeListener*)iterator.next())->vetoableChange( PropertyChangeEvent() ); + iterator.remove(); + ((XVetoableChangeListener*)iterator.next())->vetoableChange( PropertyChangeEvent() ); + iterator.remove(); + + OSL_ASSERT( helper.getLength() == 0 ); + helper.disposeAndClear( EventObject() ); + } + + { + OInterfaceContainerHelper helper( mutex ); + + Reference< XVetoableChangeListener > r1 = new TestListener(); + Reference< XVetoableChangeListener > r2 = new TestListener(); + Reference< XVetoableChangeListener > r3 = new TestListener(); + + helper.addInterface( r1 ); + helper.addInterface( r2 ); + helper.addInterface( r3 ); + + { + OInterfaceIteratorHelper iterator( helper ); + while( iterator.hasMoreElements() ) + { + Reference< XVetoableChangeListener > r = ((XVetoableChangeListener*)iterator.next()); + if( r == r1 ) + iterator.remove(); + } + } + OSL_ASSERT( helper.getLength() == 2 ); + { + OInterfaceIteratorHelper iterator( helper ); + while( iterator.hasMoreElements() ) + { + Reference< XVetoableChangeListener > r = ((XVetoableChangeListener*)iterator.next()); + OSL_ASSERT( r != r1 && ( r == r2 || r == r3 ) ); + } + } + + helper.disposeAndClear( EventObject() ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit