forked from Lasercake/Lasercake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.hpp
232 lines (199 loc) · 8.6 KB
/
config.hpp
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
228
229
230
231
232
/*
Copyright Eli Dupree and Isaac Dupree, 2011, 2012, 2013
This file is part of Lasercake.
Lasercake is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Lasercake is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Lasercake. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LASERCAKE_CONFIG_HPP__
#define LASERCAKE_CONFIG_HPP__
#include <inttypes.h>
#include <assert.h>
#include <stdexcept>
#include <boost/throw_exception.hpp>
#include <streambuf>
#include <ostream>
// Some asserts take too much runtime to turn on by default.
// So write them "maybe_assert(x);"
// Build with -DCANNY=ON to turn them on.
#ifdef CANNY
// By not using parentheses (e.g. not "#define maybe_assert(x) assert(x)"),
// we prevent any additional unintended macro-expansion,
// which in the case of assert would affect the string
// that is printed when the assert fails.
#define maybe_assert assert
const bool canny = true;
#else
// Make sure the code takes no runtime (the compiler will optimize it out)
// but that it still compiles to a boolean expression (so that turning on
// CANNY is sure to compile even if we didn't test with it on
// recently).
#define maybe_assert(x) ((true) ? (void)0 : ((x) ? (void)0 : (void)0))
const bool canny = false;
#endif
#ifndef LASERCAKE_BUILD_SYSTEM_DID_FEATURE_DETECTION
#ifndef ATTRIBUTE_NORETURN
// from http://www.boost.org/doc/libs/1_48_0/boost/exception/detail/attribute_noreturn.hpp
#if defined(_MSC_VER)
#define ATTRIBUTE_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define ATTRIBUTE_NORETURN __attribute__((noreturn))
#else
#define ATTRIBUTE_NORETURN
#endif
#endif
#if defined(__EMSCRIPTEN__)
#if BOOST_NO_EXCEPTIONS != 1
#warning "Emscripten works better if exceptions are disabled"
#endif
#endif
#if defined(__GNUC__)
inline int DETECTED_builtin_clz64(uint64_t arg) {
static_assert(sizeof(unsigned int) == 8 || sizeof(unsigned long) == 8 || sizeof(unsigned long long) == 8, "no 64-bit builtin uint type?!");
return
(sizeof(unsigned int) == 8) ? __builtin_clz(arg) :
(sizeof(unsigned long) == 8) ? __builtin_clzl(arg) :
__builtin_clzll(arg);
}
inline int DETECTED_builtin_clz32(uint32_t arg) {
static_assert(sizeof(unsigned int) == 4 || sizeof(unsigned long) == 4 || sizeof(unsigned long long) == 4, "no 32-bit builtin uint type?!");
return
(sizeof(unsigned int) == 4) ? __builtin_clz(arg) :
(sizeof(unsigned long) == 4) ? __builtin_clzl(arg) :
__builtin_clzll(arg);
}
inline int DETECTED_builtin_ctz64(uint64_t arg) {
static_assert(sizeof(unsigned int) == 8 || sizeof(unsigned long) == 8 || sizeof(unsigned long long) == 8, "no 64-bit builtin uint type?!");
return
(sizeof(unsigned int) == 8) ? __builtin_ctz(arg) :
(sizeof(unsigned long) == 8) ? __builtin_ctzl(arg) :
__builtin_ctzll(arg);
}
inline int DETECTED_builtin_ctz32(uint32_t arg) {
static_assert(sizeof(unsigned int) == 4 || sizeof(unsigned long) == 4 || sizeof(unsigned long long) == 4, "no 32-bit builtin uint type?!");
return
(sizeof(unsigned int) == 4) ? __builtin_ctz(arg) :
(sizeof(unsigned long) == 4) ? __builtin_ctzl(arg) :
__builtin_ctzll(arg);
}
#define DETECTED_builtin_clz64 DETECTED_builtin_clz64
#define DETECTED_builtin_clz32 DETECTED_builtin_clz32
#define DETECTED_builtin_ctz64 DETECTED_builtin_ctz64
#define DETECTED_builtin_ctz32 DETECTED_builtin_ctz32
#endif
// This is a conservative poor way of guessing, that probably works for
// most current machines/systems (but not for all compilers!)
#if defined(__GNUC__) && (__LP64__ || __x86_64__)
#define DETECTED_int128_t __int128_t
#define DETECTED_uint128_t __uint128_t
#define LASERCAKE_HAVE_64_BITS 1
#define LASERCAKE_HAVE_128_BIT_INT 1
#endif
#if (!__clang__ && !BOOST_INTEL && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)))
#define LASERCAKE_GCC_LESS_THAN_4_7 1
#endif
#if LASERCAKE_GCC_LESS_THAN_4_7
#define override
#endif
/*#if defined(__GNUC__)
// current compilers (e.g. GCC 4.7, Clang 3.1) don't seem to support the 'thread_local' C++11 name
#define thread_local __thread
#endif*/
// Don't use LASERCAKE_IT_SEEMS_TO_BE_WINDOWS outside this fake feature
// detection section if you can help it! Ask about specific features
// instead.
#define LASERCAKE_IT_SEEMS_TO_BE_WINDOWS \
((defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(__CYGWIN__))
#if !LASERCAKE_IT_SEEMS_TO_BE_WINDOWS
// TODO use GetProcessMemoryInfo or the like on Windows, if we care enough
#define LASERCAKE_HAVE_SYS_RESOURCE_H 1
#endif
#endif
// (not enabled unless you enable it) #define USE_BOUNDS_CHECKED_INTS 1
namespace boost {
ATTRIBUTE_NORETURN void throw_exception(std::exception const& e);
}
// It's not polite for library functions to assert() because the library's users
// misused a correct library; use these for that case.
inline ATTRIBUTE_NORETURN void caller_error(const char* error) {
// If exceptions prove worse for debugging than asserts/segfaults,
// feel free to comment this out and use asserts/segfaults/breakpoints.
boost::throw_exception(std::logic_error(error));
}
// You must provide an explanatory string so that the user of the library
// will know what *they* did wrong, and not have to interpret an assert() expression
// to find out.
inline void caller_error_if(bool cond, const char* error) {
if(cond) {
caller_error(error);
}
}
inline void caller_correct_if(bool cond, const char* error) {
if(!cond) {
caller_error(error);
}
}
// This has to be a non-function because ret should only
// be evaluated if cond is true.
#define constexpr_require_and_return(cond, str, ret) ((cond) ? (ret) : throw std::logic_error((str)))
// This has to be a non-function so that the compiler can deduce its
// return type as anything for use in ?: results. It has to be
// non-parenthesized because Clang, at least, will cast it to void
// (rather than its magic whatever-the-other-thing-in-the-?:-is type)
// if parenthesized.
#define constexpr_caller_error(str) throw std::logic_error((str))
#if DEBUG_PRINT_DETERMINISTICALLY
#include "debug_print_deterministically.hpp"
#endif
namespace logger_impl {
class log_buf : public std::streambuf {
static const std::streamsize bufsize_ = 200;
char buf_[bufsize_];
void write_buf_();
public:
log_buf() { setp(buf_, buf_ + bufsize_); }
~log_buf() { if(pptr() != pbase()) { write_buf_(); }}
std::streamsize xsputn(const char* s, std::streamsize n) override;
int_type overflow(int_type ch) override;
int sync() override { write_buf_(); return 0; }
};
class log {
log_buf streambuf_;
std::ostream os_;
public:
// The constructor and destructor generate too much code
// (including multiple function calls) to be worth inlining.
log();
~log();
template<typename SomethingOutputted>
inline std::ostream& operator<<(SomethingOutputted&& output) { return os_ << output; }
// Apparently the compiler can't deduce SomethingOutputted when it's
// a function (such as std::endl), so we have to list these overloads too.
inline std::ostream& operator<<(std::ios_base& (*output)(std::ios_base&)) { return os_ << output; }
inline std::ostream& operator<<(std::ios& (*output)(std::ios&)) { return os_ << output; }
inline std::ostream& operator<<(std::ostream& (*output)(std::ostream&)) { return os_ << output; }
// it's not meant to be copied/moved/anything
log(log const&) = delete;
log& operator=(log const&) = delete;
log(log&&) = delete;
log& operator=(log&&) = delete;
};
}
// Usage:
// LOG << this << that << std::hex << the other thing << "\n";
// Constructs a temporary buffer on the stack, used to log the
// data to stderr. Flushes data when destroyed (typically at the
// next sequence point: the end of the statement) and/or, when
// you send it std::flush or std::endl, and/or whenever its buffer
// fills up.
// On output I/O errors, this simply gives up and pretends to have been
// successful.
#define LOG (::logger_impl::log())
#endif