Files
SaraP 25e80611fe Extern :
- C3d aggiornamento delle librerie ( 117944).
2023-03-31 15:09:23 +02:00

467 lines
19 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//////////////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Хэш-функция с вероятностью совпадения значений 1/(2^32).
\en Hash-function with probability of collisions 1/(2^32). \~
*/
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef __HASH32_H
#define __HASH32_H
#include <io_define.h>
#include <tool_cstring.h>
class writer;
class reader;
//----------------------------------------------------------------------------------------
// \ru Определение простого имени \en Definition of simple name
// Activate to check compilation
// #define SIMPLENAME_AS_CLASS
#ifndef SIMPLENAME_AS_CLASS
//----------------------------------------------------------------------------------------
/** \brief \ru Определение простого имени.
\en Definition of simple name. \~
\details \ru Определение простого имени. \n
\en Definition of simple name. \n \~
\ingroup Base_Tools
*/
// ---
typedef uint32 SimpleName;
//----------------------------------------------------------------------------------------
/** \brief \ru Сравнить простые имена.
\en Compare simple names. \~
\ingroup Base_Tools
*/
// ---
inline
int SimpleNameCompare( const SimpleName & h1, const SimpleName & h2 ) {
return ( (h1 > h2) ? 1 : ( (h1 < h2) ? -1 : 0 ) );
}
//----------------------------------------------------------------------------------------
/** \brief \ru Проверить валидность простого имени.
\en Check the simple name correctness. \~
\ingroup Base_Tools
*/
// ---
inline
bool IsGoodSimpleName( const SimpleName & s ) {
return (bool)(s > 0);
}
#else // SIMPLENAME_AS_CLASS
#include <mb_variables.h>
// \ru При активации этой ветки обязательно собрать проект с активацией максимального уровня предупреждений \en When this branch is activated, the project must be rebuilt with the highest level of warnings activated
class SimpleName {
protected:
size_t body;
public:
// \ru конструкторы \en constructors
SimpleName() : body( SYS_MAX_UINT32 ) {}
SimpleName( const SimpleName & other ) : body( SYS_MAX_UINT32 ) { body = other.body; }
SimpleName( size_t other ) : body( SYS_MAX_UINT32 ) { body = other; }
// \ru операторы копирования \en copy operators
SimpleName & operator = ( const SimpleName & other ) { body = other.body; return *this; }
SimpleName & operator = ( size_t other ) { body = other; return *this; }
// \ru операторы сравнения \en compare operators
bool operator == ( const SimpleName & other ) const { return Сompare( other.body ) == 0; }
bool operator != ( const SimpleName & other ) const { return Сompare( other.body ) != 0; }
bool operator > ( const SimpleName & other ) const { return Сompare( other.body ) > 0; }
bool operator >= ( const SimpleName & other ) const { return Сompare( other.body ) >= 0; }
bool operator < ( const SimpleName & other ) const { return Сompare( other.body ) < 0; }
bool operator <= ( const SimpleName & other ) const { return Сompare( other.body ) <= 0; }
SimpleName operator + ( size_t other ) const { return SimpleName( body + (size_t)other ); }
SimpleName operator - ( size_t other ) const
{
C3D_ASSERT( body >= other );
return SimpleName( body - (size_t)other );
}
SimpleName operator * ( size_t other ) const { return SimpleName( body * other ); }
SimpleName & operator += ( size_t other ) { body += (size_t)other; return *this; }
SimpleName & operator *= ( size_t other ) { body *= (size_t)other; return *this; }
SimpleName & operator |= ( size_t other ) { body |= (size_t)other; return *this; }
SimpleName & operator ++ () { ++body; return *this; } // pre increment
SimpleName operator ++ ( int ) { size_t _tmp = body; ++body; return _tmp; } // post increment
// \ru доступ к данным \en access to data
operator bool () const { return body != 0 && body != SYS_MAX_UINT32; }
operator size_t() const { return (size_t)body; }
operator ptrdiff_t() const { return (ptrdiff_t)body; }
// service
int Сompare( const SimpleName & other ) const { return Сompare( other.body ); } // return value [-1; 0; +1]
protected:
int Сompare( size_t other ) const { return ((body > other) ? 1 : ( (body < other) ? -1 : 0 )); }
protected:
friend void WriteSimpleName( writer &, const SimpleName & s );
friend SimpleName ReadSimpleName ( reader & );
};
inline int SimpleNameCompare( const SimpleName & h1, const SimpleName & h2 ) { return h1.Сompare( h2 ); }
inline bool IsGoodSimpleName( const SimpleName & s ) { return (bool)s; }
inline void SwapIT( SimpleName & a, SimpleName & b ) { SimpleName tmp = a; a = b; b = a; }
#endif // SIMPLENAME_AS_CLASS
namespace c3d // namespace C3D
{
/** \addtogroup Base_Tools
\{
*/
//----------------------------------------------------------------------------------------
/** \brief \ru Максимально допустимое простое имя.
\en Maximum allowable simple name. \~
*/
//---
const SimpleName SIMPLENAME_MAX = size_t(SYS_MAX_UINT32);
//----------------------------------------------------------------------------------------
/** \brief \ru Значение используемое, в качестве "неопределенного", еще не назначенного имени.
\en A value is used as "undefined", not yet assigned name. \~
*/
//---
const SimpleName UNDEFINED_SNAME = size_t(SYS_MAX_UINT32);
//----------------------------------------------------------------------------------------
/** \brief \ru Начальное число для хэш-функции.
\en The initial value for the hash-function. \~
*/
// ---
const SimpleName INIT_HASH32_VAL = size_t( 31415926 );
//----------------------------------------------------------------------------------------
/** \brief \ru Золотое сечение - произвольное число для хэш-функции.
\en Golden section - an arbitrary number for hash-function. \~
*/
// ---
constexpr uint32 GOLDENRATIO = 0x9e3779b9;
/**
\}
*/
//----------------------------------------------------------------------------------------
// \ru Обратимая 32-битная смесь для любых трёх 32-битных чисел a, b, c. \en Reversible 32-bit mixture for any three 32-bit numbers a, b, c.
// \ru Вероятность изменения значений в любом случае равна как минимум одной четвёртой. \en In any case the probability of values modification is equal to 1/4 at least.
// ---
inline
void mix( uint32 & a, uint32 & b, uint32 & c )
{
a -= b; a -= c; a ^= (c >> 13);
b -= c; b -= a; b ^= (a << 8 );
c -= a; c -= b; c ^= (b >> 13);
a -= b; a -= c; a ^= (c >> 12);
b -= c; b -= a; b ^= (a << 16);
c -= a; c -= b; c ^= (b >> 5 );
a -= b; a -= c; a ^= (c >> 3 );
b -= c; b -= a; b ^= (a << 10);
c -= a; c -= b; c ^= (b >> 15);
}
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш-функция.
\en Hash-function. \~
\details \ru Хэш по последовательности байт и предыдущему хэшу. \n
Каждый бит k влияет на возвращаемое значение. \n
Функция плохо подходит для использования в криптографии. \n
k - Указатель на начало последовательности байт. \n
length - Количество байт в последовательности. \n
_c - Предыдущий hash или произвольное значение. \n
\en Hash by sequence of bytes and the previous hash. \n
Each byte k influences on the return value. \n
The function is bad for use in the cryptography. \n
k - A pointer to the beginning of the bytes sequence. \n
length - Number of bytes in the sequence. \n
_c - The previous hash or an arbitrary value. \n \~
\note \ru Алгоритм основан на хэш-функций Дженкинса.
\en The algorithm is based on Bob Jenkins hash function. \~
\return \ru Возвращает 32-битное число.
\en Returns 32-bit number. \~
\ingroup Base_Tools
*/
// ---
inline
SimpleName Hash32( uint8 * k, size_t length, SimpleName _c = INIT_HASH32_VAL )
{
PRECONDITION( HiUint32( length ) == 0 );
// \ru Установка внутреннего значения. \en Setting of the internal value.
size_t len = length;
#ifndef SIMPLENAME_AS_CLASS
uint32 c = _c;
#else // SIMPLENAME_AS_CLASS
uint32 c = LoUint32( (size_t)_c );
#endif // SIMPLENAME_AS_CLASS
uint32 b = GOLDENRATIO; // \ru Золотое сечение (произвольное значение).
uint32 a = GOLDENRATIO; // \en Golden ratio (an arbitrary value).
// handle most of the key
while ( len >= 12 )
{
a += ((uint32)k[0] + ((uint32)k[1]<<8) + ((uint32)k[2] <<16) + ((uint32)k[3] <<24)); // SKIP_SA
b += ((uint32)k[4] + ((uint32)k[5]<<8) + ((uint32)k[6] <<16) + ((uint32)k[7] <<24)); // SKIP_SA
c += ((uint32)k[8] + ((uint32)k[9]<<8) + ((uint32)k[10]<<16) + ((uint32)k[11]<<24)); // SKIP_SA
mix ( a, b, c );
k += 12;
len -= 12;
}
// \ru Значение последних одиннадцати байт. \en The values of the last eleven bytes.
c += LoUint32( length ); // \ru Первый байт с резервируется для length \en The first byte c is reserved for 'length'
switch ( len )
{
case 11: c += ((uint32)k[10]<<24); // SKIP_SA
case 10: c += ((uint32)k[9] <<16); // SKIP_SA
case 9 : c += ((uint32)k[8] <<8 ); // SKIP_SA
// \ru Первый байт с резервируется для length \en The first byte c is reserved for 'length'
case 8 : b += ((uint32)k[7] <<24); // SKIP_SA
case 7 : b += ((uint32)k[6] <<16); // SKIP_SA
case 6 : b += ((uint32)k[5] <<8 ); // SKIP_SA
case 5 : b += ((uint32)k[4]); // SKIP_SA
case 4 : a += ((uint32)k[3] <<24); // SKIP_SA
case 3 : a += ((uint32)k[2] <<16); // SKIP_SA
case 2 : a += ((uint32)k[1] <<8 ); // SKIP_SA
case 1 : a += ((uint32)k[0]); // SKIP_SA
// \ru case 0: Ничего не добавляем. \en case 0: Add nothing.
}
mix( a, b, c );
_c = static_cast<SimpleName>( c );
return _c;
}
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш указателя.
\en Hash of the pointer. \~
\details \ru Хэш указателя. \n
\en Hash of the pointer. \n \~
\ingroup Base_Tools
*/
// ---
template<typename T>
SimpleName Hash32Ptr( T * k ) { return c3d::Hash32( reinterpret_cast<uint8 *>(&k), sizeof(T*) ); }
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш строки.
\en Hash of the string. \~
\details \ru Хэш строки. \n
\en Hash of the string. \n \~
\ingroup Base_Tools
*/
// ---
inline
SimpleName HashStr( const c3d::string_t & str ) {
return c3d::Hash32( (uint8*)str.c_str(), str.length() * sizeof(TCHAR) );
}
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш строки.
\en Hash of the string. \~
\details \ru Хэш строки. \n
\en Hash of the string. \n \~
\ingroup Base_Tools
*/
// ---
inline
SimpleName HashStr( const char * c_str )
{
PRECONDITION( c_str );
return c3d::Hash32( (uint8*)c_str, strlen(c_str) * sizeof(char) );
}
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш строки.
\en Hash of the string. \~
\details \ru Хэш строки. \n
\en Hash of the string. \n \~
\ingroup Base_Tools
*/
// ---
inline
SimpleName HashStr( const wchar_t * w_str )
{
PRECONDITION( w_str );
#ifndef __MOBILE_VERSION__
return c3d::Hash32( (uint8*)w_str, wcslen(w_str) * sizeof(wchar_t) );
#else // __MOBILE_VERSION__
uint16 * hashBuf = Ucs4ToUtf16((uint32*)w_str);
uint16 * hashBufPointer = hashBuf;
SimpleName hash = c3d::Hash32( (uint8*)hashBufPointer, wcslen(w_str) * 2 );
delete[] hashBuf;
return hash;
#endif // __MOBILE_VERSION__
}
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш с типом строки.
\en Hash with a string type. \~
\details \ru Хэш с типом строки-источника. \n
Класс введен для идентификации хэша, взятого с char строки и хеша, взятого с той же wchar_t строки.
\en Hash with type of source string. \n
The class is introduced for identification of the hash taken from char of the string and from hash taken with the same wchar_t of the string. \~
\ingroup Base_Tools
*/
// ---
class StrHash {
public:
/// \ru Тип строки-источника имени. \en Type of the source string of name.
enum StrHashType {
htp_undef = 0, ///< \ru Тип источника неизвестен. \en The source type is unknown.
htp_char = 1, ///< \ru Тип источника char. \en The source type is char.
htp_wchar = 2 ///< \ru Тип источника wchar. \en The source type is wchar.
};
private:
SimpleName m_val; ///< \ru Простое имя. \en Simple name.
uint8 m_type; ///< \ru Тип строки-источника имени. \en Type of the source string of name.
public:
/// \ru Конструктор по имени и типу его происхождения. \en Constructor by name and type of its origin.
StrHash( SimpleName val, uint8 type )
: m_val ( val )
, m_type( type )
{}
/// \ru Конструктор по строке. \en Constructor by string.
StrHash ( const char * str )
: m_val ( c3d::HashStr(str) )
, m_type( htp_char )
{}
/// \ru Конструктор по строке. \en Constructor by string.
StrHash ( const wchar_t * str )
: m_val ( c3d::HashStr(str) )
, m_type( htp_wchar )
{}
SimpleName GetVal() const { return m_val; } ///< \ru Получить значение. \en Get the value.
uint8 GetType() const { return m_type; } ///< \ru Получить тип. \en Get type.
int operator == ( const StrHash & with ) const; ///< \ru Оператор равенства. \en Equality operator.
int operator == ( const char * with ) const; ///< \ru Оператор равенства. \en Equality operator.
int operator == ( const wchar_t * with ) const; ///< \ru Оператор равенства. \en Equality operator.
// \ru Чтение-запись \en Reading-writing
friend writer & operator << ( writer &, const c3d::StrHash & strHash ); ///< \ru Оператор записи. \en Write operator.
friend reader & operator >> ( reader &, c3d::StrHash & strHash ); ///< \ru Оператор чтения. \en Read operator.
};
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш пустой строки.
\en Hash of the empty string. \~
\details \ru Хэш пустой строки. \n
\en Hash of the empty string. \n \~
\ingroup Base_Tools
*/
// ---
const StrHash NullStrHash( 0, StrHash::htp_undef );
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш при отсутствии строки.
\en Hash for the string absence. \~
\details \ru Хэш при отсутствии строки. \n
\en Hash for the string absence. \n \~
\ingroup Base_Tools
*/
// ---
const StrHash UndefStrHash( SimpleName(-1), StrHash::htp_undef );
//----------------------------------------------------------------------------------------
/** \brief \ru Хэш двух простых имен.
\en Hash of two simple names. \~
\details \ru Хэш двух простых имен. \n
Часто встречающаяся комбинация - hash от двух SimpleName (uint32).
\en Hash of two simple names. \n
Frequently occurring combination - hash of two SimpleName (uint32). \~
\ingroup Base_Tools
*/
// ---
inline
SimpleName Hash32SN( SimpleName k1, SimpleName k2 )
{
//SimpleName array[] = { k1, k2 };
uint arr[2];
#ifndef SIMPLENAME_AS_CLASS
arr[0] = k1;
arr[1] = k2;
#else // SIMPLENAME_AS_CLASS
arr[0] = LoUint32( (size_t)k1 );
arr[1] = LoUint32( (size_t)k2 );
#endif // SIMPLENAME_AS_CLASS
return c3d::Hash32( (uint8*)arr, 2 * sizeof(uint) ); // \ru длина - 4 * 2 = 8 \en length - 4 * 2 = 8
}
//----------------------------------------------------------------------------------------
// \ru Проверка на равенство \en The check for equality
//---
inline int StrHash::operator == ( const StrHash & with ) const
{
PRECONDITION(m_type == with.m_type); // \ru должны быть одного типа, иначе сравнение не имеет смысла \en must be of the same type, otherwise the comparison is senseless
return ::SimpleNameCompare( m_val, with.m_val );
}
//----------------------------------------------------------------------------------------
// \ru Проверка на равенство char строкой \en Check for equality of char by string
//---
inline int StrHash::operator == ( const char * with ) const
{
PRECONDITION( false ); // \ru по идее использоваться не должна \en should not be used
PRECONDITION( m_type != htp_undef );
// \ru Если у нас хеш с wchar_t \en If we have hash with wchar_t,
if ( m_type == htp_wchar ) // \ru то что прислали нужно перевести в wchar_t \en then the input data should be converted to wchar_t
return *this == StrHash( wcsbuf(with) );
else
return *this == StrHash( with );
}
//----------------------------------------------------------------------------------------
// \ru Проверка на равенство с wchar_t строкой \en Check for equality with wchar_t by string
//---
inline int StrHash::operator == ( const wchar_t * with ) const
{
PRECONDITION( m_type != htp_undef );
// \ru Если у нас хеш с char \en If we have hash with char,
if ( m_type == htp_char ) // \ru то что прислали нужно перевести в char \en then the input data should be converted to char
return *this == StrHash( strbuf(with) );
else
return *this == StrHash( with );
}
} // namespace C3D
#endif // __HASH32_H