1 /*****************************************************************************
2 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU Lesser General Public License as *
6 * published by the Free Software Foundation; either version 2.1 of the *
7 * License, or (at your option) version 3, or any later version accepted *
8 * by the membership of KDE e.V. (or its successor approved by the *
9 * membership of KDE e.V.), which shall act as a proxy defined in *
10 * Section 6 of version 3 of the license. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with this library. If not, *
19 * see <http://www.gnu.org/licenses/>. *
20 *****************************************************************************/
21
22 #ifndef _QTC_UTILS_UTILS_H_
23 #define _QTC_UTILS_UTILS_H_
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <math.h>
31
32 #include "macros.h"
33
34 #include <memory>
35 #include <utility>
36 #include <type_traits>
37 #include <initializer_list>
38
39 /**
40 * \file utils.h
41 * \author Yichao Yu <yyc1992@gmail.com>
42 * \brief Some generic functions and macros.
43 */
44
45 /**
46 * Generic call back function.
47 */
48 typedef void (*QtcCallback)(void*);
49
50 /**
51 * Allocate memory and initialize it to zero.
52 * \param size size of the memory
53 */
54 QTC_ALWAYS_INLINE static inline void*
qtcAlloc0(size_t size)55 qtcAlloc0(size_t size)
56 {
57 void *p = malloc(size);
58 memset(p, 0, size);
59 return p;
60 }
61
62 /**
63 * Allocate memory of size \param size for a \param type.
64 * The memory is initialized to zero.
65 * \param type type pointed to by the pointer
66 * \param size size of the memory
67 * \sa qtcAlloc0
68 */
69 #define qtcNewSize(type, size) ((type*)qtcAlloc0(size))
70
71 /**
72 * Allocate memory for a \param type or an array of \param type.
73 * The memory is initialized to zero.
74 * \param type type pointed to by the pointer
75 * \param n (optional) elements in the array (default: 1)
76 * \sa qtcNewSize
77 */
78 #define qtcNew(type, n...) \
79 qtcNewSize(type, sizeof(type) * (QTC_DEFAULT(n, 1)))
80
81 namespace QtCurve {
82
83 template<typename T>
84 using remove_cvr_t = typename std::remove_cv<
85 typename std::remove_reference<T>::type>::type;
86
87 template<typename T>
88 struct _isChar : std::is_same<remove_cvr_t<T>, char> {};
89
90 template<typename T>
91 struct _isCharPtr : std::integral_constant<
92 bool,
93 std::is_pointer<remove_cvr_t<T> >::value &&
94 _isChar<typename std::remove_pointer<remove_cvr_t<T> >::type>::value> {};
95
96 template<typename T>
97 struct _isCharAry : std::integral_constant<
98 bool,
99 std::is_array<remove_cvr_t<T> >::value &&
100 _isChar<typename std::remove_extent<remove_cvr_t<T> >::type>::value> {};
101
102 template<typename T>
103 struct _isCharStr : std::integral_constant<
104 bool, _isCharPtr<T>::value || _isCharAry<T>::value> {};
105
106 template<typename T1, typename T2, class=void>
107 struct _oneOfCmp {
operator_oneOfCmp108 inline bool operator()(T1 &&v1, T2 &&v2)
109 {
110 return std::forward<T1>(v1) == std::forward<T2>(v2);
111 }
112 };
113
114 template<typename T1, typename T2>
115 struct _oneOfCmp<T1, T2, typename std::enable_if<_isCharStr<T1>::value &&
116 _isCharStr<T2>::value>::type> {
117 inline bool operator()(T1 &&v1, T2 &&v2)
118 {
119 return v1 && strcmp(v1, v2) == 0;
120 }
121 };
122
123 template<typename...>
124 struct CaseCmp {
125 inline bool operator()(const char *str1, const char *str2)
126 {
127 return str1 && strcasecmp(str1, str2) == 0;
128 }
129 };
130
131 template<template<typename...> class _Cmp=_oneOfCmp,
132 typename T1, typename T2>
133 static inline bool
134 oneOf(T1 &&v1, T2 &&v2)
135 {
136 return _Cmp<T1, T2>()(std::forward<T1>(v1), std::forward<T2>(v2));
137 }
138
139 template<template<typename...> class _Cmp=_oneOfCmp,
140 typename T, typename First, typename... Rest>
141 static inline bool
142 oneOf(T &&value, First &&first, Rest&&... rest)
143 {
144 return (oneOf<_Cmp>(std::forward<T>(value), std::forward<First>(first)) ||
145 oneOf<_Cmp>(std::forward<T>(value), std::forward<Rest>(rest)...));
146 }
147
148 template<template<typename...> class _Cmp=_oneOfCmp,
149 typename... Args>
150 static inline bool
151 noneOf(Args&&... args)
152 {
153 return !oneOf<_Cmp>(std::forward<Args>(args)...);
154 }
155
156 /**
157 * Turn a variable into a const reference. This is useful for range-based for
158 * loop where a non-const variable may cause unnecessary copy.
159 */
160 template <class T>
161 static inline const T&
162 const_(const T &t)
163 {
164 return t;
165 }
166
167 struct CDeleter {
168 template<typename T>
169 void operator()(T *p)
170 {
171 free((void*)p);
172 }
173 };
174
175 template<typename T>
176 using uniqueCPtr = std::unique_ptr<T, CDeleter>;
177
178 template<typename T, size_t N>
179 class LocalBuff {
180 LocalBuff(const LocalBuff&) = delete;
181 public:
182 LocalBuff(size_t size=N, const T *ary=nullptr)
183 : m_ptr(size > N ? qtcNew(T, size) : m_static_buf),
184 m_size(size),
185 m_static_buf{}
186 {
187 if (ary) {
188 memcpy(m_ptr, ary, sizeof(T) * size);
189 }
190 }
191 bool
192 is_static() const
193 {
194 return m_ptr == m_static_buf;
195 }
196 void
197 resize(size_t size)
198 {
199 if (is_static()) {
200 if (size > N) {
201 m_ptr = qtcNew(T, size);
202 memcpy(m_ptr, m_static_buf, sizeof(T) * m_size);
203 }
204 } else {
205 m_ptr = (T*)realloc(m_ptr, sizeof(T) * size);
206 }
207 m_size = size;
208 }
209 T*
210 get() const
211 {
212 return m_ptr;
213 }
214 T&
215 operator[](size_t i) const
216 {
217 return get()[i];
218 }
219 size_t
220 size() const
221 {
222 return m_size;
223 }
224 ~LocalBuff()
225 {
226 if (!is_static()) {
227 free(m_ptr);
228 }
229 }
230 protected:
231 T *m_ptr;
232 size_t m_size;
233 private:
234 T m_static_buf[N];
235 };
236
237 const char *getProgName();
238 }
239
240 extern "C" const char *qtcVersion();
241
242 template<typename T>
243 using qtcPtrType = QtCurve::remove_cvr_t<typename std::remove_pointer<T>::type>;
244
245 #define qtcMemPtr(ptr, name) &qtcPtrType<decltype(ptr)>::name
246
247 // Use lambda for lazy evaluation of \param def
248 #define qtcDefault(val, def) ([&] { \
249 auto __val = (val); \
250 return __val ? __val : (def); \
251 }())
252 // Use lambda for lazy evaluation of \param args
253 // C++ allows returning void expression! =) See the quote of the standard
254 // (here)[http://gcc.gnu.org/ml/gcc/2006-10/msg00697.html]
255 // The current c++ implementation of this macro does not support functions
256 // with types that do not have accessible default constructor (including
257 // references) as return type.
258 #define qtcCall(func, args...) ([&] { \
259 auto __func = (func); \
260 return __func ? __func(args) : decltype(__func(args))(); \
261 }())
262 #define qtcAssign(addr, exp) do { \
263 auto __addr = (addr); \
264 if (__addr) { \
265 *__addr = (exp); \
266 } \
267 } while(0)
268
269 // Returning a void expression is valid c++, see above
270 // Or https://gcc.gnu.org/ml/gcc/2006-10/msg00697.html
271 #define QTC_RET_IF_FAIL(exp, val...) do { \
272 if (!qtcLikely(exp)) { \
273 return (QTC_DEFAULT(val, (void)0)); \
274 } \
275 } while (0)
276
277 #endif
278