0.6.0
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
types.h
Go to the documentation of this file.
1/**
2 * @file src/common/types.h
3 *
4 * Copyright (c) 2021-2025 Bartek Kryza <bkryza@gmail.com>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18#pragma once
19
20#include <cassert>
21#include <cstdint>
22#include <optional>
23#include <regex>
24#include <unordered_set>
25#include <variant>
26#include <vector>
27
28#include "model/namespace.h"
29
30namespace clanguml::common {
31
32/**
33 * @brief Universal class for representing all kinds of Id's in the diagram
34 * model.
35 *
36 * This class provides a convenient way of representing id's in the diagram
37 * model. The main problem it solves is that it allows to store both
38 * Clang AST ID's (obtained using getID() method), which are local to a single
39 * translation unit and have a type int64_t as well as global (across
40 * multiple translation units) id's used by clang-uml in the intermediate
41 * model (which are uint64_t).
42 *
43 * The class is aware which kind of value it holds and tries to ensure that
44 * mistakes such as using AST local ID in place where global id is needed
45 * do not happen.
46 */
47class eid_t {
48public:
49 using type = uint64_t;
50
51 eid_t();
52
53 explicit eid_t(int64_t id);
54
55 explicit eid_t(type id);
56
57 eid_t(const eid_t &) = default;
58 eid_t(eid_t &&) noexcept = default;
59 eid_t &operator=(const eid_t &) = default;
60 eid_t &operator=(eid_t &&) noexcept = default;
61
62 eid_t &operator=(int64_t ast_id);
63
64 ~eid_t() = default;
65
66 bool is_global() const;
67
68 friend bool operator==(const eid_t &lhs, const eid_t &rhs);
69 friend bool operator==(const eid_t &lhs, const uint64_t &v);
70 friend bool operator!=(const eid_t &lhs, const uint64_t &v);
71 friend bool operator!=(const eid_t &lhs, const eid_t &rhs);
72 friend bool operator<(const eid_t &lhs, const eid_t &rhs);
73
74 type value() const;
75
76 int64_t ast_local_value() const;
77
78private:
81};
82
83/**
84 * Type of output diagram format generator.
85 */
86enum class generator_type_t {
87 plantuml, /*!< Diagrams will be generated in PlantUML format */
88 json, /*!< Diagrams will be generated in JSON format */
89 mermaid, /*!< Diagrams will be generated in MermaidJS format */
90 graphml /*!< Diagrams will be generated in GraphML format */
91};
92
93std::string to_string(bool v);
94
95std::string to_string(const std::string &s);
96
97std::string to_string(const std::filesystem::path &p);
98
99std::string to_string(generator_type_t type);
100
101/**
102 * @brief Simple optional reference type.
103 *
104 * This class template provides a convenient way around the std::optional
105 * limitation of not allowing references. This is useful for storing
106 * references to diagram elements in various `views`, and writing methods
107 * which return can return an empty value if the diagram does not contain
108 * something.
109 *
110 * This is not an owning type - it will not accept an rvalue - the actual
111 * value must be stored somewhere else as lvalue or some kind of smart pointer.
112 *
113 * @note Probably unsafe - do not use at home.
114 *
115 * @tparam T Type of reference
116 */
117template <typename T> class optional_ref {
118public:
119 using optional_type = T;
120
121 optional_ref() = default;
122
123 optional_ref(T *value)
124 : value_{value}
125 {
126 }
127
128 optional_ref(const T *value)
129 : value_{value}
130 {
131 }
132
133 optional_ref(T &value)
134 : value_{&value}
135 {
136 }
137
138 optional_ref(const T &value)
139 : value_{&value}
140 {
141 }
142
144 : value_{right.get()}
145 {
146 }
147
148 template <typename V,
149 typename = std::enable_if<
150 std::is_base_of_v<optional_type, typename V::optional_type> ||
151 std::is_same_v<optional_type, typename V::optional_type>>>
152 optional_ref(const V &t)
153 : value_{t.get()}
154 {
155 }
156
157 template <typename V,
158 typename = std::enable_if<
159 std::is_base_of_v<optional_type, typename V::optional_type> ||
160 std::is_same_v<optional_type, typename V::optional_type>>>
162 : value_{t.get()}
163 {
164 t.reset();
165 }
166
167 template <typename V,
168 typename = std::enable_if<std::is_base_of_v<optional_type, V>>>
169 optional_ref(const std::reference_wrapper<V> &t)
170 : value_{&t.get()}
171 {
172 }
173
175 {
176 if (this == &right)
177 return *this;
178
179 value_ = right.value_;
180 return *this;
181 }
182
184 {
185 if (this == &right)
186 return *this;
187
188 value_ = right.value_;
189 right.reset();
190 return *this;
191 }
192
193 bool has_value() const noexcept { return value_ != nullptr; }
194
195 operator bool() const noexcept { return has_value(); }
196
197 const T &value() const
198 {
199 assert(value_ != nullptr);
200 return *value_;
201 }
202
203 T &value()
204 {
205 assert(value_ != nullptr);
206 return *value_;
207 }
208
210 {
211 assert(value_ != nullptr);
212 return *value_;
213 }
214
215 const T &operator*() const
216 {
217 assert(value_ != nullptr);
218 return *value_;
219 }
220
221 void reset() { value_ = nullptr; }
222
223 T *get() const { return value_; }
224
225private:
226 T *value_{nullptr};
227};
228
229template <typename T> using opt_ref = optional_ref<T>;
230
231template <typename T>
232using reference_vector = std::vector<std::reference_wrapper<T>>;
233
234template <typename T>
235using reference_set = std::unordered_set<std::reference_wrapper<T>>;
236
237/**
238 * @brief Wrapper around std::regex, which contains original pattern
239 */
240struct regex {
241 /**
242 * @brief Constructor
243 *
244 * @param r Parsed regular expression
245 * @param p Raw regular expression pattern used for regenerating config and
246 * debugging
247 */
248 regex(std::regex r, std::string p)
249 : regexp{std::move(r)}
250 , pattern{std::move(p)}
251 {
252 }
253
254 /**
255 * @brief Regular expression match operator
256 * @param v Value to match against internal std::regex
257 * @return True, if the argument matches the regular expression
258 */
259 [[nodiscard]] bool operator%=(const std::string &v) const
260 {
261 return std::regex_match(v, regexp);
262 }
263
264 std::regex regexp; /*!< Parsed regular expression */
265 std::string pattern; /*!< Original regular expression pattern */
266};
267
268/**
269 * @brief Convenience class for configuration options with regex support
270 *
271 * This template class provides a convenient way of handling configuraiton
272 * options, which can be either some basic type like std::string or regex.
273 *
274 * @tparam T Type of alternative to regex (e.g. std::string)
275 */
276template <typename T> struct or_regex {
277 or_regex() = default;
278
279 /**
280 * @brief Constructor from alternative type
281 */
283 : value_{std::move(v)}
284 {
285 }
286
287 /**
288 * @brief Constructor from regex
289 *
290 * @param r Parsed regular expression
291 * @param p Raw regular expression pattern used for regenerating config and
292 * debugging
293 */
294 or_regex(std::regex r, std::string p)
295 : value_{regex{std::move(r), std::move(p)}}
296 {
297 }
298
299 or_regex &operator=(const T &v)
300 {
301 value_ = v;
302 return *this;
303 }
304
306 {
307 value_ = v;
308 return *this;
309 }
310
311 [[nodiscard]] bool operator==(const T &v) const
312 {
313 if (std::holds_alternative<regex>(value_))
314 return std::regex_match(v, std::get<regex>(value_).regexp);
315
316 return std::get<T>(value_) == v;
317 }
318
319 template <typename Ret> std::optional<Ret> get() const
320 {
321 if (!std::holds_alternative<Ret>(value_))
322 return std::nullopt;
323
324 return std::get<Ret>(value_);
325 }
326
327 std::string to_string() const
328 {
329 if (std::holds_alternative<regex>(value_))
330 return std::get<regex>(value_).pattern;
331
332 return clanguml::common::to_string(std::get<T>(value_));
333 }
334
335 const std::variant<T, regex> &value() const { return value_; }
336
337 bool is_regex() const { return std::holds_alternative<regex>(value_); }
338
339private:
340 std::variant<T, regex> value_;
341};
342
344
345std::string to_string(const string_or_regex &sr);
346
348
349struct path_or_regex : public or_regex<std::filesystem::path> { };
350
351} // namespace clanguml::common
352
353template <> class fmt::formatter<clanguml::common::eid_t> {
354public:
355 constexpr auto parse(format_parse_context &ctx) { return ctx.begin(); }
356 template <typename Context>
357 constexpr auto format(clanguml::common::eid_t const &id, Context &ctx) const
358 {
359 return fmt::format_to(ctx.out(), "{}", id.value());
360 }
361};
362