/*! \file pibase.h * \ingroup Core * \~\brief * \~english Base types and functions * \~russian Базовые типы и методы * * \~\details * \~english * This file implements first layer above the system and * declares some basic useful functions * \~russian * Этот файл реализует первый слой после системы и объявляет * несколько базовых полезных методов */ /* PIP - Platform Independent Primitives Base types and functions Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIBASE_H #define PIBASE_H #include "pibase_macros.h" #include "pimemoryblock.h" #include "pip_export.h" #include #ifdef CC_AVR_GCC # include #endif #include #include #include #include #include #include //! \~\brief //! \~english Global variable enabling output to piCout, default is true //! \~russian Глобальная переменная, включающая вывод в piCout, при старте true extern PIP_EXPORT bool piDebug; //! \~\brief //! \~english Global variable that set minimum real update interval //! for function PIInit::mountInfo(), default is 10000 ms //! \~russian Глобальная переменная минимального ожидания между реальным обновлением //! в методе PIInit::mountInfo(), по умолчанию 10000 мс extern PIP_EXPORT double piMountInfoRefreshIntervalMs; typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned long long ullong; typedef long long llong; typedef long double ldouble; //! \~\brief //! \~english Templated function for swap two values //! \~russian Шаблонный метод для перестановки двух значений //! \~\details //! \~english Example:\n \snippet piincludes.cpp swap //! \~russian Пример:\n \snippet piincludes.cpp swap template inline void piSwap(T & f, T & s) { T t(std::move(f)); f = std::move(s); s = std::move(t); } //! \~\brief //! \~english Templated function for swap two values without "=" //! \~russian Шаблонный метод для перестановки двух значений без использования "=" //! \~\details //! \~english Example:\n \snippet piincludes.cpp swapBinary //! \~russian Пример:\n \snippet piincludes.cpp swapBinary template inline void piSwapBinary(T & f, T & s) { if ((size_t *)&f == (size_t *)&s) return; size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T); size_t i = 0; for (i = 0; i < j; ++i) { ((size_t *)(&f))[i] ^= ((size_t *)(&s))[i]; ((size_t *)(&s))[i] ^= ((size_t *)(&f))[i]; ((size_t *)(&f))[i] ^= ((size_t *)(&s))[i]; } for (i = bs; i < bf; ++i) { ((uchar *)(&f))[i] ^= ((uchar *)(&s))[i]; ((uchar *)(&s))[i] ^= ((uchar *)(&f))[i]; ((uchar *)(&f))[i] ^= ((uchar *)(&s))[i]; } } template<> inline void piSwapBinary(const void *& f, const void *& s) { if ((size_t *)f == (size_t *)s) return; size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *); size_t i = 0; void *pf = const_cast(f), *ps = const_cast(s); for (i = 0; i < j; ++i) { ((size_t *)(&pf))[i] ^= ((size_t *)(&ps))[i]; ((size_t *)(&ps))[i] ^= ((size_t *)(&pf))[i]; ((size_t *)(&pf))[i] ^= ((size_t *)(&ps))[i]; } for (i = bs; i < bf; ++i) { ((uchar *)(&pf))[i] ^= ((uchar *)(&ps))[i]; ((uchar *)(&ps))[i] ^= ((uchar *)(&pf))[i]; ((uchar *)(&pf))[i] ^= ((uchar *)(&ps))[i]; } } //! \~\brief //! \~english Function for compare two values without "==" by raw content //! \~russian Метод для сравнения двух значений без использования "==" (по сырому содержимому) //! \~\details //! \~english Example:\n \snippet piincludes.cpp compareBinary //! \~russian Пример:\n \snippet piincludes.cpp compareBinary inline bool piCompareBinary(const void * f, const void * s, size_t size) { for (size_t i = 0; i < size; ++i) if (((const uchar *)f)[i] != ((const uchar *)s)[i]) return false; return true; } //! \~\brief //! \~english Templated function return round of float falue //! \~russian Шаблонный метод, возвращающий округленное значение //! \~\details //! \~english //! Round is the nearest integer value \n //! There are some macros: //! - \c piRoundf for "float" //! - \c piRoundd for "double" //! //! Example: //! \snippet piincludes.cpp round //! \~russian //! Округленное значение - это ближайшее целое число\n //! Есть несколько макросов: //! - \c piRoundf для "float" //! - \c piRoundd для "double" //! //! Пример: //! \snippet piincludes.cpp round template inline constexpr int piRound(const T & v) { return int(v >= T(0.) ? v + T(0.5) : v - T(0.5)); } //! \~\brief //! \~english Templated function return floor of float falue //! \~russian Шаблонный метод, возвращающий floor значение //! \~\details //! \~english //! Floor is the largest integer that is not greater than "v" \n //! There are some macros: //! - \c piFloorf for "float" //! - \c piFloord for "double" //! //! Example: //! \snippet piincludes.cpp floor //! \~russian //! Floor значение - это наибольшее целое, не большее чем "v"\n //! Есть несколько макросов: //! - \c piFloorf для "float" //! - \c piFloord для "double" //! //! Пример: //! \snippet piincludes.cpp floor template inline constexpr int piFloor(const T & v) { return v < T(0) ? int(v) - 1 : int(v); } //! \~\brief //! \~english Templated function return ceil of float falue //! \~russian Шаблонный метод, возвращающий ceil значение //! \~\details //! \~english //! Ceil is the smallest integer that is not less than "v" \n //! There are some macros: //! - \c piCeilf for "float" //! - \c piCeild for "double" //! //! Example: //! \snippet piincludes.cpp ceil //! \~russian //! Ceil значение - это наименьшее целое, не меньшее чем "v" \n //! Есть несколько макросов: //! - \c piCeilf для "float" //! - \c piCeild для "double" //! //! Пример: //! \snippet piincludes.cpp ceil template inline constexpr int piCeil(const T & v) { return v < T(0) ? int(v) : int(v) + 1; } //! \~\brief //! \~english Templated function return absolute of numeric falue //! \~russian Шаблонный метод, возвращающий модуль числового значения //! \~\details //! \~english //! Absolute is the positive or equal 0 value \n //! There are some macros: //! - \c piAbss for "short" //! - \c piAbsi for "int" //! - \c piAbsl for "long" //! - \c piAbsll for "llong" //! - \c piAbsf for "float" //! - \c piAbsd for "double" //! //! Example: //! \snippet piincludes.cpp abs //! \~russian //! Модуль числового значения всегда >= 0 \n //! Есть несколько макросов: //! - \c piAbss для "short" //! - \c piAbsi для "int" //! - \c piAbsl для "long" //! - \c piAbsll для "llong" //! - \c piAbsf для "float" //! - \c piAbsd для "double" //! //! Пример: //! \snippet piincludes.cpp abs template inline constexpr T piAbs(const T & v) { return (v >= T(0) ? v : -v); } template constexpr T piMin(const T & f, const T & s) { return ((f > s) ? s : f); } //! \~\brief //! \~english Templated function return minimum of several values //! \~russian Шаблонный метод, возвращающий минимум из нескольких значений //! \~\details //! \~english //! There are some macros: //! - \c piMins for "short" //! - \c piMini for "int" //! - \c piMinl for "long" //! - \c piMinll for "llong" //! - \c piMinf for "float" //! - \c piMind for "double" //! //! Example: //! \snippet piincludes.cpp min2 //! \~russian //! Есть несколько макросов: //! - \c piMins для "short" //! - \c piMini для "int" //! - \c piMinl для "long" //! - \c piMinll для "llong" //! - \c piMinf для "float" //! - \c piMind для "double" //! //! Пример: //! \snippet piincludes.cpp min2 template constexpr T piMin(const T & f, const T & s, const Args &... args) { return piMin(piMin(f, s), args...); } template constexpr T piMax(const T & f, const T & s) { return ((f < s) ? s : f); } //! \~\brief //! \~english Templated function return maximum of several values //! \~russian Шаблонный метод, возвращающий максимум из нескольких значений //! \~\details //! \~english //! There are some macros: //! - \c piMaxs for "short" //! - \c piMaxi for "int" //! - \c piMaxl for "long" //! - \c piMaxll for "llong" //! - \c piMaxf for "float" //! - \c piMaxd for "double" //! //! Example: //! \snippet piincludes.cpp max2 //! \~russian //! Есть несколько макросов: //! - \c piMaxs для "short" //! - \c piMaxi для "int" //! - \c piMaxl для "long" //! - \c piMaxll для "llong" //! - \c piMaxf для "float" //! - \c piMaxd для "double" //! //! Пример: //! \snippet piincludes.cpp max2 template constexpr T piMax(const T & f, const T & s, const Args &... args) { return piMax(piMax(f, s), args...); } //! \~\brief //! \~english Templated function return clamped value //! \~russian Шаблонный метод, возвращающий ограниченное значение //! \~\details //! \~english //! Clamped is the not greater than "max" and not lesser than "min" value \n //! There are some macros: //! - \c piClamps for "short" //! - \c piClampi for "int" //! - \c piClampl for "long" //! - \c piClampll for "llong" //! - \c piClampf for "float" //! - \c piClampd for "double" //! //! Example: //! \snippet piincludes.cpp clamp //! \~russian //! Ограниченное значение - не больше чем "max" и не меньше чем "min" //! Есть несколько макросов: //! - \c piClamps для "short" //! - \c piClampi для "int" //! - \c piClampl для "long" //! - \c piClampll для "llong" //! - \c piClampf для "float" //! - \c piClampd для "double" //! //! Пример: //! \snippet piincludes.cpp clamp template inline constexpr T piClamp(const T & v, const T & min, const T & max) { return (v > max ? max : (v < min ? min : v)); } //! \~\brief //! \~english Function for compare two numeric values with epsilon //! \~russian Метод для сравнения двух чисел с порогом //! \~\details //! \~english //! There are some macros: //! - \c piComparef for "float" //! - \c piCompared for "double" //! //! Example: //! \snippet piincludes.cpp compare //! \~russian //! Есть несколько макросов: //! - \c piComparef для "float" //! - \c piCompared для "double" //! //! Пример: //! \snippet piincludes.cpp compare template inline bool piCompare(const T & a, const T & b, const T & epsilon = std::numeric_limits::epsilon()) { return piAbs(a - b) <= epsilon; } // Endians //! \~\brief //! \~english Function inverse byte order in memory block ([1..N] -> [N..1]) //! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1]) inline void piChangeEndianBinary(void * data, size_t size) { auto hs = size / 2; for (size_t i = 0; i < hs; i++) piSwap(((uchar *)data)[size - i - 1], ((uchar *)data)[i]); } //! \~\brief //! \~english Function inverse byte order in memory block ([1..N] -> [N..1]) //! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1]) inline void piChangeEndianBinary(PIMemoryBlock mem_blk) { if (mem_blk.isNull()) return; piChangeEndianBinary(mem_blk.data(), mem_blk.size()); } //! \~\brief //! \~english Templated function that inverse byte order of value "v" //! \~russian Шаблонный метод, меняющий порядок байт в переменной "v" template inline void piChangeEndian(T & v); //! \~\brief //! \~english Templated function that returns value "v" with inversed byte order //! \~russian Шаблонный метод, возвращающий значение "v" с измененным порядком байт template inline T piChangedEndian(const T & v); template inline void piChangeEndian(T & v) { piChangeEndianBinary(&v, sizeof(T)); } template inline T piChangedEndian(const T & v) { T ret = v; piChangeEndianBinary(&ret, sizeof(T)); return ret; } template<> inline uint16_t piChangedEndian(const uint16_t & v) { return (v << 8) | (v >> 8); } template<> inline uint32_t piChangedEndian(const uint32_t & v) { return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000); } template<> inline float piChangedEndian(const float & v) { union { float f; uint32_t i; } u; u.f = v; u.i = piChangedEndian(u.i); return u.f; } template<> inline void piChangeEndian(uint16_t & v) { v = piChangedEndian(v); } template<> inline void piChangeEndian(uint32_t & v) { v = piChangedEndian(v); } template<> inline void piChangeEndian(float & v) { v = piChangedEndian(v); } DEPRECATEDM("use piChangeEndianBinary()") inline void piLetobe(void * data, int size) { piChangeEndianBinary(data, size); } template DEPRECATEDM("use piChangedEndian()") inline T piLetobe(const T & v) { return piChangedEndian(v); } //! \~\brief //! \~english Generic hash function, implements murmur3/32 algorithm //! \~russian Хэш-функция общего назначения, по алгоритму murmur3/32 inline uint piHashData(const uchar * data, uint len, uint seed = 0) { if (!data || len <= 0) return 0u; uint h = seed; if (len > 3) { uint i = len >> 2; do { uint k; memcpy(&k, data, sizeof(uint)); data += sizeof(uint); k *= 0xcc9e2d51; k = (k << 15) | (k >> 17); k *= 0x1b873593; h ^= k; h = (h << 13) | (h >> 19); h = h * 5 + 0xe6546b64; } while (--i); } if (len & 3) { uint i = len & 3; uint k = 0; do { k <<= 8; k |= data[i - 1]; } while (--i); k *= 0xcc9e2d51; k = (k << 15) | (k >> 17); k *= 0x1b873593; h ^= k; } h ^= len; h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } template inline uint piHash(const T & v) { return 0; } template<> inline uint piHash(const char & v) { return (uint)v; } template<> inline uint piHash(const uchar & v) { return (uint)v; } template<> inline uint piHash(const short & v) { return (uint)v; } template<> inline uint piHash(const ushort & v) { return (uint)v; } template<> inline uint piHash(const int & v) { return (uint)v; } template<> inline uint piHash(const uint & v) { return (uint)v; } template<> inline uint piHash(const llong & v) { return piHashData((const uchar *)&v, sizeof(v)); } template<> inline uint piHash(const ullong & v) { return piHashData((const uchar *)&v, sizeof(v)); } template<> inline uint piHash(const float & v) { return (uint)v; } template<> inline uint piHash(const double & v) { return piHashData((const uchar *)&v, sizeof(v)); } template<> inline uint piHash(const ldouble & v) { return piHashData((const uchar *)&v, sizeof(v)); } //! \~\brief //! \~english Call \b delete on each "container" element. //! \~russian Вызывает \b delete на каждый элемент "container". template inline void piDeleteAll(const T & container) { for (auto i: container) { delete i; } } //! \~\brief //! \~english Call \b delete on each element of //! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list). //! \~russian Вызывает \b delete на каждый элемент //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). template inline void piDeleteAll(std::initializer_list container) { for (auto i: container) { delete i; } } //! \~\brief //! \~english Call \b delete on each "container" element and clear container. //! \~russian Вызывает \b delete на каждый элемент "container" и очищает контейнер. template inline void piDeleteAllAndClear(T & container) { piDeleteAll(container); container.clear(); } //! \~\brief //! \~english Call \b delete if "pointer" is not null and set it to null. Returns if deleted. //! \~russian Вызывает \b delete на "pointer" если он не нулевой и устанавливает его в ноль. Возвращает было ли удаление. template inline bool piDeleteSafety(T *& pointer) { if (!pointer) return false; delete pointer; pointer = nullptr; return true; } #define piRoundf piRound #define piRoundd piRound #define piComparef piCompare #define piCompared piCompare #define piFloorf piFloor #define piFloord piFloor #define piCeilf piCeil #define piCeild piCeil #define piAbss piAbs #define piAbsi piAbs #define piAbsl piAbs #define piAbsll piAbs #define piAbsf piAbs #define piAbsd piAbs #define piMins piMin #define piMini piMin #define piMinl piMin #define piMinll piMin #define piMinf piMin #define piMind piMin #define piMaxs piMax #define piMaxi piMax #define piMaxl piMax #define piMaxll piMax #define piMaxf piMax #define piMaxd piMax #define piClamps piClamp #define piClampi piClamp #define piClampl piClamp #define piClampll piClamp #define piClampf piClamp #define piClampd piClamp #define piLetobes piLetobe #define piLetobei piLetobe #define piLetobel piLetobe #define piLetobell piLetobe #define piLetobef piLetobe //! \~\brief //! \~english Class for executing a function upon scope exit //! \~russian Класс для выполнения функции при выходе из области видимости //! \~\details //! \~english Example //! \~russian Пример //! \~\code //! bool yourFunc() { //! PIScopeExitCall error_call([]() { piCout << "Error!"; }); //! ... //! if (!good0) { //! ... //! return false; //! } //! if (!good1) { //! ... //! return false; //! } //! ... //! error_call.cancel(); //! return true; //! } //! \endcode //! \~english In this example "Error!" will be printed on every \b false function return. //! \~russian В данном примере будет выведен "Error!" при каждом \b false возврате из функции. class PIP_EXPORT PIScopeExitCall { public: //! \~\brief //! \~english Constructor that takes a function to execute //! \~russian Конструктор, который принимает функцию для выполнения explicit PIScopeExitCall(std::function f): func(f) {} //! \~\brief //! \~english Destructor that executes the function if it exists //! \~russian Деструктор, который выполняет функцию, если она существует ~PIScopeExitCall() { call(); } //! \~\brief //! \~english Method for canceling the function //! \~russian Метод для отмены функции void cancel() { func = nullptr; } //! \~\brief //! \~english Method for call the function //! \~russian Метод для вызова функции void call() { if (func) func(); } //! \~\brief //! \~english Method for call and canceling the function //! \~russian Метод для вызова и отмены функции void callAndCancel() { call(); cancel(); } private: NO_COPY_CLASS(PIScopeExitCall) std::function func; }; //! \~\brief //! \~english Inherit from this class to make your class non-trivially copyable. //! \~russian Наследуйтесь от этого класса чтобы сделать свой класс нетривиально копируемым. struct PIP_EXPORT PINonTriviallyCopyable { PINonTriviallyCopyable() noexcept = default; PINonTriviallyCopyable(const PINonTriviallyCopyable &) noexcept = default; PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept; PINonTriviallyCopyable & operator=(const PINonTriviallyCopyable &) noexcept = default; PINonTriviallyCopyable & operator=(PINonTriviallyCopyable &&) noexcept = default; ~PINonTriviallyCopyable() = default; }; inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept = default; template struct FunctionType { using Type = void; }; template struct FunctionType { using Type = std::function; }; template typename FunctionType::Type toStdFunction(L const & func) { return func; } #endif // PIBASE_H