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