1 /*
2 This file is part of the Okteta Kasten Framework, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2011 Alex Richardson <alex.richardson@gmx.de>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9 #include "flagdatainformation.hpp"
10 #include <QVarLengthArray>
11 #include <KLocalizedString>
12
FlagDataInformation(const QString & name,PrimitiveDataInformation * type,const EnumDefinition::Ptr & enumDef,DataInformation * parent)13 FlagDataInformation::FlagDataInformation(const QString& name, PrimitiveDataInformation* type,
14 const EnumDefinition::Ptr& enumDef, DataInformation* parent)
15 : EnumDataInformation(name, type, enumDef, parent)
16 {
17 Q_ASSERT_X(type->type() != PrimitiveDataType::Double && type->type() != PrimitiveDataType::Float && type->type() != PrimitiveDataType::Invalid,
18 "FlagDataInformation::FlagDataInformation", "Bitflags only work with integers!");
19 }
20
21 using FlagPair = QPair<QString, quint64>;
22
23 template <typename T, int len>
removeFromArray(QVarLengthArray<T,len> & array,int index)24 static void removeFromArray(QVarLengthArray<T, len>& array, int index)
25 {
26 Q_ASSERT(index >= 0 && index < array.size());
27 int max = array.size() - 1;
28 for (int i = index; i < max; ++i) {
29 array[i] = array[i + 1];
30 }
31
32 array.removeLast();
33 }
34
valueStringImpl() const35 QString FlagDataInformation::valueStringImpl() const
36 {
37 Q_ASSERT(mWasAbleToRead);
38 QMapIterator<AllPrimitiveTypes, QString> iter(mEnum->values());
39 // I doubt more than 10 flags will be set very often -> only then do we need a malloc
40 QVarLengthArray<FlagPair, 10> arr;
41 const quint64 value = mValue->value().value<quint64>();
42 while (iter.hasNext()) {
43 iter.next();
44 const quint64 flag = iter.key().value<quint64>();
45 if ((value & flag) == flag) {
46 // flag is set
47 arr.append(qMakePair(iter.value(), flag));
48 }
49 }
50
51 // now we have all flags, check if some overlap
52 for (int i = 0; i < arr.size(); ++i) {
53 const quint64 firstFlag = arr.at(i).second;
54 for (int j = 0; j < arr.size();) {
55 if (j == i) {
56 j++;
57 continue;
58 }
59 // check if they overlap
60 quint64 secondFlag = arr.at(j).second;
61 if ((firstFlag & secondFlag) == secondFlag) {
62 // they overlap, remove the second flag
63 removeFromArray(arr, j);
64 if (j < i) {
65 i--; // i was pushed back by one as well
66 }
67 } else {
68 j++;
69 }
70 }
71 }
72
73 // if array has zero elements just return the value in hexadecimal
74 if (arr.isEmpty()) {
75 return i18n("0x%1 (no matching flags)", QString::number(value, 16));
76 }
77
78 // make sure all we also show remaining bits at the end
79 quint64 usedBits = 0;
80 QString result;
81 for (int i = 0, size = arr.size(); i < size; ++i) {
82 if (i != 0) {
83 result += QLatin1String(" | ");
84 }
85 result += arr.at(i).first;
86 usedBits |= arr.at(i).second;
87 }
88
89 // TODO remove a NONE flag if others present (value = 0)
90
91 // TODO set invalid if value not completely covered by flags
92
93 if (usedBits != value) {
94 quint64 missing = value & ~usedBits;
95 result += QLatin1String(" | 0x") + QString::number(missing, 16);
96 }
97
98 return result;
99 }
100
typeNameImpl() const101 QString FlagDataInformation::typeNameImpl() const
102 {
103 return i18nc("Displayed in the type column. first comes the name "
104 "of the enum, then the underlying type (e.g. uint32)",
105 "flag %1 (%2)", mEnum->name(), mValue->typeName());
106 }
107