1 /*
2     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de>
3 
4     SPDX-License-Identifier: LGPL-2.0-only
5 */
6 
7 #ifndef KDEVPLATFORM_INDEXEDDECLARATION_H
8 #define KDEVPLATFORM_INDEXEDDECLARATION_H
9 
10 #include <language/languageexport.h>
11 
12 #include "indexedtopducontext.h"
13 #include <language/util/kdevhash.h>
14 
15 namespace KDevelop {
16 class Declaration;
17 
18 /**
19  * Represents a declaration only by its global indices
20  */
21 class KDEVPLATFORMLANGUAGE_EXPORT IndexedDeclaration
22 {
23 public:
24     IndexedDeclaration(const Declaration* decl = nullptr);
25     IndexedDeclaration(uint topContext, uint declarationIndex);
26 
27     /**
28      * \warning Duchain must be read locked
29      */
30     Declaration* declaration() const;
31 
32     /**
33      * \warning Duchain must be read locked
34      */
data()35     Declaration* data() const
36     {
37         return declaration();
38     }
39 
40     inline bool operator==(const IndexedDeclaration& rhs) const
41     {
42         return m_topContext == rhs.m_topContext && m_declarationIndex == rhs.m_declarationIndex;
43     }
44 
hash()45     inline uint hash() const
46     {
47         if (isDummy())
48             return 0;
49         return KDevHash() << m_topContext << m_declarationIndex;
50     }
51 
52     ///@warning The duchain needs to be locked when this is called
isValid()53     inline bool isValid() const
54     {
55         return !isDummy() && declaration() != nullptr;
56     }
57 
58     inline bool operator<(const IndexedDeclaration& rhs) const
59     {
60         Q_ASSERT(!isDummy());
61         return m_topContext < rhs.m_topContext ||
62                (m_topContext == rhs.m_topContext && m_declarationIndex < rhs.m_declarationIndex);
63     }
64 
65     /**
66      * \return Index of the Declaration within the top context
67      */
localIndex()68     inline uint localIndex() const
69     {
70         if (isDummy())
71             return 0;
72         else
73             return m_declarationIndex;
74     }
75 
topContextIndex()76     inline uint topContextIndex() const
77     {
78         if (isDummy())
79             return 0;
80         else
81             return m_topContext;
82     }
83 
indexedTopContext()84     inline IndexedTopDUContext indexedTopContext() const
85     {
86         if (isDummy())
87             return IndexedTopDUContext();
88         else
89             return IndexedTopDUContext(m_topContext);
90     }
91 
92     /**
93      * The following functions allow storing 2 integers in this object and marking it as a dummy,
94      * which makes the isValid() function always return false for this object, and use the integers
95      * for other purposes.
96      *
97      * Clears the contained data
98      */
setIsDummy(bool dummy)99     void setIsDummy(bool dummy)
100     {
101         if (isDummy() == dummy)
102             return;
103         if (dummy)
104             m_topContext = 1u << 31u;
105         else
106             m_topContext = 0;
107         m_declarationIndex = 0;
108     }
109 
isDummy()110     inline bool isDummy() const
111     {
112         //We use the second highest bit to mark dummies, because the highest is used for the sign bit of stored
113         //integers
114         return ( bool )(m_topContext & static_cast<uint>(1u << 31u));
115     }
116 
dummyData()117     inline QPair<uint, uint> dummyData() const
118     {
119         Q_ASSERT(isDummy());
120         return qMakePair(m_topContext & (~(1u << 31u)), m_declarationIndex);
121     }
122 
123     /**
124      * \warning Do not call this when this object is valid.
125      *
126      * The first integer loses one bit of precision.
127      */
setDummyData(QPair<uint,uint> data)128     void setDummyData(QPair<uint, uint> data)
129     {
130         Q_ASSERT(isDummy());
131 
132         m_topContext = data.first;
133         m_declarationIndex = data.second;
134         Q_ASSERT(!isDummy());
135         m_topContext |= (1u << 31u); //Mark as dummy
136         Q_ASSERT(isDummy());
137         Q_ASSERT(dummyData() == data);
138     }
139 
140 private:
141     uint m_topContext;
142     uint m_declarationIndex;
143 };
144 
qHash(const IndexedDeclaration & decl)145 inline uint qHash(const IndexedDeclaration& decl)
146 {
147     return decl.hash();
148 }
149 }
150 
151 Q_DECLARE_METATYPE(KDevelop::IndexedDeclaration)
152 Q_DECLARE_TYPEINFO(KDevelop::IndexedDeclaration, Q_MOVABLE_TYPE);
153 
154 #endif // KDEVPLATFORM_INDEXEDDECLARATION_H
155