File indexing completed on 2024-05-12 04:37:56
0001 /* 0002 SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #ifndef KDEVPLATFORM_APPENDEDLIST_STATIC_H 0008 #define KDEVPLATFORM_APPENDEDLIST_STATIC_H 0009 0010 #include <util/kdevvarlengtharray.h> 0011 #include <serialization/referencecounting.h> 0012 0013 namespace KDevelop { 0014 /** 0015 * This file contains macros and classes that can be used to conveniently 0016 * implement classes that store the data of an arbitrary count 0017 * of additional lists within the same memory block directly behind the 0018 * class data, in a way that one the whole data can be stored by one copy-operation 0019 * to another place, like needed in ItemRepository. These macros simplify 0020 * having two versions of a class: One that has its lists attached in memory, 0021 * and one version that has them contained as a directly accessible 0022 * KDevVarLengthArray. Both versions have their lists accessible through access-functions, 0023 * have a completeSize() function that computes the size of the one-block 0024 * version, and a copyListsFrom(..) function which can copy the lists from one 0025 * version to the other. The class that contains these lists must have 0026 * a boolean template parameter called "dynamic". 0027 * 0028 * See identifier.cpp for an example how to use these classes. @todo Document this a bit more 0029 * */ 0030 0031 // 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. 0032 //This might be a little slow 0033 #define FOREACH_FUNCTION_STATIC(item, container) \ 0034 for (uint a__ = 0, mustDo__ = 1; a__ < container ## Size(); ++a__) \ 0035 if ((mustDo__ == 0 || mustDo__ == 1) && (mustDo__ = 2)) \ 0036 for (item(container()[a__]); mustDo__; mustDo__ = 0) 0037 0038 #define START_APPENDED_LISTS_STATIC(selftype) using SelfType = selftype; 0039 0040 #define APPENDED_LIST_COMMON_STATIC(type, name) \ 0041 KDevelop::AppendedList<dynamic, type> name ## List; \ 0042 unsigned int name ## Size() const { return name ## List.size(); } \ 0043 template <class T> bool name ## Equals(const T &rhs) const { \ 0044 unsigned int size = name ## Size(); \ 0045 if (size != rhs.name ## Size()) \ 0046 return false; \ 0047 for (uint a = 0; a < size; ++a) {if (!(name()[a] == rhs.name()[a])) \ 0048 return false; } \ 0049 return true; \ 0050 } 0051 0052 ///@todo Make these things a bit faster(less recursion) 0053 0054 #define APPENDED_LIST_FIRST_STATIC(type, name) \ 0055 APPENDED_LIST_COMMON_STATIC(type, name) \ 0056 const type * name() const { return name ## List.data(reinterpret_cast<const char*>(this) + sizeof(SelfType)); } \ 0057 unsigned int name ## OffsetBehind() const { return name ## List.dynamicDataSize(); } \ 0058 template <class T> bool name ## ListChainEquals(const T &rhs) const { return name ## Equals(rhs); } \ 0059 template <class T> void name ## CopyAllFrom(const T &rhs) { name ## List.copy(const_cast<type*>(name()), \ 0060 rhs.name(), rhs.name ## Size()); } 0061 0062 #define APPENDED_LIST_STATIC(type, name, predecessor) \ 0063 APPENDED_LIST_COMMON_STATIC(type, name) \ 0064 const type * name() const { return name ## List.data( \ 0065 reinterpret_cast<const char*>(this) + sizeof(SelfType) + \ 0066 predecessor ## OffsetBehind()); } \ 0067 unsigned int name ## OffsetBehind() const { return name ## List.dynamicDataSize() + predecessor ## OffsetBehind(); } \ 0068 template <class T> bool name ## ListChainEquals(const T &rhs) const { return name ## Equals(rhs) && \ 0069 predecessor ## ListChainEquals(rhs); } \ 0070 template <class T> void name ## CopyAllFrom(const T &rhs) { name ## List.copy(const_cast<type*>(name()), \ 0071 rhs.name(), rhs.name ## Size()); \ 0072 predecessor ## CopyAllFrom(); } 0073 0074 #define END_APPENDED_LISTS_STATIC(predecessor) \ 0075 /* Returns the size of the object containing the appended lists, including them */ \ 0076 unsigned int completeSize() const { return sizeof(SelfType) + predecessor ## OffsetBehind(); } \ 0077 unsigned int lastOffsetBehind() const { return predecessor ## OffsetBehind(); } \ 0078 /* Compares all appended lists and returns true if they are equal */ \ 0079 template <class T> bool listsEqual(const T &rhs) const { return predecessor ## ListChainEquals(rhs); } \ 0080 template <class T> void copyListsFrom(const T &rhs) { return predecessor ## CopyAllFrom(rhs); } 0081 0082 template <bool dynamic, class T> 0083 class AppendedList 0084 : public KDevVarLengthArray<T 0085 , 10> 0086 { 0087 public: 0088 unsigned int dynamicDataSize() const 0089 { 0090 return this->size() * sizeof(T); 0091 } 0092 const T* data(const char* /*position*/) const 0093 { 0094 return KDevVarLengthArray<T, 10>::data(); 0095 } 0096 void copy(T* /*target*/, const T* data, uint size) 0097 { 0098 Q_ASSERT(!shouldDoDUChainReferenceCounting(KDevVarLengthArray<T, 10>::data())); 0099 bool empty = KDevVarLengthArray<T, 10>::isEmpty(); 0100 Q_ASSERT(empty); 0101 Q_UNUSED(empty); 0102 for (uint a = 0; a < size; ++a) 0103 this->append(data[a]); 0104 } 0105 0106 void free(T*) 0107 { 0108 Q_ASSERT(!shouldDoDUChainReferenceCounting(KDevVarLengthArray<T, 10>::data())); 0109 } 0110 }; 0111 0112 template <class T> 0113 class AppendedList<false, T> 0114 { 0115 public: 0116 AppendedList() 0117 { 0118 } 0119 unsigned int listSize = 0; 0120 unsigned int size() const 0121 { 0122 return listSize; 0123 } 0124 0125 void free(T* position) 0126 { 0127 if (listSize) 0128 Q_ASSERT(shouldDoDUChainReferenceCounting(position)); //Since it's constant, it must be in the repository 0129 for (unsigned int a = 0; a < listSize; ++a) 0130 (position + a)->~T(); 0131 } 0132 0133 //currentOffset should point to the position where the data of this item should be saved 0134 const T* data(const char* position) const 0135 { 0136 return reinterpret_cast<const T*>(position); 0137 } 0138 //Count of bytes that were appended 0139 unsigned int dynamicDataSize() const 0140 { 0141 return listSize * sizeof(T); 0142 } 0143 void copy(T* target, const T* data, uint size) 0144 { 0145 if (size) 0146 Q_ASSERT(shouldDoDUChainReferenceCounting(target)); //Since it's constant, it must be in the repository 0147 for (uint a = 0; a < size; ++a) 0148 new (target + a) T(data[a]); //Properly call all the copy constructors 0149 0150 listSize = size; 0151 } 0152 }; 0153 } 0154 0155 #endif