一、学到的知识
- 了解了
to_string
函数的标准库实现 - 复习了
#ifdef #else #endif
的使用 - 复习了
sizeof
关键字 - static_assert 用于编译期报错,语法为:
static_assert(常量表达式,提示字符串)
,表达式为 false,则报错 - 编写转换代码时,逆序将数字转换为字符的方法:
*--String = '0' + Number%10
,地址从高位到低位,数据从地位到高位,妙极了。
之前的想法是将顺序转换,然后进行反转字符串的操作,相比之下,效率无疑大大降低。
二、代码
非原生 to_string
代码,自行修改了变量名,函数名,类型名,使其更容易理解。
/** Copyright Moota, Private. All Rights Reserved. */
#pragma once
#include "../../Base/Object.h"
#include "../../Container/String/String.h"
class FFormat : public UObject
{
private:
/** 无符号数值转字符 */
template <class ResultType, class ValueType>
static ResultType* UnsignedIntegralToBuff(ResultType* Result, ValueType Value)
{
// 进行类型判断
static_assert(std::is_unsigned_v<ValueType>, "ValueType must be unsigned");
// 编译在 Win64
#ifdef _WIN64
auto Temp = Value;
#else
// 编译不在 Win64
// 判断是否超过了4个字节,超过了就需要特殊处理
// 为什么不选择8个字节呢,明明 unsigned long long 也可以处理
// 当然是折中啦
constexpr bool IsBigType = sizeof(ValueType) > 4;
if constexpr (IsBigType) {
// 数值大于 unsigned long 就一直处理
while (Value > 0xFFFFFFFFU) {
// 取余再除,经典取低位数据的操作
auto Temp = static_cast<unsigned long>(Value % 1000000000);
Value /= 1000000000;
// 因为 % 10 0000 0000,有9位,所以,一次处理9位
for (int Index = 0; Index != 9; ++Index) {
// 逆序将数字变成字符,地址从高位到低位,数据从低位到高位,很巧妙的写法
*--Result = static_cast<ReturnType>('0' + Temp % 10);
Temp /= 10;
}
}
// 结束 while 循环时,此时 Value 值小于 unsigned long,>= (0xFFFFFFFFU = 4294967295 / 1000000000) = 4
// 所以在下面的 do-while 循环时,不需要担心 Value 为0还需要执行一次的情况
}
auto Temp = static_cast<unsigned long>(Value);
#endif
// do-while循环,先做一次,包含 0 的情况
do
{
*--Result = static_cast<ResultType>('0' + Temp % 10);
Temp /= 10;
}
while (Temp != 0);
// 返回字符首地址
return Result;
}
/** 处理有符号整数 */
template <class ResultType, class ValueType>
static std::basic_string<ResultType> IntegralToString(const ValueType Value)
{
static_assert(std::is_integral_v<ValueType>, "ValueType must be integral");
// 2^64 有20位,使用这个是因为,它属于 unsigned long long的极限值,也是目前支持的最大的整数类型,这样所有的数据尺寸都包含了
ResultType Buff[21];
ResultType* const BuffEnd = _STD end(Buff);
ResultType* BuffStart = BuffEnd;
const auto UValue = static_cast<std::make_unsigned_t<ValueType>>(Value);
if (Value < 0)
{
// 小于0,0-Value就变成了正数
BuffStart = UnsignedIntegralToBuff(BuffStart, 0 - UValue);
// 然后前面添加符号-即可
*--BuffStart = '-';
}
else
{
BuffStart = UnsignedIntegralToBuff(BuffStart, UValue);
}
return std::basic_string<ResultType>(BuffStart, BuffEnd);
}
/** 处理无符号整数 */
template <class ResultType, class ValueType>
static std::basic_string<ResultType> UnsignedIntegralToString(const ValueType Value)
{
static_assert(std::is_integral_v<ValueType>, "ValueType must be integral");
static_assert(std::is_unsigned_v<ValueType>, "ValueType must be unsigned");
// 2^64 有20位
ResultType Buff[21];
ResultType* const BuffEnd = std::end(Buff);
// 非负数就不需要处理符号-的情况
ResultType* const BuffStart = UnsignedIntegralToBuff(BuffEnd, Value);
return std::basic_string<ResultType>(BuffStart, BuffEnd);
}
public:
// 其他转FString
static FString ToString(int Content)
{
return IntegralToString<char>(Content);
}
static FString ToString(unsigned long long Content)
{
return UnsignedIntegralToString<char>(Content);
}
public:
// FString转其他
};