-
Notifications
You must be signed in to change notification settings - Fork 3
/
misc.h
179 lines (160 loc) · 5.36 KB
/
misc.h
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
/*
Miscellaneous helpers from various sources
*/
#ifndef MISC_H
#define MISC_H
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
template<typename Val>
struct count_type {
template<typename... Args>
struct in : std::integral_constant<std::size_t, 0> {};
template<typename... Args>
struct in<Val, Args...> : std::integral_constant<std::size_t, 1 + in<Args...>::value> {};
template<typename NotVal, typename... Args>
struct in<NotVal, Args...> : std::integral_constant<std::size_t, in<Args...>::value> {};
};
template<typename Valtype, Valtype Val>
struct count_value {
template<Valtype... Args>
struct in : std::integral_constant<std::size_t, 0> {};
template<Valtype... Args>
struct in<Val, Args...> : std::integral_constant<std::size_t, 1 + in<Args...>::value> {};
template<Valtype NotVal, Valtype... Args>
struct in<NotVal, Args...> : std::integral_constant<std::size_t, in<Args...>::value> {};
};
//
// Scope exit helper
// Call on scope exit (like finally)
// Example:
// FILE * fp = fopen("test.out", "wb");
// SCOPE_EXIT(fclose(fp));
//
template<typename F>
struct ScopeExit {
explicit ScopeExit(F f) : f(f) {}
~ScopeExit() { f(); }
F f;
};
template<typename F>
ScopeExit<F> MakeScopeExit(F f) {
return ScopeExit<F>(f);
};
#define SCOPE_EXIT(code) auto STRING_JOIN2(scope_exit_, __LINE__) = MakeScopeExit([=]() { code; })
//
// Some definitions of C++14+ constructs
//
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template<class T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
template<class C>
auto cbegin(const C& container) -> decltype(std::begin(container)) {
return std::begin(container);
}
template<class C>
auto cend(const C& container) -> decltype(std::end(container)) {
return std::end(container);
}
//
// Debug output
//
template<typename... Types>
void debug(Types... args);
template<typename Type1, typename... Types>
void debug(Type1 arg1, Types... rest) {
std::cout << typeid(arg1).name() << ": " << arg1 << std::endl;
debug(rest...);
}
template<>
void debug() {}
//
// Convenient constructor for std::array
// from https://a4z.bitbucket.io/blog/2017/01/19/A-convenient-constructor-for-std::array.html
//
template<typename... Args>
std::array<typename std::common_type<Args...>::type, sizeof...(Args)> array(Args&&... args) {
return std::array<typename std::common_type<Args...>::type, sizeof...(Args)>{std::forward<Args>(args)...};
}
//
// iterator-zip
//
template<typename... Args>
class ContainerBundle {
public:
using iterator = IteratorBundle<typename Args::iterator...>;
using iter_coll = std::tuple<typename Args::iterator...>;
explicit ContainerBundle(typename std::add_pointer<Args>::type... args) : dat{args...}, bg{args->begin()...}, nd{args->end()...} {}
~ContainerBundle() = default;
ContainerBundle(const ContainerBundle&) = delete;
ContainerBundle(ContainerBundle&&) = default;
inline iterator begin() { return bg; }
inline iterator end() const { return nd; }
private:
std::tuple<typename std::add_pointer<Args>::type...> dat;
iterator bg, nd;
};
template<typename... Itr>
class IteratorBundle {
public:
using value_type = std::tuple<typename Itr::value_type...>;
using internal_type = std::tuple<Itr...>;
IteratorBundle() = default; // etc.
bool operator==(const IteratorBundle& it) const { return loc == it.loc; }
// special implementation insisting that all
// elements in the bundle compare unequal. This ensures proper
// function for containers of different sizes.
bool operator!=(const IteratorBundle& it) const;
inline value_type operator*() { return deref(); }
inline IteratorBundle& operator++() {
advance_them<0, sizeof...(Itr)>::eval(loc);
return
}
template<bool... b>
struct static_all_of;
template<bool... tail>
struct static_all_of<true, tail...> : static_all_of<tail...> {};
// no need to look further if first argument is false
template<bool... tail>
struct static_all_of<false, tail...> : std::false_type {};
template<>
struct static_all_of<> : std::true_type {};
template<typename... Args>
ContainerBundle<typename std::remove_pointer<Args>::type...> zip(Args... args) {
static_assert(static_all_of<std::is_pointer<Args>::value...>::value, "Each argument to zip must be a pointer to a container! ");
return {args...};
}
};
//
// output stream << std::tuple
//
namespace details {
template<std::size_t i>
struct ostream_tuple_helper {
template<typename T>
static std::ostream& write(std::ostream& os, T&& t) {
return ostream_tuple_helper<i - 1>::write(os, t) << ", " << std::get<i - 1>(t);
}
};
template<>
struct ostream_tuple_helper<1> {
template<typename T>
static std::ostream& write(std::ostream& os, T&& t) {
return os << std::get<0>(t);
}
};
template<>
struct ostream_tuple_helper<0> {
template<typename T>
static std::ostream& write(std::ostream& os, T&& t) {
return os;
}
};
} // namespace details
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t) {
return details::ostream_tuple_helper<std::tuple_size<std::tuple<Args...>>::value>::write(os, t);
}
#endif