File indexing completed on 2024-04-28 05:46:51

0001 /*****************************************************************************
0002  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0003  *                                                                           *
0004  *   This program is free software; you can redistribute it and/or modify    *
0005  *   it under the terms of the GNU Lesser General Public License as          *
0006  *   published by the Free Software Foundation; either version 2.1 of the    *
0007  *   License, or (at your option) version 3, or any later version accepted   *
0008  *   by the membership of KDE e.V. (or its successor approved by the         *
0009  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0010  *   Section 6 of version 3 of the license.                                  *
0011  *                                                                           *
0012  *   This program is distributed in the hope that it will be useful,         *
0013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0015  *   Lesser General Public License for more details.                         *
0016  *                                                                           *
0017  *   You should have received a copy of the GNU Lesser General Public        *
0018  *   License along with this library. If not,                                *
0019  *   see <http://www.gnu.org/licenses/>.                                     *
0020  *****************************************************************************/
0021 
0022 #ifndef _QTC_UTILS_UTILS_H_
0023 #define _QTC_UTILS_UTILS_H_
0024 
0025 #include <stdint.h>
0026 #include <string.h>
0027 #include <stdlib.h>
0028 #include <stdio.h>
0029 #include <stddef.h>
0030 #include <math.h>
0031 
0032 #include "macros.h"
0033 
0034 #include <memory>
0035 #include <utility>
0036 #include <type_traits>
0037 #include <initializer_list>
0038 
0039 /**
0040  * \file utils.h
0041  * \author Yichao Yu <yyc1992@gmail.com>
0042  * \brief Some generic functions and macros.
0043  */
0044 
0045 /**
0046  * Generic call back function.
0047  */
0048 typedef void (*QtcCallback)(void*);
0049 
0050 /**
0051  * Allocate memory and initialize it to zero.
0052  * \param size size of the memory
0053  */
0054 QTC_ALWAYS_INLINE static inline void*
0055 qtcAlloc0(size_t size)
0056 {
0057     void *p = malloc(size);
0058     memset(p, 0, size);
0059     return p;
0060 }
0061 
0062 /**
0063  * Allocate memory of size \param size for a \param type.
0064  * The memory is initialized to zero.
0065  * \param type type pointed to by the pointer
0066  * \param size size of the memory
0067  * \sa qtcAlloc0
0068  */
0069 #define qtcNewSize(type, size) ((type*)qtcAlloc0(size))
0070 
0071 /**
0072  * Allocate memory for a \param type or an array of \param type.
0073  * The memory is initialized to zero.
0074  * \param type type pointed to by the pointer
0075  * \param n (optional) elements in the array (default: 1)
0076  * \sa qtcNewSize
0077  */
0078 #define qtcNew(type, n...)                              \
0079     qtcNewSize(type, sizeof(type) * (QTC_DEFAULT(n, 1)))
0080 
0081 namespace QtCurve {
0082 
0083 template<typename T>
0084 using remove_cvr_t = typename std::remove_cv<
0085     typename std::remove_reference<T>::type>::type;
0086 
0087 template<typename T>
0088 struct _isChar : std::is_same<remove_cvr_t<T>, char> {};
0089 
0090 template<typename T>
0091 struct _isCharPtr : std::integral_constant<
0092     bool,
0093     std::is_pointer<remove_cvr_t<T> >::value &&
0094     _isChar<typename std::remove_pointer<remove_cvr_t<T> >::type>::value> {};
0095 
0096 template<typename T>
0097 struct _isCharAry : std::integral_constant<
0098     bool,
0099     std::is_array<remove_cvr_t<T> >::value &&
0100     _isChar<typename std::remove_extent<remove_cvr_t<T> >::type>::value> {};
0101 
0102 template<typename T>
0103 struct _isCharStr : std::integral_constant<
0104     bool, _isCharPtr<T>::value || _isCharAry<T>::value> {};
0105 
0106 template<typename T1, typename T2, class=void>
0107 struct _oneOfCmp {
0108     inline bool operator()(T1 &&v1, T2 &&v2)
0109     {
0110         return std::forward<T1>(v1) == std::forward<T2>(v2);
0111     }
0112 };
0113 
0114 template<typename T1, typename T2>
0115 struct _oneOfCmp<T1, T2, typename std::enable_if<_isCharStr<T1>::value &&
0116                                       _isCharStr<T2>::value>::type> {
0117     inline bool operator()(T1 &&v1, T2 &&v2)
0118     {
0119         return v1 && strcmp(v1, v2) == 0;
0120     }
0121 };
0122 
0123 template<typename...>
0124 struct CaseCmp {
0125     inline bool operator()(const char *str1, const char *str2)
0126     {
0127         return str1 && strcasecmp(str1, str2) == 0;
0128     }
0129 };
0130 
0131 template<template<typename...> class _Cmp=_oneOfCmp,
0132          typename T1, typename T2>
0133 static inline bool
0134 oneOf(T1 &&v1, T2 &&v2)
0135 {
0136     return _Cmp<T1, T2>()(std::forward<T1>(v1), std::forward<T2>(v2));
0137 }
0138 
0139 template<template<typename...> class _Cmp=_oneOfCmp,
0140          typename T, typename First, typename... Rest>
0141 static inline bool
0142 oneOf(T &&value, First &&first, Rest&&... rest)
0143 {
0144     return (oneOf<_Cmp>(std::forward<T>(value), std::forward<First>(first)) ||
0145             oneOf<_Cmp>(std::forward<T>(value), std::forward<Rest>(rest)...));
0146 }
0147 
0148 template<template<typename...> class _Cmp=_oneOfCmp,
0149          typename... Args>
0150 static inline bool
0151 noneOf(Args&&... args)
0152 {
0153     return !oneOf<_Cmp>(std::forward<Args>(args)...);
0154 }
0155 
0156 /**
0157  * Turn a variable into a const reference. This is useful for range-based for
0158  * loop where a non-const variable may cause unnecessary copy.
0159  */
0160 template <class T>
0161 static inline const T&
0162 const_(const T &t)
0163 {
0164     return t;
0165 }
0166 
0167 struct CDeleter {
0168     template<typename T>
0169     void operator()(T *p)
0170     {
0171         free((void*)p);
0172     }
0173 };
0174 
0175 template<typename T>
0176 using uniqueCPtr = std::unique_ptr<T, CDeleter>;
0177 
0178 template<typename T, size_t N>
0179 class LocalBuff {
0180     LocalBuff(const LocalBuff&) = delete;
0181 public:
0182     LocalBuff(size_t size=N, const T *ary=nullptr)
0183         : m_ptr(size > N ? qtcNew(T, size) : m_static_buf),
0184           m_size(size),
0185           m_static_buf{}
0186     {
0187         if (ary) {
0188             memcpy(m_ptr, ary, sizeof(T) * size);
0189         }
0190     }
0191     bool
0192     is_static() const
0193     {
0194         return m_ptr == m_static_buf;
0195     }
0196     void
0197     resize(size_t size)
0198     {
0199         if (is_static()) {
0200             if (size > N) {
0201                 m_ptr = qtcNew(T, size);
0202                 memcpy(m_ptr, m_static_buf, sizeof(T) * m_size);
0203             }
0204         } else {
0205             m_ptr = (T*)realloc(m_ptr, sizeof(T) * size);
0206         }
0207         m_size = size;
0208     }
0209     T*
0210     get() const
0211     {
0212         return m_ptr;
0213     }
0214     T&
0215     operator[](size_t i) const
0216     {
0217         return get()[i];
0218     }
0219     size_t
0220     size() const
0221     {
0222         return m_size;
0223     }
0224     ~LocalBuff()
0225     {
0226         if (!is_static()) {
0227             free(m_ptr);
0228         }
0229     }
0230 protected:
0231     T *m_ptr;
0232     size_t m_size;
0233 private:
0234     T m_static_buf[N];
0235 };
0236 
0237 const char *getProgName();
0238 }
0239 
0240 extern "C" const char *qtcVersion();
0241 
0242 template<typename T>
0243 using qtcPtrType = QtCurve::remove_cvr_t<typename std::remove_pointer<T>::type>;
0244 
0245 #define qtcMemPtr(ptr, name) &qtcPtrType<decltype(ptr)>::name
0246 
0247 // Use lambda for lazy evaluation of \param def
0248 #define qtcDefault(val, def) ([&] {             \
0249             auto __val = (val);                 \
0250             return __val ? __val : (def);       \
0251         }())
0252 // Use lambda for lazy evaluation of \param args
0253 // C++ allows returning void expression! =) See the quote of the standard
0254 // (here)[http://gcc.gnu.org/ml/gcc/2006-10/msg00697.html]
0255 // The current c++ implementation of this macro does not support functions
0256 // with types that do not have accessible default constructor (including
0257 // references) as return type.
0258 #define qtcCall(func, args...) ([&] {                                   \
0259             auto __func = (func);                                       \
0260             return __func ? __func(args) : decltype(__func(args))();    \
0261         }())
0262 #define qtcAssign(addr, exp) do {               \
0263         auto __addr = (addr);                   \
0264         if (__addr) {                           \
0265             *__addr = (exp);                    \
0266         }                                       \
0267     } while(0)
0268 
0269 // Returning a void expression is valid c++, see above
0270 // Or https://gcc.gnu.org/ml/gcc/2006-10/msg00697.html
0271 #define QTC_RET_IF_FAIL(exp, val...) do {       \
0272         if (!qtcLikely(exp)) {                  \
0273             return (QTC_DEFAULT(val, (void)0)); \
0274         }                                       \
0275     } while (0)
0276 
0277 #if defined(__GNUC__) && __GNUC__ >= 7
0278 #  define QTC_FALLTHROUGH() __attribute__((fallthrough))
0279 #elif defined(__clang_major__) && defined(__clang_minor__) &&   \
0280     (__clang_major__ > 4 || __clang_minor__ >= 5)
0281 // We require at least clang 3.x for c++11
0282 #  define QTC_FALLTHROUGH() [[clang::fallthrough]]
0283 #else
0284 #  define QTC_FALLTHROUGH()
0285 #endif
0286 
0287 #endif