将名称转换为常量,使用开关而不是丑陋的代码。

huangapple go评论68阅读模式
英文:

Convert name to constant using switch without ugly code

问题

以下是代码的中文翻译:

/** --------------------------------------------------------------------------- 
 * @brief 将类型名称从字符串转换为常量类型值
 @code
enumType eType = type_g("int32");   assert( eType == eTypeInt32 );
eType = type_g("int8");             assert( eType == eTypeInt8 );
 @endcode
 * @param stringType 作为字符串发送的类型
 * @return {enumType} 类型常量
*/
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; 

<details>
<summary>英文:</summary>

I am converting a string to a constant number and that should be done as fast as possible. If possible at compile time. It is used a lot within the code.

Is there a better way to write this type of code?

What it does is to convert the first four character into a 32 bit integer and uses that in a switch to find the constant for 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;
    }


**EDIT**
*Based on tips from @Chris Uzdavinis so new solutions is like this*

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;
    }


</details>
# 答案1
**得分**: 4
以下是您要翻译的代码部分:
```cpp
您可以编写一个简单的函数来执行所有这些重复的工作,然后调用它,大大减少了混乱,使代码更易读,只需为每个枚举编写一个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 &lt; sv.size(); ++i) {
result += sv[i] &lt;&lt; (8*i); 
}
return result;
}
constexpr enumType type_g(std::string_view stringType )
{
using enum enumType;
switch(myHash(stringType))
{
case myHash(&quot;bina&quot;): return eTypeBinary;
case myHash(&quot;bool&quot;): return eTypeBool;
case myHash(&quot;doub&quot;): return eTypeCDouble;
// ...
default:
throw &quot;unhandled&quot;; // compile time err if reached in constexpr
}
}

请注意,代码中包含HTML转义字符(例如,<表示小于符号),这些字符需要在实际使用中进行适当处理。

英文:

You can write a simple function to do all that repetitious work, and then call it, vastly reducing the ugliness and making it a lot more readable, just write a case for each enum as you would code it:

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 &lt; sv.size(); ++i) {
result += sv[i] &lt;&lt; (8*i); 
}
return result;
}
constexpr enumType type_g(std::string_view stringType )
{
using enum enumType;
switch(myHash(stringType))
{
case myHash(&quot;bina&quot;): return eTypeBinary;
case myHash(&quot;bool&quot;): return eTypeBool;
case myHash(&quot;doub&quot;): return eTypeCDouble;
// ...
default:
throw &quot;unhandled&quot;; // compile time err if reached in constexpr
}
}

huangapple
  • 本文由 发表于 2023年4月10日 20:41:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977210.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定