1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
// license:BSD-3-Clause
// copyright-holders:Couriersud
#ifndef PGSL_H_
#define PGSL_H_
///
/// \file pgsl.h
///
/// This core guidelines gsl implementation currently provides only enough
/// functionality to syntactically support a very limited number of the
/// gsl specification.
///
/// Going forward this approach may be extended.
///
#include "pconfig.h"
#include "pexception.h"
#include "ptypes.h"
#include <exception>
#include <optional>
#include <type_traits>
#include <utility>
#if defined(__has_builtin) // clang and gcc 10
#if __has_builtin(__builtin_unreachable)
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
#else
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0))
#endif
#elif defined(__GNUC__) && !(defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ))
//#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
#define gsl_Expects(e) (__builtin_expect(!!(e), 1) ? static_cast<void>(0) : __builtin_unreachable())
#elif defined(_MSC_VER)
#define gsl_Expects(e) __assume(e)
#else
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0))
#endif
#if 1
// FIXME: __builtin_unreachable contrary to google sources does not seem to be of
// any use and decreases performance slightly. Convert gsl_Expects to a noop
// and revisit in the future.
#undef gsl_Expects
#define gsl_Expects(e) do {} while (0)
#if 0
// Alternative and c++ style implementation. Suffers from the same drawbacks
// like __builtin_unreachable
static constexpr inline void gsl_Expects(const bool &e)
{
if (!e)
__builtin_unreachable();
}
#endif
#endif
#define gsl_Ensures(e) gsl_Expects(e)
namespace plib {
namespace pgsl {
struct narrowing_error : public std::exception {};
template <typename T>
using owner = T;
template <typename T>
using not_null = T;
/// \brief perform a narrowing cast without checks
///
template <typename T, typename O>
constexpr T narrow_cast(O && v) noexcept
{
static_assert(plib::is_arithmetic<T>::value && std::is_convertible<std::remove_reference_t<O>, T>::value, "narrow cast expects conversion between arithmetic types");
return static_cast<T>(std::forward<O>(v));
}
/// \brief perform a narrowing cast terminating if loss of precision
///
/// The c++ core guidelines require the narrow function to raise an error
/// This will make narrow noexcept(false). This has shown to have a
/// measurable impact on performance and thus we deviate from
/// the standard here.
///
template <typename T, typename O>
inline T narrow(O && v) noexcept
{
static_assert(plib::is_arithmetic<T>::value && std::is_convertible<std::remove_reference_t<O>, T>::value, "narrow cast expects conversion between arithmetic types");
const auto val = static_cast<T>(std::forward<O>(v));
if( v == static_cast<std::remove_reference_t<O>>(val))
{
return val;
}
plib::terminate("narrowing_error");
// throw narrowing_error();
}
} // namespace pgsl
/// \brief dynamic downcast from base type pointer to derived type pointer
///
/// This is a `noexcept` dynamic_cast implementation. It will return the cast
/// wrapped into a std::optional type forcing the caller to
/// examine if the conversion was successful.
///
/// \tparam D Derived type
/// \tparam B Base type
/// \param base pointer to type B
/// \returns return_success_t
///
template <typename D, typename B>
std::enable_if_t<std::is_pointer_v<D> && std::is_pointer_v<std::remove_reference_t<B>>,
std::optional<D>>
dynamic_downcast(B base) noexcept
{
D ret = dynamic_cast<D>(base);
if (ret != nullptr)
return ret;
return std::nullopt;
}
/// \brief dynamic downcast from base type reference to derived type pointer
///
/// This is a `noexcept` dynamic_cast implementation. It will return the
/// pointer cast wrapped into a std::optional type forcing the caller to
/// examine if the conversion was successful.
///
/// The return value is a pointer cast since there is no std::optional for
/// references. Such a construct is considered ill-formed according to
/// the std::optional specification (Section 5.2, p1).
///
/// \tparam D Derived type
/// \tparam B Base type
/// \param base reference of type B
/// \returns return_success_t
///
template <typename D, typename B>
std::enable_if_t<std::is_pointer_v<D> &&!std::is_pointer_v<std::remove_reference_t<B>> ,
std::optional<D>>
dynamic_downcast(B &base) noexcept
{
D ret = dynamic_cast<D>(&base);
if (ret != nullptr)
return ret;
return std::nullopt;
}
/// \brief downcast from base type to derived type
///
/// The cpp core guidelines require a very careful use of static cast
/// for downcast operations. This template is used to identify these uses
/// and later for debug builds use dynamic_cast.
///
template <typename D, typename B>
constexpr D downcast(B && b) noexcept
{
static_assert((std::is_pointer<D>::value && std::is_pointer<B>::value)
|| (std::is_reference<D>::value && std::is_reference<B>::value), "downcast only supports pointers or reference for derived");
return static_cast<D>(std::forward<B>(b));
}
using pgsl::narrow_cast;
/// \brief cast to void *
///
/// The purpose of void_ptr_cast is to help identify casts to void in the code.
///
template <typename T>
constexpr void * void_ptr_cast(T *ptr) noexcept { return static_cast<void *>(ptr); }
} // namespace plib
//FIXME: This is the place to use more complete implementations
namespace gsl = plib::pgsl;
#endif // PGSL_H_
|