forked from toroidal-code/cppspec
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.hpp
More file actions
executable file
·227 lines (194 loc) · 6.25 KB
/
Copy pathutil.hpp
File metadata and controls
executable file
·227 lines (194 loc) · 6.25 KB
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/**
* @file
* @brief Utility functions and classes
*/
#ifndef CPPSPEC_UTIL_HPP
#define CPPSPEC_UTIL_HPP
#pragma once
#include <string>
#include <sstream>
#include <functional>
#ifdef __GNUG__
#include <cxxabi.h>
#include <memory>
#endif
namespace CppSpec {
namespace Util {
/**
* Demangle a symbol into a human-readable string.
*
* @param mangled the mangled symbol
*
* @return a human-readable translation of the given symbol
*/
#ifdef __GNUG__
inline std::string demangle(const char *mangled) {
int status;
std::unique_ptr<char[], void (*)(void *)> result{
abi::__cxa_demangle(mangled, NULL, NULL, &status), std::free};
return (status == 0) ? result.get() : mangled;
}
#else
inline std::string demangle(const char *name) { return name; }
#endif
/**
* @brief Helper class for static assertions that has a built-in error string.
*/
template <class A>
struct verbose_assert {
static_assert(A::value, "Assertion failed (see below for more information)");
static bool const value = A::value;
};
template <typename T>
struct is_true : public std::is_same<std::true_type, T> {};
template <typename T>
struct is_false : public std::is_same<std::false_type, T> {};
/**
* @brief Functions for testing if a class is iterable
*/
namespace is_iterable_imp {
template <class C>
auto test(void *) -> decltype(std::declval<C>().begin(),
std::declval<C>().end(), std::true_type{});
template <class C>
auto test(int) -> decltype(std::declval<C>().cbegin(), std::declval<C>().cend(),
std::true_type{});
template <class>
auto test(...) -> std::false_type;
} // namespace is_iterable_imp
/**
* @brief Checks whether T is an iterable type.
*
* Provides the member constant value which is equal
* to `true`, if T is an iterable type. Otherwise,
* value is equal to `false`.
*
* @tparam T a type to check
*/
template <class T>
class is_iterable : public decltype(is_iterable_imp::test<T>(0)) {};
/** @brief Helper variable template for is_iterable. */
#ifdef HAS_VARIABLE_TEMPLATES
template <class T>
constexpr bool is_iterable_v = is_iterable<T>::value;
#endif
/**
* @brief Functions for testing if a class is a container
*/
namespace is_container_imp {
template <class C>
auto test(void *) -> decltype(std::declval<C>().max_size(),
std::declval<C>().empty(), is_iterable<C>{});
template <class>
auto test(...) -> std::false_type;
} // namespace is_container_imp
/**
* @brief Checks whether T is a container type.
*
* Provides the member constant value which is equal
* to `true`, if T is a container type. Otherwise,
* value is equal to `false`.
*
* A container is defined by having the functions
* `begin`, `end`, `max_size`, and `empty`.
*
* @tparam T a type to check
*/
template <class T>
struct is_container : public decltype(is_container_imp::test<T>(0)) {};
/** @brief Helper variable template for is_container. */
#ifdef HAS_VARIABLE_TEMPLATES
template <class T>
constexpr bool is_container_v = is_container<T>::value;
#endif
/**
* @brief Functions for testing if a class can be streamed
*/
namespace is_streamable_imp {
template <typename C>
auto test(void *) -> std::is_same<
// check for operator<< in std::ostream first (fundamental types)
decltype(std::declval<std::ostream>().operator<<(std::declval<C>())),
std::ostream &>;
template <class C>
auto test(int) -> std::is_same<
// check for an operator<< via SFINAE
decltype(operator<<(std::declval<std::ostream &>(),
std::declval<C const &>())),
std::ostream & // make sure the return type is ostream&
>;
template <class>
auto test(...) -> std::false_type; // fallthrough
} // namespace is_streamable_imp
/**
* @brief Checks whether T can be streamed.
*
* Provides the member constant value which is equal
* to `true`, if T is a streamable type. Otherwise,
* value is equal to `false`.
*
* A streamable type is defined by having the operator<<
* defined in scope.
*
* @tparam T a type to check
*/
template <class T>
struct is_streamable : public decltype(is_streamable_imp::test<T>(0)) {};
/** @brief Helper variable template for is_container. */
#ifdef HAS_VARIABLE_TEMPLATES
template <class T>
constexpr bool is_streamable_v = is_streamable<T>::value;
#endif
/**
* @brief Functions for testing if a class can be streamed
*/
namespace is_functional_imp {
// The C++ reference says that all "functions" (not FunctionObjects) respond to
// std::is_function<T>
template <typename C>
auto test(void *) -> std::is_function<C>;
// It also says that something qualifies as a FunctionObject iff
// std::is_object<T> is true and the object responds to the call operator()
// however, we pass it over in favor of the next option.
// template <class C>
// auto test(int) -> decltype(std::is_object<C>{}, void(std::declval<C>()()),
// std::true_type{});
// An alternative from Stack Overflow question 18107368. Anything that could
// possibly be "functional" should be able to be cast to std::function<void()>
template <class C>
auto test(int) -> std::is_convertible<C, std::function<void()>>;
template <class C>
auto test(...) -> std::false_type; // fallthrough
} // namespace is_functional_imp
template <class T>
struct is_functional : public decltype(is_functional_imp::test<T>(0)) {};
/** @brief Helper variable template for is_container. */
#ifdef HAS_VARIABLE_TEMPLATES
template <class T>
constexpr bool is_functional_v = is_functional<T>::value;
#endif
/**
* @brief Implode a string
*
* @tparam Range the type of the iterable object. is_iterable<Range>::value
* must evaluate to true.
* @param iterable an iterable object
* @param separator a user-defined separator to delimit elements
*
* @return the joined string
*/
template <typename Range>
inline std::string join(Range &iterable, const std::string &separator = "") {
std::ostringstream oss;
typename Range::const_iterator it;
for (it = iterable.cbegin(); it != iterable.cend();) {
oss << *it; // use operator<< to convert and append
// Hacky way to get around forward_list singly-linked problem:
// increment the iterator here, compare and then continue.
if (++it != iterable.cend()) oss << separator;
}
return oss.str();
}
} // namespace Util
} // namespace CppSpec
#endif // CPPSPEC_UTIL_HPP