/// Immutable except for fc::from_variant.
struct name {
private:
friend struct fc::reflector<name>;
friend void fc::from_variant(const fc::variant& v, tafsys::chain::name& check);
void set( std::string_view str );
std::string to_string()const;
constexpr uint64_t to_uint64_t()const { return value; }
// 构建一个新的name对象,初始化默认为0
constexpr name() : value(0) {}
// 使用给定的unit64_t类型的值构建一个新的name对象。
constexpr explicit name( uint64_t v ) :value(v) {}
// 使用给定的一个范围的枚举类型,构建一个新的name对象。
constexpr explicit name( name::raw r ) :value(static_cast<uint64_t>(r)) {}
// 使用给定的字符串构建一个新的name对象。
constexpr explicit name( std::string_view str ):value(0) {
if( str.size() > 13 ) { // 字符串最长不能超过12
eosio::check( false, "string is too long to be a valid name" );
}
if( str.empty() ) {
return;
}
// 将字符串转为uint64_t
auto n = std::min( (uint32_t)str.size(), (uint32_t)12u );
for( decltype(n) i = 0; i < n; ++i ) {
value <<= 5;
value |= char_to_value( str[i] );
}
value <<= ( 4 + 5*(12 - n) );
if( str.size() == 13 ) {
uint64_t v = char_to_value( str[12] );
if( v > 0x0Full ) {
eosio::check(false, "thirteenth character in name cannot be a letter that comes after j");
}
value |= v;
}
}
// 将一个Base32符号的char转换为它对应的值。
static constexpr uint8_t char_to_value( char c ) {
if( c == '.')
return 0;
else if( c >= '1' && c <= '5' )
return (c - '1') + 1;
else if( c >= 'a' && c <= 'z' )
return (c - 'a') + 6;
else // 字符中出现了不允许的内容。
eosio::check( false, "character is not in allowed character set for names" );
return 0; // 流程控制将不会到达这里,这一行是为了防止warn信息。
}
// 返回一个name对象的长度,运算方法。
constexpr uint8_t length()const {
constexpr uint64_t mask = 0xF800000000000000ull;
if( value == 0 )
return 0;
uint8_t l = 0;
uint8_t i = 0;
for( auto v = value; i < 13; ++i, v <<= 5 ) {
if( (v & mask) > 0 ) {
l = i;
}
}
return l + 1;
}
// 返回一个name对象的后缀,完整的运算方法。
constexpr name suffix()const {
uint32_t remaining_bits_after_last_actual_dot = 0;
uint32_t tmp = 0;
for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // remaining_bits必须有符号整数
// 从左到右依次遍历name中的字符,共12次
auto c = (value >> remaining_bits) & 0x1Full;
if( !c ) { // 如果当前字符是点
tmp = static_cast<uint32_t>(remaining_bits);
} else { // 如果当前字符不是点
remaining_bits_after_last_actual_dot = tmp;
}
}
uint64_t thirteenth_character = value & 0x0Full;
if( thirteenth_character ) { // 如果第13个字符不是点
remaining_bits_after_last_actual_dot = tmp;
}
if( remaining_bits_after_last_actual_dot == 0 ) // 除了潜在的前导点之外,name中没有实际的点
return name{value};
// 此时,remaining_bits_after_last_actual_dot必须在4到59的范围内(并且限制为5的增量)。
// 除了4个最低有效位(对应于第13个字符)之外,对应于最后一个实际点之后的字符的剩余位的掩码。
uint64_t mask = (1ull << remaining_bits_after_last_actual_dot) - 16;
uint32_t shift = 64 - remaining_bits_after_last_actual_dot;
return name{ ((value & mask) << shift) + (thirteenth_character << (shift-1)) };
}
// 将name类型转为raw枚举类型:基于name对象的值,返回一个raw枚举类型的实例。
constexpr operator raw()const { return raw(value); }
// 显式转换一个name的uint64_t值为bool,如果name的值不为0,返回true。
constexpr explicit operator bool()const { return value != 0; }
// 根据给定的char缓冲区,以字符串的类型写入name对象。参数begin:char缓冲区的开头,参数end:刚好超过char缓冲区的位置,作为结尾。
char* write_as_string( char* begin, char* end )const {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
constexpr uint64_t mask = 0xF800000000000000ull;
if( (begin + 13) < begin || (begin + 13) > end ) return begin;
auto v = value;
for( auto i = 0; i < 13; ++i, v <<= 5 ) {
if( v == 0 ) return begin;
auto indx = (v & mask) >> (i == 12 ? 60 : 59);
*begin = charmap[indx];
++begin;
}
return begin;
}
// 将name对象转为一个字符串返回。
std::string to_string()const {
char buffer[13];
auto end = write_as_string( buffer, buffer + sizeof(buffer) );
return {buffer, end};
}
// 重载运算符等于号
friend constexpr bool operator == ( const name& a, const name& b ) {
return a.value == b.value;
}
// 重载运算符符不等于
friend constexpr bool operator != ( const name& a, const name& b ) {
return a.value != b.value;
}
// 重载运算符小于号
friend constexpr bool operator < ( const name& a, const name& b ) {
return a.value < b.value;
}
uint64_t value = 0; // 其实name对象只有一个有效属性,就是value,以上都是name对象的构造方式、限制条件、各种转型以及运算符重载。
EOSLIB_SERIALIZE( name, (value) )
};
// Each char of the string is encoded into 5-bit chunk and left-shifted
// to its 5-bit slot starting with the highest slot for the first char.
// The 13th char, if str is long enough, is encoded into 4-bit chunk
// and placed in the lowest 4 bits. 64 = 12 * 5 + 4
static constexpr name string_to_name( std::string_view str )
{
return name( string_to_uint64_t( str ) );
}