QXmpp Version: 1.11.3
Loading...
Searching...
No Matches
Enums.h
1// SPDX-FileCopyrightText: 2025 Linus Jahn <lnj@kaidan.im>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#ifndef ENUMS_H
6#define ENUMS_H
7
8#include <array>
9#include <optional>
10#include <ranges>
11
12#include <QDebug>
13#include <QList>
14#include <QString>
15
16namespace QXmpp::Private::Enums {
17
18// std::array helper
19namespace detail {
20
21template<class T, std::size_t N, std::size_t... I>
22constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(T (&&a)[N], std::index_sequence<I...>)
23{
24 return { { std::move(a[I])... } };
25}
26
27} // namespace detail
28
29template<typename Enum, std::size_t N>
30consteval std::array<std::remove_cv_t<std::tuple<Enum, QStringView>>, N> makeValues(std::tuple<Enum, QStringView> (&&a)[N])
31{
32 return detail::to_array_impl(std::move(a), std::make_index_sequence<N> {});
33}
34
35template<typename Enum>
36struct Data;
37
38// order check
39template<typename Enum, size_t N>
40consteval bool checkEnumOrder(const std::array<std::tuple<Enum, QStringView>, N> &values)
41{
42 size_t offset = 0;
43 if constexpr (N > 0) {
44 offset = size_t(std::get<0>(values[0]));
45 }
46 for (size_t i = offset; i < (N + offset); ++i) {
47 if (i != size_t(std::get<0>(values[i]))) {
48 return false;
49 }
50 }
51 return true;
52}
53
54template<typename Enum>
55concept SerializableEnum = requires {
56 typename Data<Enum>;
57
58 requires std::ranges::random_access_range<decltype(Data<Enum>::Values)>;
59 requires std::same_as<
60 std::ranges::range_value_t<decltype(Data<Enum>::Values)>,
61 std::tuple<Enum, QStringView>>;
62 requires checkEnumOrder<Enum>(Data<Enum>::Values);
63};
64
65template<typename Enum>
66concept SerializableFlags = requires {
67 typename Data<Enum>;
68 requires Data<Enum>::IsFlags == true;
69
70 requires std::ranges::random_access_range<decltype(Data<Enum>::Values)>;
71 requires std::same_as<
72 std::ranges::range_value_t<decltype(Data<Enum>::Values)>,
73 std::tuple<Enum, QStringView>>;
74};
75
76template<typename Enum>
77concept NullableEnum = requires(Enum value) {
78 typename Data<Enum>;
79 { Data<Enum>::NullValue } -> std::convertible_to<Enum>;
80};
81
82template<typename Enum>
83constexpr std::optional<Enum> fromString(QStringView str)
84 requires SerializableEnum<Enum> || SerializableFlags<Enum>
85{
86 constexpr auto values = Data<Enum>::Values;
87
88 auto enumPart = [](const auto &v) { return std::get<0>(v); };
89 auto stringPart = [](const auto &v) { return std::get<1>(v); };
90
91 if (auto itr = std::ranges::find(values, str, stringPart); itr != values.end()) {
92 return enumPart(*itr);
93 }
94 return {};
95}
96
97template<SerializableEnum Enum>
98constexpr QStringView toString(Enum value)
99{
100 // offset for enums that do not start at 0
101 constexpr auto offset = size_t(std::get<0>(Data<Enum>::Values[0]));
102
103 auto &[enumerator, string] = Data<Enum>::Values.at(size_t(value) - offset);
104 return string;
105};
106
107template<SerializableFlags Enum, typename Container>
108constexpr QFlags<Enum> fromStrings(const Container &container)
109{
110 QFlags<Enum> result;
111 for (const auto &string : container) {
112 if (auto flag = fromString<Enum>(string)) {
113 result.setFlag(*flag);
114 }
115 }
116 return result;
117}
118
119template<SerializableFlags Enum>
120constexpr auto toStrings(QFlags<Enum> value)
121{
122 auto testFlag = [value](auto entry) {
123 auto &[enumerator, string] = entry;
124 return value.testFlag(enumerator);
125 };
126 auto string = [](auto entry) { return std::get<1>(entry); };
127
128 return std::views::filter(Data<Enum>::Values, testFlag) | std::views::transform(string);
129}
130
131template<SerializableFlags Enum>
132QList<QString> toStringList(QFlags<Enum> value)
133{
134 auto strings = toStrings(value) | std::views::transform(&QStringView::toString);
135 return QList<QString>(strings.begin(), strings.end());
136}
137
138} // namespace QXmpp::Private::Enums
139
140// operators
141
142template<QXmpp::Private::Enums::SerializableEnum Enum>
143bool operator==(QStringView s, Enum e) { return s == QXmpp::Private::Enums::toString(e); }
144template<QXmpp::Private::Enums::SerializableEnum Enum>
145bool operator!=(QStringView s, Enum e) { return s != QXmpp::Private::Enums::toString(e); }
146
147template<QXmpp::Private::Enums::SerializableEnum Enum>
148struct QConcatenable<Enum> {
149 typedef Enum type;
150 typedef QString ConvertTo;
151 enum { ExactSize = true };
152
153 static int size(Enum e)
154 {
155 return QXmpp::Private::Enums::toString(e).size();
156 }
157 static void appendTo(Enum m, QChar *&out)
158 {
159 QConcatenable<QStringView>::appendTo(QXmpp::Private::Enums::toString(m), out);
160 }
161};
162
163template<QXmpp::Private::Enums::SerializableEnum Enum>
164QDebug operator<<(QDebug debug, Enum e)
165{
166 return debug << QXmpp::Private::Enums::toString(e);
167}
168
169#endif // ENUMS_H