Update git submodules
[LibreOffice.git] / include / osl / diagnose.hxx
blob71d49f3d8a985555b727f756f198160cb270b2c5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_OSL_DIAGNOSE_HXX
20 #define INCLUDED_OSL_DIAGNOSE_HXX
22 /// @cond INTERNAL
24 #include "sal/config.h"
26 #include <cstddef>
27 #include <typeinfo>
28 #include <unordered_set>
30 #include "osl/diagnose.h"
31 #include "osl/interlck.h"
32 #include "osl/mutex.hxx"
33 #include "rtl/instance.hxx"
34 #include "sal/log.hxx"
35 #include "sal/saldllapi.h"
36 #include "sal/types.h"
38 namespace osl {
39 namespace detail {
41 struct ObjectRegistryData;
43 } // namespace detail
44 } // namespace osl
46 extern "C" {
48 SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses(
49 char const* pName )
50 SAL_THROW_EXTERN_C();
52 SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
53 ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
54 SAL_THROW_EXTERN_C();
56 SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_registerObject(
57 ::osl::detail::ObjectRegistryData & rData, void const* pObj )
58 SAL_THROW_EXTERN_C();
60 SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
61 ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62 SAL_THROW_EXTERN_C();
64 // These functions presumably should not be extern "C", but changing
65 // that would break binary compatibility.
66 #ifdef __clang__
67 #pragma clang diagnostic push
68 #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
69 #endif
71 SAL_DLLPUBLIC ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
72 SAL_THROW_EXTERN_C();
74 #ifdef __clang__
75 #pragma clang diagnostic pop
76 #endif
78 } // extern "C"
80 namespace osl {
82 namespace detail {
84 struct VoidPtrHash {
85 ::std::size_t operator()( void const* p ) const {
86 ::std::size_t const d = static_cast< ::std::size_t >(
87 reinterpret_cast< ::std::ptrdiff_t >(p) );
88 return d + (d >> 3);
92 typedef ::std::unordered_set<void const*, VoidPtrHash > VoidPointerSet;
94 struct ObjectRegistryData {
95 ObjectRegistryData( ::std::type_info const& rTypeInfo )
96 : m_pName(rTypeInfo.name()), m_nCount(0),
97 m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)) {}
99 char const* const m_pName;
100 oslInterlockedCount m_nCount;
101 VoidPointerSet m_addresses;
102 bool const m_bStoreAddresses;
105 template <typename T>
106 class ObjectRegistry
108 public:
109 ObjectRegistry() : m_data( typeid(T) ) {}
110 ~ObjectRegistry() { checkObjectCount(0); }
112 bool checkObjectCount( ::std::size_t nExpected ) const {
113 bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
114 m_data, nExpected );
115 if (!bRet && m_data.m_bStoreAddresses) {
116 MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() );
117 // following loop is for debugging purposes, iterating over map:
118 VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
119 VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
120 for ( ; iPos != iEnd; ++iPos ) {
121 SAL_WARN_IF( *iPos == NULL, "sal.debug", "null pointer" );
124 return bRet;
127 void registerObject( void const* pObj ) {
128 osl_detail_ObjectRegistry_registerObject(m_data, pObj);
131 void revokeObject( void const* pObj ) {
132 osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
135 private:
136 ObjectRegistry( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
137 ObjectRegistry const& operator=( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
139 ObjectRegistryData m_data;
142 } // namespace detail
144 /** Helper class which indicates leaking object(s) of a particular class in
145 non-pro builds; use e.g.
147 @code{.cpp}
148 class MyClass : private osl::DebugBase<MyClass> {...};
149 @endcode
151 Using the environment variable
153 OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
155 you can specify a ';'-separated list of strings matching to class names
156 (or "all" for all classes), for which DebugBase stores addresses to created
157 objects instead of just counting them. This enables you to iterate over
158 leaking objects in your debugger.
160 @tparam InheritingClassT binds the template instance to that class
161 @attention Use at own risk.
162 For now this is just public (yet unpublished) API and may change
163 in the future!
165 template <typename InheritingClassT>
166 class DebugBase
168 public:
169 #if OSL_DEBUG_LEVEL <= 0
170 static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
171 #else // OSL_DEBUG_LEVEL > 0
172 /** @return whether the expected number of objects is alive,
173 else this function SAL_WARNs
175 static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
176 return StaticObjectRegistry::get().checkObjectCount(nExpected);
179 protected:
180 DebugBase() {
181 StaticObjectRegistry::get().registerObject( this );
183 ~DebugBase() {
184 StaticObjectRegistry::get().revokeObject( this );
187 private:
188 struct StaticObjectRegistry
189 : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
190 StaticObjectRegistry> {};
191 #endif
194 } // namespace osl
196 /// @endcond
198 #endif // ! defined( INCLUDED_OSL_DIAGNOSE_HXX)
200 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */