/*
*******************************************************************************
\file util.h
\brief Utilities
\project bee2 [cryptographic library]
\created 2012.07.16
\version 2025.09.05
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/

/*!
*******************************************************************************
\file util.h
\brief Вспомогательные функции и макросы
*******************************************************************************
*/

#ifndef __BEE2_UTIL_H
#define __BEE2_UTIL_H

#include "bee2/defs.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
*******************************************************************************
Вспомогательные макросы
*******************************************************************************
*/

/*!	\brief Число элементов в массиве a */
#define COUNT_OF(a) (sizeof(a) / sizeof(*(a)))

/*!	\brief Число элементов в массиве a
	\pre Массив непустой.
*/
#define LAST_OF(a) ((a)[COUNT_OF(a) - 1])

/*!	\brief Компиляция с проверкой условия
	
	Для отладочной версии вычислить e и завершить компиляцию, если e == 0.
*/
#ifdef NDEBUG
	#define CASSERT(e) ((void)0)
#else
	#define CASSERT(e) ((void)sizeof(char[1 - 2 * !(e)]))
#endif

/*!	\brief Предполагается выполнение условия
	
	Для отладочной версии вычислить e и завершить выполнение, если e == 0.
	\remark Используется собственная редакция макроса assert(). В стандартной 
	редакции есть проверка условия. При правильной работе программы условие
	никогда не выполняется, и анализаторы покрытия тестами могут показывать 
	только частичное покрытие.
*/
#ifdef NDEBUG
	#define ASSERT(e) ((void)0)
#else
	extern void utilAssert(int e, const char* file, int line);
	#define ASSERT(e) utilAssert(!!(e), __FILE__, __LINE__)
#endif

/*!	\brief Проверяется выполнение условия

	Вычислить e (всегда) и завершить выполнение, если a == 0 (при отладке). 
*/
#define VERIFY(e) {if (!(e)) ASSERT(0);}

/*!	\brief Ожидается выполнение условия

	Ожидать выполнения a, ничего не предпринимая. 
	\remark Макрос EXPECT указывает на условия, которые ожидаются, 
	но все таки могут быть нарушены. Примеры условий: простота числа, 
	неприводимость многочлена, корректность эллиптической кривой. 
	\remark Ожидаемые условия могут быть труднопроверяемыми. Поэтому
	программы не могут полагаться на безусловное выполнение этих условий 
	и должны устойчиво работать даже при их нарушении. Например, 
	программа сложения точек эллиптической кривой над простым полем GF(p) 
	должна завершать сложение даже если p -- составное.
	\remark Следует четко разграничивать ASSERT (как правило, самоконтроль 
	программиста) и EXPECT (как правило, контроль входных данных).
	\remark Некоторые ожидаемые условия могут частично проверяться. 
	Например, EXPECT(p -- нечетное простое) может быть поддержано проверкой 
	ASSERT(p -- нечетное). Безусловные проверки, поддерживающие ожидаемые 
	условия, должны по возможности документироваться.
*/
#define EXPECT(a) 

#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define MIN3(a, b, c) MIN2(a, MIN2(b, c))
#define MAX3(a, b, c) MAX2(a, MAX2(b, c))
#define MIN4(a, b, c, d) MIN2(MIN2(a, b), MIN2(c, d))
#define MAX4(a, b, c, d) MAX2(MAX2(a, b), MAX2(c, d))

/*!	\brief Поменять местами значения переменных a и b
	\pre Переменные имеют один тип.
	\pre Переменные являются целочисленными, допускающими операцию ^.
	\pre Переменные a и b различны.
	\remark Если a и b --- это одна и та же переменная, то она будет
	обнулена. Безопасный код:
	\code
		a != b ? SWAP(a, b) : 0;
	\endcode

*/
#define SWAP(a, b)\
	(a) ^= (b), (b) ^= (a), (a) ^= (b)

/*!	\brief Поменять местами значения указателей a и b
	\pre Переменные a и b различны.
*/
#define SWAP_PTR(a, b)\
	*((octet**)&(a)) = (octet*)(a) - ((octet*)(b) - (octet*)0),\
	*((octet**)&(b)) = (octet*)(b) + ((octet*)(a) - (octet*)0),\
	*((octet**)&(a)) = (octet*)(b) - ((octet*)(a) - (octet*)0)

/*!
*******************************************************************************
\def CLEAN
\brief Очистить переменную

\def CLEAN2
\brief Очистить две переменные

\def CLEAN3
\brief Очистить три переменные

\pre Целевые переменные допускают присваивание нуля.

\remark Макросы CLEANx предназначены для очистки критических переменных по
завершении функций. После очистки переменная приводится к типу void, что 
потенциально подавляет предупреждения статических анализаторов о 
неиспользуемых участках кода (см. напр. 
https://clang.llvm.org/docs/analyzer/user-docs/FAQ.html#dead-store).
*******************************************************************************
*/

#define CLEAN(a)\
	(a) = 0, (void)(a)

#define CLEAN2(a, b)\
	CLEAN(a), CLEAN(b)

#define CLEAN3(a, b, c)\
	CLEAN2(a, b), CLEAN(c)

/*
*******************************************************************************
Версия
*******************************************************************************
*/

/*!	\brief Версия 

	Определяется версия библиотеки bee2.
	\return Версия в виде строки major.minor.patch.
*/
const char* utilVersion();

/*
*******************************************************************************
Деструкторы
*******************************************************************************
*/

/*!	\brief Регистрация деструктора

	Регистрируется функция fn, которая будет вызвана при завершении работы
	программы / выгрузке динамической библиотеки.
	\return Признак успеха.
	\remark Зарегистрированные функции вызываются в порядке LIFO
	(last-in-first-out).
	\remark Одна и та же функция может быть зарегистрирована несколько раз.
*/
bool_t utilOnExit(
	void (*fn)()		/*!< [in] функция */
);

/*
*******************************************************************************
Минимум / максимум
*******************************************************************************
*/

/*!	\brief Минимум

	Определяется минимум из n чисел типа size_t, переданных как дополнительные
	параметры.
	\pre n > 0.
	\return Минимум.
*/
size_t utilMin(
	size_t n,			/*!< [in] количество чисел */
	...					/*!< [in] числа */
);

/*!	\brief Максимум

	Определяется максимум из n чисел типа size_t, переданных как дополнительные
	параметры.
	\pre n > 0.
	\return Максимум.
*/
size_t utilMax(
	size_t n,			/*!< [in] количество чисел */
	...					/*!< [in] числа */
);


/*
*******************************************************************************
Выравнивание
*******************************************************************************
*/

/*!	\brief Ближайшее сверху кратное

	Определяется ближайшее к size сверху число, кратное alignment.
	\return Искомое число.
	\remark Функция используется при выравнивании фрагментов памяти на границы
	блоков из alignment октетов.
*/
size_t utilAlign(
	size_t size,		/*!< [in] размер */
	size_t alignment	/*!< [in] кратность */
);

/*
*******************************************************************************
Контрольные суммы
*******************************************************************************
*/

/*!	\brief Контрольная сумма CRC32

	Определяется контрольная сумма буфера [count]buf. При расчете контрольной 
	суммы используется состояние state. Контрольная сумма рассчитывается 
	по алгоритму CRC32 из стандарта ISO 3309.
	\remark Контрольную сумму большого фрагмента данных можно определять
	последовательно путем многократных обращений к функции.
	При первом обращении состояние state должно быть нулевым.
	\return Контрольная сумма.
*/
u32 utilCRC32(
	const void* buf,	/*!< [in] буфер */
	size_t count,		/*!< [in] число октетов */
	u32 state			/*!< [in,out] состояние */
);

/*!	\brief Контрольная сумма FNV32

	Определяется контрольная сумма буфера [count]buf. При расчете контрольной 
	суммы используется состояние state. Контрольная сумма рассчитывается по 
	алгоритму FNV-1a с размерностью 32 
	(http://isthe.com/chongo/tech/comp/fnv/).
	\remark Контрольную сумму большого фрагмента данных можно определять
	последовательно путем многократных обращений к функции.
	При первом обращении state должно равняться 2166136261 = 0x811C9DC5.
	\return Контрольная сумма.
*/
u32 utilFNV32(
	const void* buf,	/*!< [in] буфер */
	size_t count,		/*!< [in] число октетов */
	u32 state			/*!< [in,out] состояние */
);

/*!	\brief 32-разрядный нонс

	По уникальным системным данным (дата, время) строится 32-разрядный нонс.
	\return Нонс.
	\remark Нонс (калька с англ. nonce) --- "слабо" повторяющееся значение,
	которое используется в криптографических протоколах. С помощью нонсов можно
	инициализовать генераторы псевдослучайных чисел (см. prngCOMBOStart()).
*/
u32 utilNonce32();

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __BEE2_UTIL_H */
