File: referencecounting.h

package info (click to toggle)
kdevelop 4%3A5.6.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 57,892 kB
  • sloc: cpp: 278,773; javascript: 3,558; python: 3,385; sh: 1,317; ansic: 689; xml: 273; php: 95; makefile: 40; lisp: 13; sed: 12
file content (132 lines) | stat: -rw-r--r-- 4,807 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * This file is part of KDevelop
 *
 * Copyright 2009 David Nolden <david.nolden.kdevelop@art-master.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
#ifndef KDEVPLATFORM_REFERENCECOUNTING_H
#define KDEVPLATFORM_REFERENCECOUNTING_H

#include "serializationexport.h"

#include <QMap>
#include <QPair>
#include <QMutexLocker>

//When this is enabled, the duchain unloading is disabled as well, and you should start
//with a cleared ~/.kdevduchain
// #define TEST_REFERENCE_COUNTING

namespace KDevelop {
template <typename T>
const T* make_const(const T* argument)
{
    return argument;
}

///Since shouldDoDUChainReferenceCounting is called extremely often, we export some internals into the header here,
///so the reference-counting code can be inlined.

KDEVPLATFORMSERIALIZATION_EXPORT extern bool doReferenceCounting;
KDEVPLATFORMSERIALIZATION_EXPORT extern QMutex refCountingLock;
KDEVPLATFORMSERIALIZATION_EXPORT extern QMap<void*, QPair<uint, uint>>* refCountingRanges;
KDEVPLATFORMSERIALIZATION_EXPORT extern bool refCountingHasAdditionalRanges;
KDEVPLATFORMSERIALIZATION_EXPORT extern void* refCountingFirstRangeStart;
KDEVPLATFORMSERIALIZATION_EXPORT extern QPair<uint, uint> refCountingFirstRangeExtent;

KDEVPLATFORMSERIALIZATION_EXPORT void initReferenceCounting();

///@internal The spin-lock ,must already be locked
inline bool shouldDoDUChainReferenceCountingInternal(void* item)
{
    auto it = make_const(refCountingRanges)->upperBound(item);
    if (it != refCountingRanges->constBegin()) {
        --it;
        return reinterpret_cast<char*>(it.key()) <= reinterpret_cast<char*>(item) &&
               reinterpret_cast<char*>(item) < reinterpret_cast<char*>(it.key()) + it.value().first;
    }

    return false;
}

///This is used by indexed items to decide whether they should do reference-counting
inline bool shouldDoDUChainReferenceCounting(void* item)
{
    if (!doReferenceCounting) //Fast path, no place has been marked for reference counting, 99% of cases
        return false;

    QMutexLocker lock(&refCountingLock);

    if (refCountingFirstRangeStart &&
        (reinterpret_cast<char*>(refCountingFirstRangeStart) <= reinterpret_cast<char*>(item)) &&
        (reinterpret_cast<char*>(item) < reinterpret_cast<char*>(refCountingFirstRangeStart) + refCountingFirstRangeExtent.first))
        return true;

    if (refCountingHasAdditionalRanges)
        return shouldDoDUChainReferenceCountingInternal(item);
    else
        return false;
}

///Enable reference-counting for the given range
///You should only enable the reference-counting for the time it's really needed,
///and it always has to be enabled too when the items are deleted again, else
///it will lead to inconsistencies in the repository.
///@warning If you are not working on the duchain internal storage mechanism, you should
///not care about this stuff at all.
///@param start Position where to start the reference-counting
///@param size Size of the area in bytes
KDEVPLATFORMSERIALIZATION_EXPORT void enableDUChainReferenceCounting(void* start, unsigned int size);
///Must be called as often as enableDUChainReferenceCounting, with the same ranges
///Must never be called for the same range twice, and not for overlapping ranges
///@param start Position where the reference-counting was started
KDEVPLATFORMSERIALIZATION_EXPORT void disableDUChainReferenceCounting(void* start);

///Use this as local variable within the object that maintains the reference-count,
///and use
struct ReferenceCountManager
{
    #ifndef TEST_REFERENCE_COUNTING
    inline void increase(uint& ref, uint /*targetId*/)
    {
        ++ref;
    }
    inline void decrease(uint& ref, uint /*targetId*/)
    {
        Q_ASSERT(ref);
        --ref;
    }

    #else

    ReferenceCountManager();
    ~ReferenceCountManager();

    ReferenceCountManager(const ReferenceCountManager& rhs);
    ReferenceCountManager& operator=(const ReferenceCountManager& rhs);

    void increase(uint& ref, uint targetId);
    void decrease(uint& ref, uint targetId);

//     bool hasReferenceCount() const;

    uint m_id;
    #endif
};
}

#endif