LibreOffice Module comphelper (master)  1
interfacecontainer2.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
22 
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
25 
26 #include <memory>
27 
28 #include <com/sun/star/lang/XEventListener.hpp>
29 
30 
31 using namespace osl;
32 using namespace com::sun::star::uno;
33 using namespace com::sun::star::lang;
34 
35 namespace comphelper
36 {
37 
38 OInterfaceIteratorHelper2::OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont_ )
39  : rCont( rCont_ ),
40  bIsList( rCont_.bIsList )
41 {
42  MutexGuard aGuard( rCont.rMutex );
43  if( rCont.bInUse )
44  // worst case, two iterators at the same time
46  aData = rCont_.aData;
47  if( bIsList )
48  {
49  rCont.bInUse = true;
50  nRemain = aData.pAsVector->size();
51  }
52  else if( aData.pAsInterface )
53  {
54  aData.pAsInterface->acquire();
55  nRemain = 1;
56  }
57  else
58  nRemain = 0;
59 }
60 
62 {
63  bool bShared;
64  {
65  MutexGuard aGuard( rCont.rMutex );
66  // bResetInUse protect the iterator against recursion
68  if( bShared )
69  {
70  OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper2 must be in use" );
71  rCont.bInUse = false;
72  }
73  }
74 
75  if( !bShared )
76  {
77  if( bIsList )
78  // Sequence owned by the iterator
79  delete aData.pAsVector;
80  else if( aData.pAsInterface )
81  // Interface is acquired by the iterator
82  aData.pAsInterface->release();
83  }
84 }
85 
87 {
88  if( nRemain )
89  {
90  nRemain--;
91  if( bIsList )
92  return (*aData.pAsVector)[nRemain].get();
93  else if( aData.pAsInterface )
94  return aData.pAsInterface;
95  }
96  // exception
97  return nullptr;
98 }
99 
101 {
102  if( bIsList )
103  {
104  OSL_ASSERT( nRemain >= 0 &&
105  nRemain < static_cast<sal_Int32>(aData.pAsVector->size()) );
107  }
108  else
109  {
110  OSL_ASSERT( 0 == nRemain );
112  }
113 }
114 
116  : rMutex( rMutex_ )
117  , bInUse( false )
118  , bIsList( false )
119 {
120 }
121 
123 {
124  OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper2 but is in use" );
125  if( bIsList )
126  delete aData.pAsVector;
127  else if( aData.pAsInterface )
128  aData.pAsInterface->release();
129 }
130 
132 {
133  MutexGuard aGuard( rMutex );
134  if( bIsList )
135  return aData.pAsVector->size();
136  else if( aData.pAsInterface )
137  return 1;
138  return 0;
139 }
140 
141 std::vector< Reference<XInterface> > OInterfaceContainerHelper2::getElements() const
142 {
143  std::vector< Reference<XInterface> > rVec;
144  MutexGuard aGuard( rMutex );
145  if( bIsList )
146  rVec = *aData.pAsVector;
147  else if( aData.pAsInterface )
148  {
149  rVec.emplace_back( aData.pAsInterface );
150  }
151  return rVec;
152 }
153 
155 {
156  OSL_ENSURE( bInUse, "OInterfaceContainerHelper2 not in use" );
157  if( bInUse )
158  {
159  // this should be the worst case. If an iterator is active
160  // and a new Listener is added.
161  if( bIsList )
162  aData.pAsVector = new std::vector< Reference< XInterface > >( *aData.pAsVector );
163  else if( aData.pAsInterface )
164  aData.pAsInterface->acquire();
165 
166  bInUse = false;
167  }
168 }
169 
171 {
172  OSL_ASSERT( rListener.is() );
173  MutexGuard aGuard( rMutex );
174  if( bInUse )
176 
177  if( bIsList )
178  {
179  aData.pAsVector->push_back( rListener );
180  return aData.pAsVector->size();
181  }
182  else if( aData.pAsInterface )
183  {
184  std::vector< Reference< XInterface > > * pVec = new std::vector< Reference< XInterface > >( 2 );
185  (*pVec)[0] = aData.pAsInterface;
186  (*pVec)[1] = rListener;
187  aData.pAsInterface->release();
188  aData.pAsVector = pVec;
189  bIsList = true;
190  return 2;
191  }
192  else
193  {
194  aData.pAsInterface = rListener.get();
195  if( rListener.is() )
196  rListener->acquire();
197  return 1;
198  }
199 }
200 
202 {
203  OSL_ASSERT( rListener.is() );
204  MutexGuard aGuard( rMutex );
205  if( bInUse )
207 
208  if( bIsList )
209  {
210  // It is not valid to compare the pointer directly, but it's faster.
211  auto it = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(),
212  [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
213  return rItem.get() == rListener.get(); });
214 
215  // interface not found, use the correct compare method
216  if (it == aData.pAsVector->end())
217  it = std::find(aData.pAsVector->begin(), aData.pAsVector->end(), rListener);
218 
219  if (it != aData.pAsVector->end())
220  aData.pAsVector->erase(it);
221 
222  if( aData.pAsVector->size() == 1 )
223  {
224  XInterface * p = (*aData.pAsVector)[0].get();
225  p->acquire();
226  delete aData.pAsVector;
227  aData.pAsInterface = p;
228  bIsList = false;
229  return 1;
230  }
231  else
232  return aData.pAsVector->size();
233  }
234  else if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener )
235  {
236  aData.pAsInterface->release();
237  aData.pAsInterface = nullptr;
238  }
239  return aData.pAsInterface ? 1 : 0;
240 }
241 
242 void OInterfaceContainerHelper2::disposeAndClear( const EventObject & rEvt )
243 {
244  ClearableMutexGuard aGuard( rMutex );
245  OInterfaceIteratorHelper2 aIt( *this );
246  // Release container, in case new entries come while disposing
247  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
248  if( !bIsList && aData.pAsInterface )
249  aData.pAsInterface->release();
250  // set the member to null, use the iterator to delete the values
251  aData.pAsInterface = nullptr;
252  bIsList = false;
253  bInUse = false;
254  aGuard.clear();
255  while( aIt.hasMoreElements() )
256  {
257  try
258  {
259  Reference<XEventListener > xLst( aIt.next(), UNO_QUERY );
260  if( xLst.is() )
261  xLst->disposing( rEvt );
262  }
263  catch ( RuntimeException & )
264  {
265  // be robust, if e.g. a remote bridge has disposed already.
266  // there is no way to delegate the error to the caller :o(.
267  }
268  }
269 }
270 
271 
273 {
274  MutexGuard aGuard( rMutex );
275  // Release container, in case new entries come while disposing
276  OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper2 not in use" );
277  if (bInUse)
279  if (bIsList)
280  delete aData.pAsVector;
281  else if (aData.pAsInterface)
282  aData.pAsInterface->release();
283  aData.pAsInterface = nullptr;
284  bIsList = false;
285 }
286 
287 
288 }
289 
290 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
sal_Int32 addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Inserts an element into the container.
void disposeAndClear(const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
sal_Int32 removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
Removes an element from the container.
~OInterfaceIteratorHelper2()
Releases the connection to the container.
~OInterfaceContainerHelper2()
Release all interfaces.
bool bInUse
TRUE -> used by an iterator.
OInterfaceContainerHelper2(::osl::Mutex &rMutex)
Create an interface container.
std::vector< css::uno::Reference< css::uno::XInterface > > * pAsVector
void clear()
Clears the container without calling disposing().
std::vector< css::uno::Reference< css::uno::XInterface > > getElements() const
Return all interfaces added to this container.
detail::element_alias2 aData
bIsList == TRUE -> aData.pAsVector of type vector< XInterfaceSequence >, otherwise aData...
This is the iterator of an InterfaceContainerHelper.
void * p
bool bIsList
TRUE -> aData.pAsVector is of type Sequence< XInterfaceSequence >.
sal_Int32 getLength() const
Return the number of Elements in the container.
css::uno::XInterface * next()
Return the next element of the iterator.
void remove()
Removes the current element (the last one returned by next()) from the underlying container...