QXmpp  Version: 1.15.1
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 
16 namespace QXmpp::Private::Enums {
17 
18 // std::array helper
19 namespace detail {
20 
21 template<class T, std::size_t N, std::size_t... I>
22 constexpr 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 
29 template<typename Enum, std::size_t N>
30 consteval 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 
35 template<typename Enum>
36 struct Data;
37 
38 // order check
39 template<typename Enum, size_t N>
40 consteval 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 
54 template<typename Enum>
55 concept 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 
65 template<typename Enum>
66 concept 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 
76 template<typename Enum>
77 concept NullableEnum = requires(Enum value) {
78  typename Data<Enum>;
79  { Data<Enum>::NullValue } -> std::convertible_to<Enum>;
80 };
81 
82 template<typename Enum>
83 constexpr 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 
97 template<SerializableEnum Enum>
98 constexpr 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 
107 template<SerializableFlags Enum, typename Container>
108 constexpr 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 
119 template<SerializableFlags Enum>
120 constexpr 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 
131 template<SerializableFlags Enum>
132 QList<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 
142 template<QXmpp::Private::Enums::SerializableEnum Enum>
143 bool operator==(QStringView s, Enum e) { return s == QXmpp::Private::Enums::toString(e); }
144 template<QXmpp::Private::Enums::SerializableEnum Enum>
145 bool operator!=(QStringView s, Enum e) { return s != QXmpp::Private::Enums::toString(e); }
146 
147 template<QXmpp::Private::Enums::SerializableEnum Enum>
148 struct 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 
163 template<QXmpp::Private::Enums::SerializableEnum Enum>
164 QDebug operator<<(QDebug debug, Enum e)
165 {
166  return debug << QXmpp::Private::Enums::toString(e);
167 }
168 
169 #endif // ENUMS_H
Definition: Enums.h:16