1 /*
2     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
3 
4     SPDX-License-Identifier: LGPL-2.0-only
5 */
6 
7 #ifndef KDEVPLATFORM_APPENDEDLIST_STATIC_H
8 #define KDEVPLATFORM_APPENDEDLIST_STATIC_H
9 
10 #include <util/kdevvarlengtharray.h>
11 #include <serialization/referencecounting.h>
12 
13 namespace KDevelop {
14 /**
15  * This file contains macros and classes that can be used to conveniently
16  * implement classes that store the data of an arbitrary count
17  * of additional lists within the same memory block directly behind the
18  * class data, in a way that one the whole data can be stored by one copy-operation
19  * to another place, like needed in ItemRepository. These macros simplify
20  * having two versions of a class: One that has its lists attached in memory,
21  * and one version that has them contained as a directly accessible
22  * KDevVarLengthArray. Both versions have their lists accessible through access-functions,
23  * have a completeSize() function that computes the size of the one-block
24  * version, and a copyListsFrom(..) function which can copy the lists from one
25  * version to the other. The class that contains these lists must have
26  * a boolean template parameter called "dynamic".
27  *
28  * See identifier.cpp for an example how to use these classes. @todo Document this a bit more
29  * */
30 
31 // Foreach macro that takes a container and a function-name, and will iterate through the vector returned by that function, using the length returned by the function-name with "Size" appended.
32 //This might be a little slow
33 #define FOREACH_FUNCTION_STATIC(item, container) \
34     for (uint a__ = 0, mustDo__ = 1; a__ < container ## Size(); ++a__) \
35         if ((mustDo__ == 0 || mustDo__ == 1) && (mustDo__ = 2)) \
36             for (item(container()[a__]); mustDo__; mustDo__ = 0)
37 
38 #define START_APPENDED_LISTS_STATIC(selftype) using SelfType = selftype;
39 
40 #define APPENDED_LIST_COMMON_STATIC(type, name) \
41     KDevelop::AppendedList<dynamic, type> name ## List; \
42     unsigned int name ## Size() const { return name ## List.size(); } \
43     template <class T> bool name ## Equals(const T &rhs) const { \
44         unsigned int size = name ## Size(); \
45         if (size != rhs.name ## Size()) \
46             return false; \
47         for (uint a = 0; a < size; ++a) {if (!(name()[a] == rhs.name()[a])) \
48                                              return false; } \
49         return true; \
50     }
51 
52 ///@todo Make these things a bit faster(less recursion)
53 
54 #define APPENDED_LIST_FIRST_STATIC(type, name) \
55     APPENDED_LIST_COMMON_STATIC(type, name) \
56     const type * name() const { return name ## List.data(reinterpret_cast<const char*>(this) + sizeof(SelfType)); } \
57     unsigned int name ## OffsetBehind() const { return name ## List.dynamicDataSize(); } \
58     template <class T> bool name ## ListChainEquals(const T &rhs) const { return name ## Equals(rhs); } \
59     template <class T> void name ## CopyAllFrom(const T &rhs) { name ## List.copy(const_cast<type*>(name()), \
60                                                                                   rhs.name(), rhs.name ## Size()); }
61 
62 #define APPENDED_LIST_STATIC(type, name, predecessor) \
63     APPENDED_LIST_COMMON_STATIC(type, name) \
64     const type * name() const { return name ## List.data( \
65                                     reinterpret_cast<const char*>(this) + sizeof(SelfType) + \
66                                     predecessor ## OffsetBehind()); } \
67     unsigned int name ## OffsetBehind() const { return name ## List.dynamicDataSize() + predecessor ## OffsetBehind(); } \
68     template <class T> bool name ## ListChainEquals(const T &rhs) const { return name ## Equals(rhs) && \
69                                                                                  predecessor ## ListChainEquals(rhs); } \
70     template <class T> void name ## CopyAllFrom(const T &rhs) { name ## List.copy(const_cast<type*>(name()), \
71                                                                                   rhs.name(), rhs.name ## Size()); \
72                                                                 predecessor ## CopyAllFrom(); }
73 
74 #define END_APPENDED_LISTS_STATIC(predecessor) \
75     /* Returns the size of the object containing the appended lists, including them */ \
76     unsigned int completeSize() const { return sizeof(SelfType) + predecessor ## OffsetBehind(); } \
77     unsigned int lastOffsetBehind() const { return predecessor ## OffsetBehind(); } \
78     /* Compares all appended lists and returns true if they are equal */                \
79     template <class T> bool listsEqual(const T &rhs) const { return predecessor ## ListChainEquals(rhs); } \
80     template <class T> void copyListsFrom(const T &rhs) { return predecessor ## CopyAllFrom(rhs); }
81 
82 template <bool dynamic, class T>
83 class AppendedList
84     : public KDevVarLengthArray<T
85         , 10>
86 {
87 public:
dynamicDataSize()88     unsigned int dynamicDataSize() const
89     {
90         return this->size() * sizeof(T);
91     }
data(const char *)92     const T* data(const char* /*position*/) const
93     {
94         return KDevVarLengthArray<T, 10>::data();
95     }
copy(T *,const T * data,uint size)96     void copy(T* /*target*/, const T* data, uint size)
97     {
98         Q_ASSERT(!shouldDoDUChainReferenceCounting(KDevVarLengthArray<T, 10>::data()));
99         bool empty = KDevVarLengthArray<T, 10>::isEmpty();
100         Q_ASSERT(empty);
101         Q_UNUSED(empty);
102         for (uint a = 0; a < size; ++a)
103             this->append(data[a]);
104     }
105 
free(T *)106     void free(T*)
107     {
108         Q_ASSERT(!shouldDoDUChainReferenceCounting(KDevVarLengthArray<T, 10>::data()));
109     }
110 };
111 
112 template <class T>
113 class AppendedList<false, T>
114 {
115 public:
AppendedList()116     AppendedList()
117     {
118     }
119     unsigned int listSize = 0;
size()120     unsigned int size() const
121     {
122         return listSize;
123     }
124 
free(T * position)125     void free(T* position)
126     {
127         if (listSize)
128             Q_ASSERT(shouldDoDUChainReferenceCounting(position)); //Since it's constant, it must be in the repository
129         for (unsigned int a = 0; a < listSize; ++a)
130             (position + a)->~T();
131     }
132 
133     //currentOffset should point to the position where the data of this item should be saved
data(const char * position)134     const T* data(const char* position) const
135     {
136         return reinterpret_cast<const T*>(position);
137     }
138     //Count of bytes that were appended
dynamicDataSize()139     unsigned int dynamicDataSize() const
140     {
141         return listSize * sizeof(T);
142     }
copy(T * target,const T * data,uint size)143     void copy(T* target, const T* data, uint size)
144     {
145         if (size)
146             Q_ASSERT(shouldDoDUChainReferenceCounting(target)); //Since it's constant, it must be in the repository
147         for (uint a = 0; a < size; ++a)
148             new (target + a) T(data[a]); //Properly call all the copy constructors
149 
150         listSize = size;
151     }
152 };
153 }
154 
155 #endif
156