//! \addtogroup Core
//! \{
//! \~\file pibase.h
//! \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 <http://www.gnu.org/licenses/>.
*/

#ifndef PIBASE_H
#define PIBASE_H

#include "pibase_macros.h"
#include "pimemoryblock.h"
#include "pip_export.h"

#include <string.h>

#ifdef CC_AVR_GCC
#  include <ArduinoSTL.h>
#endif
#include <atomic>
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <functional>
#include <initializer_list>
#include <limits>

//! \~\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<typename T>
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<typename T>
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<void *>(f), *ps = const_cast<void *>(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) {
	return 0 == memcmp(f, s, size);
}

//! \~\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<typename T>
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<typename T>
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<typename T>
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<typename T>
inline constexpr T piAbs(const T & v) {
	return (v >= T(0) ? v : -v);
}


//! \~\brief
//! \~english Templated function return minimum of two values
//! \~russian Шаблонный метод, возвращающий минимум из двух значений
template<typename T>
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<typename T, typename... Args>
constexpr T piMin(const T & f, const T & s, const Args &... args) {
	return piMin<T>(piMin<T>(f, s), args...);
}


//! \~\brief
//! \~english Templated function return maximum of two values
//! \~russian Шаблонный метод, возвращающий максимум из двух значений
template<typename T>
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<typename T, typename... Args>
constexpr T piMax(const T & f, const T & s, const Args &... args) {
	return piMax<T>(piMax<T>(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<typename T>
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<typename T>
inline bool piCompare(const T & a, const T & b, const T & epsilon = std::numeric_limits<T>::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>(((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<typename T>
inline void piChangeEndian(T & v);


//! \~\brief
//! \~english Templated function that returns value "v" with inversed byte order
//! \~russian Шаблонный метод, возвращающий значение "v" с измененным порядком байт
template<typename T>
inline T piChangedEndian(const T & v);


template<typename T>
inline void piChangeEndian(T & v) {
	piChangeEndianBinary(&v, sizeof(T));
}

template<typename T>
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<typename T>
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;
}


//! \~\brief
//! \~english Generic hash function, returns 0 for unknown types
//! \~russian Хэш-функция общего назначения, возвращает 0 для неизвестных типов
template<typename T>
inline uint piHash(const T & v) {
	return 0;
}

//! \~\brief
//! \~english Hash function specialization for char type
//! \~russian Специализация хэш-функции для типа char
template<>
inline uint piHash(const char & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for uchar type
//! \~russian Специализация хэш-функции для типа uchar
template<>
inline uint piHash(const uchar & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for short type
//! \~russian Специализация хэш-функции для типа short
template<>
inline uint piHash(const short & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for ushort type
//! \~russian Специализация хэш-функции для типа ushort
template<>
inline uint piHash(const ushort & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for int type
//! \~russian Специализация хэш-функции для типа int
template<>
inline uint piHash(const int & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for uint type
//! \~russian Специализация хэш-функции для типа uint
template<>
inline uint piHash(const uint & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for llong type using piHashData
//! \~russian Специализация хэш-функции для типа llong с использованием piHashData
template<>
inline uint piHash(const llong & v) {
	return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Hash function specialization for ullong type using piHashData
//! \~russian Специализация хэш-функции для типа ullong с использованием piHashData
template<>
inline uint piHash(const ullong & v) {
	return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Hash function specialization for float type
//! \~russian Специализация хэш-функции для типа float
template<>
inline uint piHash(const float & v) {
	return (uint)v;
}
//! \~\brief
//! \~english Hash function specialization for double type using piHashData
//! \~russian Специализация хэш-функции для типа double с использованием piHashData
template<>
inline uint piHash(const double & v) {
	return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Hash function specialization for ldouble type using piHashData
//! \~russian Специализация хэш-функции для типа ldouble с использованием piHashData
template<>
inline uint piHash(const ldouble & v) {
	return piHashData((const uchar *)&v, sizeof(v));
}


//! \~\brief
//! \~english Zero "size" bytes by address "ptr".
//! \~russian Зануляет "size" байт по адресу "ptr".
inline void piZeroMemory(void * ptr, size_t size) {
	memset(ptr, 0, size);
}

//! \~\brief
//! \~english Zero variable "v" memory.
//! \~russian Зануляет память переменной "v".
template<typename T>
inline void piZeroMemory(T & v) {
	piZeroMemory(&v, sizeof(v));
}


//! \~\brief
//! \~english Call \b delete on each "container" element.
//! \~russian Вызывает \b delete на каждый элемент "container".
template<typename T>
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<typename T>
inline void piDeleteAll(std::initializer_list<T> container) {
	for (auto i: container) {
		delete i;
	}
}

//! \~\brief
//! \~english Call \b delete on each "container" element and clear container.
//! \~russian Вызывает \b delete на каждый элемент "container" и очищает контейнер.
template<typename T>
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<typename T>
inline bool piDeleteSafety(T *& pointer) {
	if (!pointer) return false;
	delete pointer;
	pointer = nullptr;
	return true;
}

#define piRoundf   piRound<float>
#define piRoundd   piRound<double>
#define piComparef piCompare<float>
#define piCompared piCompare<double>
#define piFloorf   piFloor<float>
#define piFloord   piFloor<double>
#define piCeilf    piCeil<float>
#define piCeild    piCeil<double>
#define piAbss     piAbs<short>
#define piAbsi     piAbs<int>
#define piAbsl     piAbs<long>
#define piAbsll    piAbs<llong>
#define piAbsf     piAbs<float>
#define piAbsd     piAbs<double>
#define piMins     piMin<short>
#define piMini     piMin<int>
#define piMinl     piMin<long>
#define piMinll    piMin<llong>
#define piMinf     piMin<float>
#define piMind     piMin<double>
#define piMaxs     piMax<short>
#define piMaxi     piMax<int>
#define piMaxl     piMax<long>
#define piMaxll    piMax<llong>
#define piMaxf     piMax<float>
#define piMaxd     piMax<double>
#define piClamps   piClamp<short>
#define piClampi   piClamp<int>
#define piClampl   piClamp<long>
#define piClampll  piClamp<llong>
#define piClampf   piClamp<float>
#define piClampd   piClamp<double>
#define piLetobes  piLetobe<ushort>
#define piLetobei  piLetobe<uint>
#define piLetobel  piLetobe<ulong>
#define piLetobell piLetobe<ullong>
#define piLetobef  piLetobe<float>


//! \~\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 {
	NO_COPY_CLASS(PIScopeExitCall)
public:
	//! \~\brief
	//! \~english Constructor that takes a function to execute
	//! \~russian Конструктор, который принимает функцию для выполнения
	explicit PIScopeExitCall(std::function<void()> f): func(std::move(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:
	std::function<void()> func;
};


//! \~\brief
//! \~english Inherit from this class to make your class non-trivially copyable.
//! \~russian Наследуйтесь от этого класса чтобы сделать свой класс нетривиально копируемым.
struct PIP_EXPORT PINonTriviallyCopyable {
	PINonTriviallyCopyable()                                = default;
	PINonTriviallyCopyable(const PINonTriviallyCopyable &)  = default;
	PINonTriviallyCopyable(PINonTriviallyCopyable &&) ;
	PINonTriviallyCopyable & operator=(const PINonTriviallyCopyable &)  = default;
	PINonTriviallyCopyable & operator=(PINonTriviallyCopyable &&)       = default;
	~PINonTriviallyCopyable()                                                   = default;
};
inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&)  = default;


//! \~\brief
//! \~english Template struct for extracting function type from callable objects
//! \~russian Шаблонная структура для извлечения типа функции из вызываемых объектов
template<typename T>
struct FunctionType {
	using Type = void;
};

//! \~\brief
//! \~english Specialization for member function pointers
//! \~russian Специализация для указателей на члены класса
template<typename Ret, typename Class, typename... Args>
struct FunctionType<Ret (Class::*)(Args...) const> {
	using Type = std::function<Ret(Args...)>;
};

//! \~\brief
//! \~english Convert lambda/functional object to std::function
//! \~russian Преобразует лямбду/функциональный объект в std::function
//! \~\details
//! \~english
//! Uses FunctionType template to extract the function signature from the callable object
//! \~russian
//! Использует шаблон FunctionType для извлечения сигнатуры функции из вызываемого объекта
template<typename L>
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
	return func;
}


#endif // PIBASE_H
