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