我正在将字符串转换为常量,这应该尽可能快地完成。如果可能的话,在编译时。它在代码中使用得很多。
是否有更好的方法来编写这种类型的代码?
它的作用是将前四个字符转换为32位整数,并在switch中使用该整数查找name的常量。
/** ---------------------------------------------------------------------------
* @brief Convert type name from string to constant type value
@code
enumType eType = type_g("int32"); assert( eType == eTypeInt32 );
eType = type_g("int8"); assert( eType == eTypeInt8 );
@endcode
* @param stringType type sent as string
* @return {enumType} type constant
*/
constexpr enumType type_g( const std::string_view& stringType )
{
enumType eType = eTypeUnknown;
constexpr uint32_t binary_ = ((uint32_t)'b') + (uint32_t)('i' << 8) + (uint32_t)('n' << 16) + (uint32_t)('a' << 24);
constexpr uint32_t bool_ = ((uint32_t)'b') + (uint32_t)('o' << 8) + (uint32_t)('o' << 16) + (uint32_t)('l' << 24);
constexpr uint32_t double_ = ((uint32_t)'d') + (uint32_t)('o' << 8) + (uint32_t)('u' << 16) + (uint32_t)('b' << 24);
constexpr uint32_t float_ = ((uint32_t)'f') + (uint32_t)('l' << 8) + (uint32_t)('o' << 16) + (uint32_t)('a' << 24);
constexpr uint32_t i128_ = ((uint32_t)'i') + (uint32_t)('1' << 8) + (uint32_t)('2' << 16) + (uint32_t)('8' << 24);
constexpr uint32_t i256_ = ((uint32_t)'i') + (uint32_t)('2' << 8) + (uint32_t)('5' << 16) + (uint32_t)('6' << 24);
constexpr uint32_t i512_ = ((uint32_t)'i') + (uint32_t)('5' << 8) + (uint32_t)('1' << 16) + (uint32_t)('2' << 24);
constexpr uint32_t int8_ = ((uint32_t)'i') + (uint32_t)('n' << 8) + (uint32_t)('t' << 16) + (uint32_t)('8' << 24);
constexpr uint32_t int16_ = ((uint32_t)'i') + (uint32_t)('n' << 8) + (uint32_t)('t' << 16) + (uint32_t)('1' << 24);
constexpr uint32_t int32_ = ((uint32_t)'i') + (uint32_t)('n' << 8) + (uint32_t)('t' << 16) + (uint32_t)('3' << 24);
constexpr uint32_t int64_ = ((uint32_t)'i') + (uint32_t)('n' << 8) + (uint32_t)('t' << 16) + (uint32_t)('6' << 24);
constexpr uint32_t u128_ = ((uint32_t)'u') + (uint32_t)('1' << 8) + (uint32_t)('2' << 16) + (uint32_t)('8' << 24);
constexpr uint32_t u256_ = ((uint32_t)'u') + (uint32_t)('2' << 8) + (uint32_t)('5' << 16) + (uint32_t)('6' << 24);
constexpr uint32_t u512_ = ((uint32_t)'u') + (uint32_t)('5' << 8) + (uint32_t)('1' << 16) + (uint32_t)('2' << 24);
constexpr uint32_t uint_ = ((uint32_t)'u') + (uint32_t)('i' << 8) + (uint32_t)('n' << 16) + (uint32_t)('t' << 24);
constexpr uint32_t pointer_ = ((uint32_t)'p') + (uint32_t)('o' << 8) + (uint32_t)('i' << 16) + (uint32_t)('n' << 24);
constexpr uint32_t rbinary_ = ((uint32_t)'r') + (uint32_t)('b' << 8) + (uint32_t)('i' << 16) + (uint32_t)('n' << 24);
constexpr uint32_t rstring_ = ((uint32_t)'r') + (uint32_t)('s' << 8) + (uint32_t)('t' << 16) + (uint32_t)('r' << 24);
constexpr uint32_t string_ = ((uint32_t)'s') + (uint32_t)('t' << 8) + (uint32_t)('r' << 16) + (uint32_t)('i' << 24);
constexpr uint32_t utf8_ = ((uint32_t)'u') + (uint32_t)('t' << 8) + (uint32_t)('f' << 16) + (uint32_t)('8' << 24);
constexpr uint32_t utf32_ = ((uint32_t)'u') + (uint32_t)('t' << 8) + (uint32_t)('f' << 16) + (uint32_t)('3' << 24);
constexpr uint32_t uuid_ = ((uint32_t)'u') + (uint32_t)('u' << 8) + (uint32_t)('i' << 16) + (uint32_t)('d' << 24);
constexpr uint32_t wstring_ = ((uint32_t)'w') + (uint32_t)('s' << 8) + (uint32_t)('t' << 16) + (uint32_t)('r' << 24);
uint32_t uTypeName = *( uint32_t* )stringType.data();
switch( uTypeName )
{
case binary_: eType = eTypeBinary; break;
case bool_: eType = eTypeBool; break;
case double_: eType = eTypeCDouble; break;
case float_: eType = eTypeCFloat; break;
case i128_: eType = eTypeInt128; break;
case i256_: eType = eTypeInt256; break;
case i512_: eType = eTypeInt512; break;
case int8_: eType = eTypeInt8; break;
case int16_: eType = eTypeInt16; break;
case int32_: eType = eTypeInt32; break;
case int64_: eType = eTypeInt64; break;
case pointer_: eType = eTypePointer; break;
case rbinary_: eType = eTypeRBinary; break;
case rstring_: eType = eTypeRString; break;
case string_: eType = eTypeString; break;
case u128_: eType = eTypeUInt128; break;
case u256_: eType = eTypeUInt256; break;
case u512_: eType = eTypeUInt512; break;
case uint_:
{
if( stringType[4] == '8' ) eType = eTypeUInt8;
else if( stringType[4] == '1' ) eType = eTypeUInt16;
else if( stringType[4] == '3' ) eType = eTypeUInt32;
else if( stringType[4] == '6' ) eType = eTypeUInt64;
else { static_assert("invalid type name"); assert( false ); }
}
break;
case uuid_: eType = eTypeGuid; break;
case utf8_: eType = eTypeUtf8String; break;
case wstring_: eType = eTypeWString; break;
case utf32_: eType = eTypeUtf32String; break;
default:
assert(false);
}
return eType;
}
编辑
基于来自@Chris Uzdavinis的提示,所以新的解决方案是这样的
namespace detail {
/// helper method used to convert first four characters into 32 bit unsigned integer value
constexpr uint32_t hash_type( std::string_view stringType )
{
uint32_t uHashValue = (uint32_t)stringType[0];
uHashValue += (uint32_t)stringType[1] << 8;
uHashValue += (uint32_t)stringType[2] << 16;
uHashValue += (uint32_t)stringType[3] << 24;
return uHashValue;
}
}
/** ---------------------------------------------------------------------------
* @brief Convert type name from string to constant type value
@code
enumType eType = type_g("int32"); assert( eType == eTypeInt32 );
eType = type_g("int8"); assert( eType == eTypeInt8 );
@endcode
* @param stringType type sent as string
* @return {enumType} type constant
*/
constexpr enumType type_g( const std::string_view& stringType )
{ assert( stringType.length() >= 4 );
using namespace detail;
enumType eType = eTypeUnknown;
uint32_t uTypeName = hash_type( stringType );
switch( uTypeName )
{
case hash_type("bina"): eType = eTypeBinary; break; // binary
case hash_type("bool"): eType = eTypeBool; break; // bool
case hash_type("doub"): eType = eTypeCDouble; break; // double
case hash_type("floa"): eType = eTypeCFloat; break; // float
case hash_type("i128"): eType = eTypeInt128; break; // int128
case hash_type("i256"): eType = eTypeInt256; break; // int254
case hash_type("i512"): eType = eTypeInt512; break; // int512
case hash_type("int8"): eType = eTypeInt8; break; // int8
case hash_type("int1"): eType = eTypeInt16; break; // int16
case hash_type("int3"): eType = eTypeInt32; break; // int32
case hash_type("int6"): eType = eTypeInt64; break; // int64
case hash_type("poin"): eType = eTypePointer; break; // pointer
case hash_type("rbin"): eType = eTypeRBinary; break; // rbinary (binary reference)
case hash_type("rstr"): eType = eTypeRString; break; // rstring (string reference)
case hash_type("stri"): eType = eTypeString; break;
case hash_type("u128"): eType = eTypeUInt128; break; // uint128
case hash_type("u256"): eType = eTypeUInt256; break; // uint256
case hash_type("u512"): eType = eTypeUInt512; break; // uint512
case hash_type("uint"): // uint8, uint16, uint32, uint64
{
if( stringType[4] == '8' ) eType = eTypeUInt8;
else if( stringType[4] == '1' ) eType = eTypeUInt16;
else if( stringType[4] == '3' ) eType = eTypeUInt32;
else if( stringType[4] == '6' ) eType = eTypeUInt64;
else { static_assert("invalid type name"); assert( false ); }
}
break;
case hash_type("uuid"): eType = eTypeGuid; break; // uuid
case hash_type("utf8"): eType = eTypeUtf8String; break; // utf8
case hash_type("wstr"): eType = eTypeWString; break; // wstring
case hash_type("utf3"): eType = eTypeUtf32String; break; // uft32
default: assert(false);
}
return eType;
}
您可以编写一个简单的函数来完成所有重复的工作,然后调用它,大大减少了丑陋并使其更具可读性,只需为每个enum编写一个case:
enum class enumType : uint32_t {
eTypeBinary, eTypeBool, eTypeCDouble, eTypeCFloat, eTypeInt128, eTypeInt256,
eTypeInt512, eTypeInt8, eTypeInt16, eTypeInt32, eTypeInt64, eTypePointer,
eTypeRBinary, eTypeRString, eTypeString, eTypeUInt128, eTypeUInt256, eTypeUInt512,
eTypeUInt8, eTypeUInt16, eTypeUInt32, eTypeUInt64, eTypeGuid, eTypeUtf8String,
eTypeWString, eTypeUtf32String, eTypeUnknown,
};
constexpr uint32_t myHash(std::string_view sv) {
uint32_t result = 0;
for (int i = 0; i < sv.size(); ++i) {
result += sv[i] << (8*i);
}
return result;
}
constexpr enumType type_g(std::string_view stringType )
{
using enum enumType;
switch(myHash(stringType))
{
case myHash("bina"): return eTypeBinary;
case myHash("bool"): return eTypeBool;
case myHash("doub"): return eTypeCDouble;
// ...
default:
throw "unhandled"; // compile time err if reached in constexpr
}
}