#ifndef _HASHSTRING_H_
#define _HASHSTRING_H_
#include <tuple>
namespace INISTRING
{
typedef unsigned int uint32_t;
class HashString
{
public:
HashString() = delete;//默认构造函数, 禁止默认构造
HashString(const char* _szString);//带参构造函数
HashString(const HashString& _Instance)=delete;//删除复制构造函数, 无法复制
HashString(HashString&& _Instance)noexcept;//移动构造函数, std::move 触发
~HashString();//析构函数
HashString& operator=(const HashString& _Instance)=delete;//删除重载赋值函数,无法赋值
HashString& operator=(HashString&& _Instance)noexcept;//重载赋值移动函数: std::move触发
bool operator==(const HashString& _Instance)const;//重载等于符号
bool operator>(const HashString& _Instance)const;//重载大于符号
bool operator<(const HashString& _Instance)const;//重载小于符号
HashString& operator=(const char* _szText);//重载赋值函数
const char* GetString()const;//获取字串首地址
const uint32_t GetLength()const;//获取字串长度
bool IsEmpty()const;//判断字串是否空字串
const unsigned long long Convert()const;
private:
//<const char* szHead, uint32_t m_iLength, uint32_t m_iHash1, uint32_t m_iHash1a>
std::tuple<const char*, uint32_t, uint32_t, uint32_t> CalcString(const char* _szText);
uint32_t FNVHash1(const char* _szText, uint32_t _iLength);
uint32_t FNVHash1a(const char* _szText, uint32_t _iLength);
private:
char *m_szText;
uint32_t m_iLength;
//采用双重hash验证, hash双重算法使用FNV-1和FNV-1a
struct HashValue
{
uint32_t m_iHash1a;
uint32_t m_iHash1;
};
HashValue m_vecHash;
unsigned long long* m_pHash;//指向m_vecHash内存块的指针,用来快速比较
};
}
#include "HashString-inl.h"
#endif#include "HashString.h"
#ifdef _DEBUG
//#define _INISTRING_DEBUG_
#endif // DEBUG
#ifdef _INISTRING_DEBUG_
#include "../../DebugInfo/Include/DebugInfo.h"
#endif // _INISTRING_DEBUG_
inline bool IsSpace(const unsigned char* _pByte);
/*
{
return\
*_pByte == ' ' ||
*_pByte == '\t' ||
*_pByte == '\n' ||
*_pByte == '\v' ||
*_pByte == '\f' ||
*_pByte == '\r';
}*/
/*
# FNV - 1算法公式
hash = FNV_offset_basis
for each byte_of_data to be hashed
hash = hash * FNV_prime
hash = hash ^ byte_of_data
return hash
# FNV - 1a算法公式
hash = FNV_offset_basis
for each byte_of_data to be hashed
hash = hash ^ byte_of_data
hash = hash * FNV_prime
return hash
*/
inline uint32_t CalcHash1(const unsigned char _Byte, uint32_t _iOffset, const uint32_t _iFNVPrime = 16777619)
{
_iOffset *= _iFNVPrime;
_iOffset ^= _Byte;
return _iOffset;
}
inline uint32_t CalcHash1a(const unsigned char _Byte, uint32_t _iOffset, const uint32_t _iFNVPrime = 16777619)
{
_iOffset ^= _Byte;
_iOffset *= _iFNVPrime;
return _iOffset;
}
uint32_t INISTRING::HashString::FNVHash1(const char* _szText, uint32_t _iLength)
{
uint32_t iHash = 2166136261;//初始化hash 32位的填充值
uint32_t iFNVPrime = 16777619;//FNV的32位的散列因子?
for (unsigned int i = 0; i < _iLength; ++i)
{
iHash *= iFNVPrime;
iHash ^= _szText[i];
}
return iHash;
}
uint32_t INISTRING::HashString::FNVHash1a(const char* _szText, uint32_t _iLength)
{
uint32_t iHash = 2166136261;//初始化hash 32位的填充值
uint32_t iFNVPrime = 16777619;//FNV的32位的散列因子?
for (unsigned int i = 0; i < _iLength; ++i)
{
iHash ^= _szText[i];
iHash *= iFNVPrime;
}
return iHash;
}
std::tuple<const char*, uint32_t, uint32_t, uint32_t> INISTRING::HashString::CalcString(const char* _szText)
{
//放弃优化,因为key的长度一般很短。优化复杂度如下:
//1. 过滤字串头部和尾部的空格
//2. 计算字串的长度(已经过滤头尾空格)
//3. 计算字串的hash值
//如果要优化,复杂度代价可能比直接while逐个解析char的代价还要大
//register:这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中
//而不是通过内存寻址访问,以提高效率。注意是尽可能,不是绝对。
//毕竟cpu寄存器有限
//解析过程: 每次抽4byte逐个解析, 因为提供的字串流可能是存在于硬盘。
//存在于硬盘, 每次抽4byte到内存 比起 每次抽1byte到内存 可能更快
const char* szHead = nullptr;//过滤空格后的字串头地址,用作返回值
const char* szTail = nullptr;//过滤空格后的字串尾地址
const char* szSource = _szText;//目标字串操作指针
register uint32_t iMagicBits = 0x7EFEFEFFL;//cpu进行位运算所需的因子数,计算4byte里面是否含有空字符'0'
register uint32_t iBlock;//抽出来的4byte配合MagicBits进行位运算,快速判断4byte里面是否含有空字符'0'
unsigned char vecBuffer[sizeof(uint32_t)];//抽出4byte的储存容器
//计算hash的思路,采用极端情况的字串: " string text " ,此字串头尾和中间都有空格。并且需要过滤掉头尾空白字符的同时计算出hash值
//1.开始计算hash肯定跳过字串头部的空格
//2.字串中间的空格只能当作临时hash计算,因为你不知道这个空格后面会不会都只有空格(此空格后面可能还有有效字符)。此时计算空格后的hash存放在iTmpHash内
//3.iHash所存放的都是最一个非空格字符的hash,这样即使在字串中间遇到空格字符,也能照常向下计算hash(计算所得放在iTmpHash),因为如果之后的字符全是空格的话,此时iHash就是最终的hash了,而iTmpHash就永远被放弃了
//处理hash值使用的数据, FNV1版本
uint32_t iHash1 = 0;//储存最终hash值的容器
uint32_t iTmpHash1 = 2166136261;//储存临时hash值的容器,并填充初始值
//处理hash值使用的数据, FNV1a版本
uint32_t iHash1a = 0;//储存最终hash值的容器
uint32_t iTmpHash1a = 2166136261;//储存临时hash值的容器,并填充初始值
while (true)
{
*(uint32_t*)vecBuffer = *(uint32_t*)szSource;//从字串流中抽取4byte到容器
iBlock = *(uint32_t*)vecBuffer;//把抽出来的4byte将由cpu计算
if ((((iBlock + iMagicBits) ^ ~iBlock) & ~iMagicBits) != 0)//计算4byte里面是否含有空字符'0'
{//含有空字符'0'
for (int i = 0; i < sizeof(uint32_t); ++i)
{
//找到字串末尾,打包并返回所需数据
if (vecBuffer[i] == '\0')
{
return std::make_tuple(szHead, szTail - szHead, iHash1, iHash1a);
}
if (IsSpace(vecBuffer + i))//如果是空白字符
{
//字串头地址已经找到,此空白字符开始计算hash值。并储存在临时hash容器
if (szHead)
{
iTmpHash1 = CalcHash1(vecBuffer[i], iTmpHash1);//FNV1版本
iTmpHash1a = CalcHash1a(vecBuffer[i], iTmpHash1a);//FNV1a版本
}
//else 字串头都未找到,说明正在过滤字串头部空格
}
else//如果不是空白字符
{
if (!szHead)szHead = szSource + i;//找到字串头地址
szTail = (szSource + i) + 1;//计算字串尾地址
//FNV1版本
iTmpHash1 = CalcHash1(vecBuffer[i], iTmpHash1);//计算hash
iHash1 = iTmpHash1;//此字符非空白字符,临时hash值转交给最终hash值
//FNV1a版本
iTmpHash1a = CalcHash1a(vecBuffer[i], iTmpHash1a);//计算hash
iHash1a = iTmpHash1a;//此字符非空白字符,临时hash值转交给最终hash值
}
}
}
else
{//不含空字符
for (int i = 0; i < sizeof(uint32_t); ++i)
{
if (IsSpace(vecBuffer + i))//如果是空白字符
{
//字串头地址已经找到,此空白字符开始计算hash值。并储存在临时hash容器
if (szHead)
{
iTmpHash1 = CalcHash1(vecBuffer[i], iTmpHash1);//FNV1版本
iTmpHash1a = CalcHash1a(vecBuffer[i], iTmpHash1a);//FNV1a版本
}
//else 字串头都未找到,说明正在过滤字串头部空格
}
else//如果不是空白字符
{
if (!szHead)szHead = szSource + i;//找到字串头地址
szTail = (szSource + i) + 1;//计算字串尾地址
//FNV1版本
iTmpHash1 = CalcHash1(vecBuffer[i], iTmpHash1);//计算hash
iHash1 = iTmpHash1;//此字符非空白字符,临时hash值转交给最终hash值
//FNV1a版本
iTmpHash1a = CalcHash1a(vecBuffer[i], iTmpHash1a);//计算hash
iHash1a = iTmpHash1a;//此字符非空白字符,临时hash值转交给最终hash值
}
}
}
szSource += sizeof(uint32_t);
}
}
/*
//默认构造函数
INISTRING::HashString::HashString():m_szText(nullptr),m_iLength(0),m_vecHash{0}, m_pHash((long long*)(&m_vecHash))
{
#ifdef _INISTRING_DEBUG_
Info("默认构造: 创建新HashString空白对象<{}>", fmt::ptr(this));
#endif // _INISTRING_DEBUG_
}
*/
//带参<char*>构造函数
INISTRING::HashString::HashString(const char* _szText) :
m_szText(nullptr), m_iLength(0),m_vecHash{0}, m_pHash((unsigned long long*)(&m_vecHash))
{
#ifdef _INISTRING_DEBUG_
Info("带参构造<char*>: 创建新HashString对象<{}>", fmt::ptr(this));
if (!_szText)Error("带参构造<char*>:不能使用空指针初始化HashString:{}", fmt::ptr(this));
assert(_szText != 0 && "不能使用空指针初始化HashString");
#endif // _INISTRING_DEBUG_
const char* szHead = nullptr;//过滤空格后的字串头地址,用作返回值
std::tie(szHead, m_iLength, m_vecHash.m_iHash1, m_vecHash.m_iHash1a) = CalcString(_szText);//计算字串,并解包返回值
//uint32_t iHash1 = FNVHash1(szHead, m_iLength);//调试对比
//uint32_t iHash1a = FNVHash1a(szHead, m_iLength);//调试对比
if (m_iLength)
{
uint32_t iLength = (sizeof(uint32_t) - (m_iLength % sizeof(uint32_t))) + m_iLength;//求对齐数
m_szText = new char[iLength];//创建内存对齐的内存块
memcpy(m_szText, szHead, m_iLength);//复制字串到内存块
m_szText[m_iLength] = '\0';//强制帮字串末尾加入空字符
#ifdef _INISTRING_DEBUG_
Info("字串内存块地址:{},内容<{:s}>", fmt::ptr(m_szText), m_szText);
#endif
}
#ifdef _INISTRING_DEBUG_
else Warn("带参构造<char*>: 创建新HashString对象<{}>, 目标是空字串", fmt::ptr(this));
#endif // _INISTRING_DEBUG_
}
//移动构造函数, std::move 触发
INISTRING::HashString::HashString(HashString&& _Instance)noexcept:
m_szText(nullptr),
m_iLength(0),
m_vecHash{ 0 },
m_pHash((unsigned long long*)(&m_vecHash))
{
#ifdef _INISTRING_DEBUG_
Info("HashString对象<{}>触发std::move, move对象<{}>", fmt::ptr(this), fmt::ptr(&_Instance));
#endif // _INISTRING_DEBUG_
*this = std::forward<HashString>(_Instance);//完美转发右值引用
}
//重载赋值移动函数: std::move触发
INISTRING::HashString& INISTRING::HashString::operator=(HashString&& _Instance)noexcept
{
if (m_szText)
{
#ifdef _INISTRING_DEBUG_
Info("HashString对象<{}>移动赋值, 正在销毁字串内存块<{}>", fmt::ptr(this), fmt::ptr(m_szText));
#endif // _INISTRING_DEBUG_
delete m_szText;
}
m_szText = _Instance.m_szText;
m_iLength = _Instance.m_iLength;
m_vecHash = _Instance.m_vecHash;
_Instance.m_szText = nullptr;
_Instance.m_iLength = 0;
_Instance.m_vecHash.m_iHash1 = 0;
_Instance.m_vecHash.m_iHash1a = 0;
return *this;
}
//析构函数
INISTRING::HashString::~HashString()
{
#ifdef _INISTRING_DEBUG_
Info("析构HashString对象,对象地址:{}, 正在销毁字串内存块<{}>", fmt::ptr(this), fmt::ptr(m_szText));
#endif // _INISTRING_DEBUG_
if (m_szText)delete m_szText;
}
//重载比较 等于函数
bool INISTRING::HashString::operator==(const HashString& _Instance)const
{
return *m_pHash == *_Instance.m_pHash;
}
//重载比较 大于函数
bool INISTRING::HashString::operator>(const HashString& _Instance)const
{
return *m_pHash > *_Instance.m_pHash;
}
//重载比较 小于函数
bool INISTRING::HashString::operator<(const HashString& _Instance)const
{
return *m_pHash < *_Instance.m_pHash;
}
//重载赋值函数
INISTRING::HashString& INISTRING::HashString::operator=(const char* _szText)
{
#ifdef _INISTRING_DEBUG_
Info("HashString对象<{}>触发重载赋值函数", fmt::ptr(this));
#endif // _INISTRING_DEBUG_
* this = HashString(_szText);
return *this;
}
//获取字串首地址
const char* INISTRING::HashString::GetString()const
{
return m_szText;
}
//获取字串长度
const uint32_t INISTRING::HashString::GetLength()const
{
return m_iLength;
}
//判断字串是否空字串
bool INISTRING::HashString::IsEmpty()const
{
return m_iLength ? true : false;
}
const unsigned long long INISTRING::HashString::Convert()const
{
return *m_pHash;
}
根据我提供的代码,帮我优先它,但不要更改类名
最新发布