1 /*
2   metaenum.h
3 
4   This file is part of GammaRay, the Qt application inspection and
5   manipulation tool.
6 
7   Copyright (C) 2016-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8   Author: Volker Krause <volker.krause@kdab.com>
9 
10   Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11   accordance with GammaRay Commercial License Agreement provided with the Software.
12 
13   Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 
15   This program is free software; you can redistribute it and/or modify
16   it under the terms of the GNU General Public License as published by
17   the Free Software Foundation, either version 2 of the License, or
18   (at your option) any later version.
19 
20   This program is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23   GNU General Public License for more details.
24 
25   You should have received a copy of the GNU General Public License
26   along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 */
28 
29 #ifndef GAMMARAY_METAENUM_H
30 #define GAMMARAY_METAENUM_H
31 
32 #include <QStringList>
33 
34 #include <type_traits>
35 
36 namespace GammaRay {
37 /** Enum/flag stringification utilities. */
38 namespace MetaEnum {
39 template<typename T>
40 struct Value {
41     T value;
42     const char * const name;
43 };
44 
45 template<typename T, std::size_t N>
count(const Value<T> (&)[N])46 std::size_t count(const Value<T>(&)[N])
47 {
48     return N;
49 }
50 
51 template<typename T, std::size_t N>
enumToString(T value,const Value<T> (& lookupTable)[N])52 QString enumToString(T value, const Value<T>(&lookupTable)[N])
53 {
54     for (std::size_t i = 0; i < N; ++i) {
55         if (lookupTable[i].value == value)
56             return QString::fromUtf8(lookupTable[i].name);
57     }
58     return QStringLiteral("unknown (") + QString::number(value) + ')';
59 }
60 
61 template<typename T, typename F, std::size_t N>
flagsToString(T flags,const Value<F> (& lookupTable)[N])62 QString flagsToString(T flags, const Value<F>(&lookupTable)[N])
63 {
64     QStringList l;
65     T handledFlags = T();
66 
67     for (std::size_t i = 0; i < N; ++i) {
68         if (flags & lookupTable[i].value) {
69             l.push_back(QString::fromUtf8(lookupTable[i].name));
70         }
71         handledFlags |= lookupTable[i].value;
72     }
73 
74     if (flags & ~handledFlags) {
75         l.push_back(QStringLiteral("flag 0x") +
76                     QString::number(qulonglong(flags & ~handledFlags), 16));
77     }
78 
79     if (l.isEmpty()) {
80         // check if we have a special 0-value
81         for (std::size_t i = 0; i < N; ++i) {
82             if (lookupTable[i].value == 0)
83                 return QString::fromUtf8(lookupTable[i].name);
84         }
85         return QStringLiteral("<none>");
86     }
87     return l.join(QStringLiteral("|"));
88 }
89 
90 // functors for easy use with VariantHandler::registerStringConverter
91 namespace detail {
92 template <typename T, std::size_t N>
93 class enum_to_string_functor
94 {
95 public:
enum_to_string_functor(const MetaEnum::Value<T> (& lookupTable)[N])96     explicit enum_to_string_functor(const MetaEnum::Value<T>(&lookupTable)[N])
97         : m_lookupTable(lookupTable)
98     {}
99 
operator()100     QString operator()(T value)
101     {
102         return MetaEnum::enumToString(value, m_lookupTable);
103     }
104 
105 private:
106     const MetaEnum::Value<T> (&m_lookupTable)[N];
107 
108 };
109 
110 template <typename T, std::size_t N>
111 class flags_to_string_functor
112 {
113 public:
flags_to_string_functor(const MetaEnum::Value<T> (& lookupTable)[N])114     explicit flags_to_string_functor(const MetaEnum::Value<T>(&lookupTable)[N])
115         : m_lookupTable(lookupTable)
116     {}
117 
118 #if !defined(Q_CC_MSVC) || _MSC_VER >= 1900 //krazy:exclude=cpp to deal with older MS compilers
operator()119     QString operator()(typename std::underlying_type<T>::type value)
120 #else
121     QString operator()(unsigned int value)
122 #endif
123     {
124         return MetaEnum::flagsToString(value, m_lookupTable);
125     }
126 
127 private:
128     const MetaEnum::Value<T> (&m_lookupTable)[N];
129 
130 };
131 
132 }
133 
134 /** Creates a functor for MetaEnum::enumToString and a specific lookup table. */
135 template <typename T, std::size_t N>
enumToString_fn(const Value<T> (& lookupTable)[N])136 detail::enum_to_string_functor<T, N> enumToString_fn(const Value<T>(&lookupTable)[N])
137 {
138     return detail::enum_to_string_functor<T, N>(lookupTable);
139 }
140 
141 /** Creates a functor for MetaEnum::flagsToString and a specific lookup table. */
142 template <typename T, std::size_t N>
flagsToString_fn(const Value<T> (& lookupTable)[N])143 detail::flags_to_string_functor<T, N> flagsToString_fn(const Value<T>(&lookupTable)[N])
144 {
145     return detail::flags_to_string_functor<T, N>(lookupTable);
146 }
147 
148 } // MetaEnum
149 } // GammaRay
150 
151 #endif
152