LibreOffice Module comphelper (master)  1
compbase.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 
10 #include <comphelper/compbase.hxx>
11 #include <sal/log.hxx>
12 #include <osl/diagnose.h>
13 
14 namespace comphelper
15 {
17 
18 // css::lang::XComponent
20 {
21  std::unique_lock aGuard(m_aMutex);
22  if (m_bDisposed)
23  return;
24  m_bDisposed = true;
25  disposing(aGuard);
26  if (!aGuard.owns_lock())
27  aGuard.lock();
28  css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
29  maEventListeners.disposeAndClear(aGuard, aEvt);
30 }
31 
32 void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {}
33 
35  css::uno::Reference<css::lang::XEventListener> const& rxListener)
36 {
37  std::unique_lock aGuard(m_aMutex);
38  if (m_bDisposed)
39  return;
40  maEventListeners.addInterface(aGuard, rxListener);
41 }
42 
44  css::uno::Reference<css::lang::XEventListener> const& rxListener)
45 {
46  std::unique_lock aGuard(m_aMutex);
47  maEventListeners.removeInterface(aGuard, rxListener);
48 }
49 
50 css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
51 {
52  css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
53  static_cast<css::lang::XComponent*>(this));
54  if (aReturn.hasValue())
55  return aReturn;
56  return OWeakObject::queryInterface(rType);
57 }
58 
59 static void checkInterface(css::uno::Type const& rType)
60 {
61  if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
62  {
63  OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
64  SAL_WARN("cppuhelper", msg);
65  throw css::uno::RuntimeException(msg);
66  }
67 }
68 
69 static bool isXInterface(rtl_uString* pStr)
70 {
71  return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
72 }
73 
74 static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
75  typelib_TypeDescriptionReference const* pTDR2)
76 {
77  return ((pTDR1 == pTDR2)
78  || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
79 }
80 
81 static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
82 {
83  cppu::type_entry* pEntries = cd->m_typeEntries;
84  if (!cd->m_storedTypeRefs) // not inited?
85  {
86  static std::mutex aMutex;
87  std::scoped_lock guard(aMutex);
88  if (!cd->m_storedTypeRefs) // not inited?
89  {
90  // get all types
91  for (sal_Int32 n = cd->m_nTypes; n--;)
92  {
93  cppu::type_entry* pEntry = &pEntries[n];
94  css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
95  OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
96  "### wrong helper init: expected interface!");
97  OSL_ENSURE(
98  !isXInterface(rType.getTypeLibType()->pTypeName),
99  "### want to implement XInterface: template argument is XInterface?!?!?!");
100  if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
101  {
102  OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
103  SAL_WARN("cppuhelper", msg);
104  throw css::uno::RuntimeException(msg);
105  }
106  // ref is statically held by getCppuType()
107  pEntry->m_type.typeRef = rType.getTypeLibType();
108  }
109  OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
110  cd->m_storedTypeRefs = true;
111  }
112  }
113  else
114  {
115  OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
116  }
117  return pEntries;
118 }
119 
120 static void* makeInterface(sal_IntPtr nOffset, void* that)
121 {
122  return (static_cast<char*>(that) + nOffset);
123 }
124 
125 static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
126  typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
127 {
128  // This code assumes that the vtables of a multiple-inheritance class (the
129  // offset amount by which to adjust the this pointer) follow one another in
130  // the object layout, and that they contain slots for the inherited classes
131  // in a specific order. In theory, that need not hold for any given
132  // platform; in practice, it seems to work well on all supported platforms:
133 next:
134  for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
135  {
136  if (i > 0)
137  {
138  *offset += sizeof(void*);
139  }
140  typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
141  // ignore XInterface:
142  if (base->nBaseTypes > 0)
143  {
144  if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
145  demandedType))
146  {
147  return true;
148  }
149  // Profiling showed that it is important to speed up the common case
150  // of only one base:
151  if (type->nBaseTypes == 1)
152  {
153  type = base;
154  goto next;
155  }
156  if (recursivelyFindType(demandedType, base, offset))
157  {
158  return true;
159  }
160  }
161  }
162  return false;
163 }
164 
165 static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
166  cppu::class_data* cd, void* that)
167 {
168  cppu::type_entry* pEntries = getTypeEntries(cd);
169  sal_Int32 nTypes = cd->m_nTypes;
170  sal_Int32 n;
171 
172  // try top interfaces without getting td
173  for (n = 0; n < nTypes; ++n)
174  {
175  if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
176  {
177  return makeInterface(pEntries[n].m_offset, that);
178  }
179  }
180  // query deep getting td
181  for (n = 0; n < nTypes; ++n)
182  {
183  typelib_TypeDescription* pTD = nullptr;
184  TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
185  if (pTD)
186  {
187  // exclude top (already tested) and bottom (XInterface) interface
188  OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
189  "### want to implement XInterface:"
190  " template argument is XInterface?!?!?!");
191  sal_IntPtr offset = pEntries[n].m_offset;
192  bool found = recursivelyFindType(
193  pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
194  TYPELIB_DANGER_RELEASE(pTD);
195  if (found)
196  {
197  return makeInterface(offset, that);
198  }
199  }
200  else
201  {
202  OUString msg("cannot get type description for type \""
203  + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
204  SAL_WARN("cppuhelper", msg);
205  throw css::uno::RuntimeException(msg);
206  }
207  }
208  return nullptr;
209 }
210 
211 css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
213 {
214  checkInterface(rType);
215  typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
216 
217  // shortcut XInterface to WeakComponentImplHelperBase
218  if (!isXInterface(pTDR->pTypeName))
219  {
220  void* p = queryDeepNoXInterface(pTDR, cd, pBase);
221  if (p)
222  {
223  return css::uno::Any(&p, pTDR);
224  }
225  }
226  return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
227 }
228 
229 } // namespace comphelper
230 
231 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
void disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
Call disposing on all object in the container that support XEventListener.
Serves two purposes (1) extracts code that doesn't need to be templated (2) helps to handle the custo...
Definition: compbase.hxx:31
static bool recursivelyFindType(typelib_TypeDescriptionReference const *demandedType, typelib_InterfaceTypeDescription const *type, sal_IntPtr *offset)
Definition: compbase.cxx:125
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const &rType) override
Definition: compbase.cxx:50
sal_Int64 n
virtual void SAL_CALL removeEventListener(css::uno::Reference< css::lang::XEventListener > const &rxListener) override
Definition: compbase.cxx:43
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Inserts an element into the container.
static cppu::type_entry * getTypeEntries(cppu::class_data *cd)
Definition: compbase.cxx:81
static void checkInterface(css::uno::Type const &rType)
Definition: compbase.cxx:59
virtual ~WeakComponentImplHelperBase() override
Definition: compbase.cxx:16
Mutex aMutex
virtual void SAL_CALL addEventListener(css::uno::Reference< css::lang::XEventListener > const &rxListener) override
Definition: compbase.cxx:34
virtual void disposing(std::unique_lock< std::mutex > &)
Called by dispose for subclasses to do dispose() work.
Definition: compbase.cxx:32
virtual void SAL_CALL dispose() override
Definition: compbase.cxx:19
int i
void const * base
struct _typelib_TypeDescription typelib_TypeDescription
std::mutex mutex
Definition: random.cxx:41
static bool isXInterface(rtl_uString *pStr)
Definition: compbase.cxx:69
void * p
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
Removes an element from the container.
static bool td_equals(typelib_TypeDescriptionReference const *pTDR1, typelib_TypeDescriptionReference const *pTDR2)
Definition: compbase.cxx:74
static void * queryDeepNoXInterface(typelib_TypeDescriptionReference const *pDemandedTDR, cppu::class_data *cd, void *that)
Definition: compbase.cxx:165
#define SAL_WARN(area, stream)
static void * makeInterface(sal_IntPtr nOffset, void *that)
Definition: compbase.cxx:120
comphelper::OInterfaceContainerHelper4< css::lang::XEventListener > maEventListeners
Definition: compbase.hxx:53
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const &rType, cppu::class_data *cd, WeakComponentImplHelperBase *pBase)
WeakComponentImplHelper.
Definition: compbase.cxx:211
const Type m_type