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