/
cpp-util.hh
173 lines (146 loc) · 4.76 KB
/
cpp-util.hh
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
#ifndef __CPP_UTIL_HH
#define __CPP_UTIL_HH
#include <array>
#include <cstdarg>
#include <cstdlib>
#include <memory>
#include <type_traits>
#include <semaphore.h>
#if defined (ANDROID)
#include <android/log.h>
#else
#include <cstdio>
#endif
#include "cppcompat.hh"
#include "platform-compat.hh"
static inline void
do_abort_unless (bool condition, const char* fmt, ...)
{
if (XA_LIKELY (condition)) {
return;
}
va_list ap;
va_start (ap, fmt);
#if defined (ANDROID)
__android_log_vprint (ANDROID_LOG_FATAL, "monodroid", fmt, ap);
#else // def ANDROID
vfprintf (stderr, fmt, ap);
fprintf (stderr, "\n");
#endif // ndef ANDROID
va_end (ap);
std::abort ();
}
#define abort_unless(_condition_, _fmt_, ...) do_abort_unless (_condition_, "%s:%d (%s): " _fmt_, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
#define abort_if_invalid_pointer_argument(_ptr_) abort_unless ((_ptr_) != nullptr, "Parameter '%s' must be a valid pointer", #_ptr_)
#define abort_if_negative_integer_argument(_arg_) abort_unless ((_arg_) > 0, "Parameter '%s' must be larger than 0", #_arg_)
namespace xamarin::android
{
template <typename T>
struct CDeleter final
{
void operator() (T* p)
{
std::free (p);
}
};
template <typename T>
using c_unique_ptr = std::unique_ptr<T, CDeleter<T>>;
template<size_t Size>
struct helper_char_array final
{
constexpr char* data () noexcept
{
return _elems;
}
constexpr const char* data () const noexcept
{
return _elems;
}
constexpr char const& operator[] (size_t n) const noexcept
{
return _elems[n];
}
constexpr char& operator[] (size_t n) noexcept
{
return _elems[n];
}
char _elems[Size]{};
};
// MinGW 9 on the CI build bots has a bug in the gcc compiler which causes builds to fail with:
//
// error G713F753E: ‘constexpr auto xamarin::android::concat_const(const char (&)[Length]...) [with long long unsigned int ...Length = {15, 7, 5}]’ called in a constant expression
// ...
// /usr/lib/gcc/x86_64-w64-mingw32/9.3-win32/include/c++/array:94:12: note: ‘struct std::array<char, 17>’ has no user-provided default constructor
// struct array
// ^~~~~
// /usr/lib/gcc/x86_64-w64-mingw32/9.3-win32/include/c++/array:110:56: note: and the implicitly-defined constructor does not initialize ‘char std::array<char, 17>::_M_elems [17]’
// typename _AT_Type::_Type _M_elems;
// ^~~~~~~~
//
// thus we need to use this workaround here
//
#if defined (__MINGW32__) && __GNUC__ < 10
template<size_t Size>
using char_array = helper_char_array<Size>;
#else
template<size_t Size>
using char_array = std::array<char, Size>;
#endif
template<size_t ...Length>
constexpr auto concat_const (const char (&...parts)[Length])
{
// `parts` being constant string arrays, Length for each of them includes the trailing NUL byte, thus the
// `sizeof... (Length)` part which subtracts the number of template parameters - the amount of NUL bytes so that
// we don't waste space.
constexpr size_t total_length = (... + Length) - sizeof... (Length);
char_array<total_length + 1> ret;
ret[total_length] = 0;
size_t i = 0;
for (char const* from : {parts...}) {
for (; *from != '\0'; i++) {
ret[i] = *from++;
}
}
return ret;
};
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum operator & (TEnum l, TEnum r) noexcept
{
using etype = std::underlying_type_t<TEnum>;
return static_cast<TEnum>(static_cast<etype>(l) & static_cast<etype>(r));
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum& operator &= (TEnum& l, TEnum r) noexcept
{
return l = (l & r);
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum operator | (TEnum l, TEnum r) noexcept
{
using etype = std::underlying_type_t<TEnum>;
return static_cast<TEnum>(static_cast<etype>(l) | static_cast<etype>(r));
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum& operator |= (TEnum& l, TEnum r) noexcept
{
return l = (l | r);
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum operator ~ (TEnum r) noexcept
{
using etype = std::underlying_type_t<TEnum>;
return static_cast<TEnum> (~static_cast<etype>(r));
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum operator ^ (TEnum l, TEnum r) noexcept
{
using etype = std::underlying_type_t<TEnum>;
return static_cast<TEnum>(static_cast<etype>(l) ^ static_cast<etype>(r));
}
template <typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
constexpr TEnum& operator ^= (TEnum& l, TEnum r) noexcept
{
return l = (l ^ r);
}
}
#endif // !def __CPP_UTIL_HH