FE
0.13.1
Header-only C++ frontend library
Toggle main menu visibility
Loading...
Searching...
No Matches
cast.h
Go to the documentation of this file.
1
#pragma once
2
3
#include <cassert>
4
#include <concepts>
5
6
#include <format>
7
#include <utility>
8
9
#include <
fe/assert.h
>
10
11
namespace
fe
{
12
13
template
<
class
T>
14
concept
Nodeable
=
requires
(T n) {
15
T::Node;
16
n.node();
17
};
18
19
/// Like Nodeable, but for a class that spans a *set* of node kinds instead of a single one.
20
/// Such a class declares `static constexpr bool isa_node(<node type>)` to decide membership.
21
/// This keeps RuntimeCast::isa from falling back to a `dynamic_cast` for abstract bases that merely group nodes.
22
template
<
class
T>
23
concept
NodeSetable
=
requires
(T n) {
24
{ T::isa_node(n.node()) } -> std::convertible_to<bool>;
25
};
26
27
/// Inherit from this class using [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern),
28
/// for some nice `dynamic_cast`-style wrappers.
29
template
<
class
B>
30
class
RuntimeCast
{
31
public
:
32
// clang-format off
33
/// `static_cast` with debug check.
34
template
<
class
T> T*
as
() { assert(
isa<T>
());
return
static_cast<
T*
>
(
this
); }
35
36
/// `dynamic_cast`.
37
/// If @p T isa fe::Nodeable, it will use `node()`, otherwise a `dynamic_cast`.
38
template
<
class
T>
39
T*
isa
() {
40
if
constexpr
(
Nodeable<T>
) {
41
return
static_cast<
B*
>
(
this
)->node() == T::Node ?
static_cast<
T*
>
(
this
) :
nullptr
;
42
}
else
if
constexpr
(
NodeSetable<T>
) {
43
return
T::isa_node(
static_cast<
B*
>
(
this
)->node()) ?
static_cast<
T*
>
(
this
) :
nullptr
;
44
}
else
{
45
return
dynamic_cast<
T*
>
(
static_cast<
B*
>
(
this
));
46
}
47
}
48
49
template
<
class
T>
const
T*
as
()
const
{
return
const_cast<
RuntimeCast
*
>
(
this
)->
template
as<T >
(); }
///< `const` version.
50
template
<
class
T>
const
T*
isa
()
const
{
return
const_cast<
RuntimeCast
*
>
(
this
)->
template
isa<T >
(); }
///< `const` version.
51
// clang-format on
52
53
/// Like as() but - instead of merely asserting via isa() in `Debug` builds - throws a `std::logic_error` with a
54
/// formatted message when the cast fails.
55
/// @p fmt / @p args describe what was expected: a plain string works, as does a format string plus arguments.
56
/// If `B` is `std::formattable`, the offending object is appended to the message.
57
template
<
class
T,
class
... Args>
58
T*
expect
(std::format_string<Args...> fmt, Args&&... args) {
59
if
(
auto
res =
isa<T>
())
return
res;
60
auto
what = std::format(fmt, std::forward<Args>(args)...);
61
if
constexpr
(std::formattable<const B*, char>)
62
throwf
(
"expected {}, but got '{}'"
, what,
static_cast<
const
B*
>
(
this
));
63
else
64
throwf
(
"expected {}"
, what);
65
}
66
67
/// `const` version.
68
template
<
class
T,
class
... Args>
69
const
T*
expect
(std::format_string<Args...> fmt, Args&&... args)
const
{
70
return
const_cast<
RuntimeCast
*
>
(
this
)->
template
expect<T>
(fmt, std::forward<Args>(args)...);
71
}
72
};
73
74
}
// namespace fe
assert.h
fe::RuntimeCast
Inherit from this class using CRTP, for some nice dynamic_cast-style wrappers.
Definition
cast.h:30
fe::RuntimeCast::as
T * as()
static_cast with debug check.
Definition
cast.h:34
fe::RuntimeCast::isa
T * isa()
dynamic_cast.
Definition
cast.h:39
fe::RuntimeCast::expect
const T * expect(std::format_string< Args... > fmt, Args &&... args) const
const version.
Definition
cast.h:69
fe::RuntimeCast::isa
const T * isa() const
const version.
Definition
cast.h:50
fe::RuntimeCast::expect
T * expect(std::format_string< Args... > fmt, Args &&... args)
Like as() but - instead of merely asserting via isa() in Debug builds - throws a std::logic_error wit...
Definition
cast.h:58
fe::RuntimeCast::as
const T * as() const
const version.
Definition
cast.h:49
fe::NodeSetable
Like Nodeable, but for a class that spans a set of node kinds instead of a single one.
Definition
cast.h:23
fe::Nodeable
Definition
cast.h:14
fe
Definition
algo.h:17
fe::throwf
void throwf(std::format_string< Args... > fmt, Args &&... args)
Throws a T (a std::logic_error by default) whose message is std::format(fmt, args....
Definition
assert.h:15
fe
cast.h
Generated by
1.18.0