0.5.4
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-2024 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};
91
92std::string to_string(const std::string &s);
93
95
96/**
97 * @brief Simple optional reference type.
98 *
99 * This class template provides a convenient way around the std::optional
100 * limitation of not allowing references. This is useful for storing
101 * references to diagram elements in various `views`, and writing methods
102 * which return can return an empty value if the diagram does not contain
103 * something.
104 *
105 * This is not an owning type - it will not accept an rvalue - the actual
106 * value must be stored somewhere else as lvalue or some kind of smart pointer.
107 *
108 * @note Probably unsafe - do not use at home.
109 *
110 * @tparam T Type of reference
111 */
112template <typename T> class optional_ref {
113public:
114 using optional_type = T;
115
116 optional_ref() = default;
117
118 optional_ref(T *value)
119 : value_{value}
120 {
121 }
122
123 optional_ref(const T *value)
124 : value_{value}
125 {
126 }
127
128 optional_ref(T &value)
129 : value_{&value}
130 {
131 }
132
133 optional_ref(const T &value)
134 : value_{&value}
135 {
136 }
137
139 : value_{right.get()}
140 {
141 }
142
143 template <typename V,
144 typename = std::enable_if<
145 std::is_base_of_v<optional_type, typename V::optional_type> ||
146 std::is_same_v<optional_type, typename V::optional_type>>>
147 optional_ref(const V &t)
148 : value_{t.get()}
149 {
150 }
151
152 template <typename V,
153 typename = std::enable_if<
154 std::is_base_of_v<optional_type, typename V::optional_type> ||
155 std::is_same_v<optional_type, typename V::optional_type>>>
157 : value_{t.get()}
158 {
159 t.reset();
160 }
161
162 template <typename V,
163 typename = std::enable_if<std::is_base_of_v<optional_type, V>>>
164 optional_ref(const std::reference_wrapper<V> &t)
165 : value_{&t.get()}
166 {
167 }
168
170 {
171 if (this == &right)
172 return *this;
173
174 value_ = right.value_;
175 return *this;
176 }
177
179 {
180 if (this == &right)
181 return *this;
182
183 value_ = right.value_;
184 right.reset();
185 return *this;
186 }
187
188 bool has_value() const noexcept { return value_ != nullptr; }
189
190 operator bool() const noexcept { return has_value(); }
191
192 const T &value() const
193 {
194 assert(value_ != nullptr);
195 return *value_;
196 }
197
198 T &value()
199 {
200 assert(value_ != nullptr);
201 return *value_;
202 }
203
205 {
206 assert(value_ != nullptr);
207 return *value_;
208 }
209
210 const T &operator*() const
211 {
212 assert(value_ != nullptr);
213 return *value_;
214 }
215
216 void reset() { value_ = nullptr; }
217
218 T *get() const { return value_; }
219
220private:
221 T *value_{nullptr};
222};
223
224template <typename T> using opt_ref = optional_ref<T>;
225
226template <typename T>
227using reference_vector = std::vector<std::reference_wrapper<T>>;
228
229template <typename T>
230using reference_set = std::unordered_set<std::reference_wrapper<T>>;
231
232/**
233 * @brief Wrapper around std::regex, which contains original pattern
234 */
235struct regex {
236 /**
237 * @brief Constructor
238 *
239 * @param r Parsed regular expression
240 * @param p Raw regular expression pattern used for regenerating config and
241 * debugging
242 */
243 regex(std::regex r, std::string p)
244 : regexp{std::move(r)}
245 , pattern{std::move(p)}
246 {
247 }
248
249 /**
250 * @brief Regular expression match operator
251 * @param v Value to match against internal std::regex
252 * @return True, if the argument matches the regular expression
253 */
254 [[nodiscard]] bool operator%=(const std::string &v) const
255 {
256 return std::regex_match(v, regexp);
257 }
258
259 std::regex regexp; /*!< Parsed regular expression */
260 std::string pattern; /*!< Original regular expression pattern */
261};
262
263/**
264 * @brief Convenience class for configuration options with regex support
265 *
266 * This template class provides a convenient way of handling configuraiton
267 * options, which can be either some basic type like std::string or regex.
268 *
269 * @tparam T Type of alternative to regex (e.g. std::string)
270 */
271template <typename T> struct or_regex {
272 or_regex() = default;
273
274 /**
275 * @brief Constructor from alternative type
276 */
278 : value_{std::move(v)}
279 {
280 }
281
282 /**
283 * @brief Constructor from regex
284 *
285 * @param r Parsed regular expression
286 * @param p Raw regular expression pattern used for regenerating config and
287 * debugging
288 */
289 or_regex(std::regex r, std::string p)
290 : value_{regex{std::move(r), std::move(p)}}
291 {
292 }
293
294 or_regex &operator=(const T &v)
295 {
296 value_ = v;
297 return *this;
298 }
299
301 {
302 value_ = v;
303 return *this;
304 }
305
306 [[nodiscard]] bool operator==(const T &v) const
307 {
308 if (std::holds_alternative<regex>(value_))
309 return std::regex_match(v, std::get<regex>(value_).regexp);
310
311 return std::get<T>(value_) == v;
312 }
313
314 template <typename Ret> std::optional<Ret> get() const
315 {
316 if (!std::holds_alternative<Ret>(value_))
317 return std::nullopt;
318
319 return std::get<Ret>(value_);
320 }
321
322 std::string to_string() const
323 {
324 if (std::holds_alternative<regex>(value_))
325 return std::get<regex>(value_).pattern;
326
327 return clanguml::common::to_string(std::get<T>(value_));
328 }
329
330 const std::variant<T, regex> &value() const { return value_; }
331
332 bool is_regex() const { return std::holds_alternative<regex>(value_); }
333
334private:
335 std::variant<T, regex> value_;
336};
337
339
340std::string to_string(const string_or_regex &sr);
341
343
344struct path_or_regex : public or_regex<std::filesystem::path> { };
345
346} // namespace clanguml::common
347
348template <> class fmt::formatter<clanguml::common::eid_t> {
349public:
350 constexpr auto parse(format_parse_context &ctx) { return ctx.begin(); }
351 template <typename Context>
352 constexpr auto format(clanguml::common::eid_t const &id, Context &ctx) const
353 {
354 return fmt::format_to(ctx.out(), "{}", id.value());
355 }
356};