Skip to main content

libraries/eosiolib/core/eosio/name.hpp

More...

Namespaces

Name
eosio
eosio::internal_use_do_not_use
eosio::detail

Classes

Name
structeosio::name
structeosio::detail::to_const_char_arr

Functions

Name
template <typename T ,T... Str>
constexpr eosio::name
operator""_n()
namespace eosio

Detailed Description

Copyright: defined in eos/LICENSE

Functions Documentation

function operator""_n

template <typename T ,
T... Str>
inline constexpr eosio::name operator""_n()

namespace eosio

"foo"_n is a shortcut for name("foo")

Source code


#pragma once

#include "check.hpp"
#include "serialize.hpp"
#include "reflect.hpp"

#include <string>
#include <string_view>

namespace eosio {
namespace internal_use_do_not_use {
extern "C" {
__attribute__((eosio_wasm_import))
void printn(uint64_t);
}
}

struct name {
public:
enum class raw : uint64_t {};

constexpr name() : value(0) {}

constexpr explicit name( uint64_t v )
:value(v)
{}

constexpr explicit name( name::raw r )
:value(static_cast<uint64_t>(r))
{}

constexpr explicit name( std::string_view str )
:value(0)
{
if( str.size() > 13 ) {
eosio::check( false, "string is too long to be a valid name" );
}
if( str.empty() ) {
return;
}

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

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; // control flow will never reach here; just added to suppress warning
}

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

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 ) { // Note: remaining_bits must remain signed integer
// Get characters one-by-one in name in order from left to right (not including the 13th character)
auto c = (value >> remaining_bits) & 0x1Full;
if( !c ) { // if this character is a dot
tmp = static_cast<uint32_t>(remaining_bits);
} else { // if this character is not a dot
remaining_bits_after_last_actual_dot = tmp;
}
}

uint64_t thirteenth_character = value & 0x0Full;
if( thirteenth_character ) { // if 13th character is not a dot
remaining_bits_after_last_actual_dot = tmp;
}

if( remaining_bits_after_last_actual_dot == 0 ) // there is no actual dot in the %name other than potentially leading dots
return name{value};

// At this point remaining_bits_after_last_actual_dot has to be within the range of 4 to 59 (and restricted to increments of 5).

// Mask for remaining bits corresponding to characters after last actual dot, except for 4 least significant bits (corresponds to 13th character).
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)) };
}

constexpr name prefix() const {
uint64_t result = value;
bool not_dot_character_seen = false;
uint64_t mask = 0xFull;

// Get characters one-by-one in name in order from right to left
for( int32_t offset = 0; offset <= 59; ) {
auto c = (value >> offset) & mask;

if( !c ) { // if this character is a dot
if(not_dot_character_seen) { // we found the rightmost dot character
result = (value >> offset) << offset;
break;
}
} else {
not_dot_character_seen = true;
}

if (offset == 0) {
offset += 4;
mask = 0x1Full;
} else {
offset += 5;
}
}

return name{ result };
}

constexpr operator raw()const { return raw(value); }

constexpr explicit operator bool()const { return value != 0; }

char* write_as_string( char* begin, char* end, bool dry_run = false )const {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
constexpr uint64_t mask = 0xF800000000000000ull;

if( dry_run || (begin + 13 < begin) || (begin + 13 > end) ) {
char* actual_end = begin + length();
if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end;
}

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

std::string to_string()const {
char buffer[13];
auto end = write_as_string( buffer, buffer + sizeof(buffer) );
return {buffer, end};
}

inline void print()const {
internal_use_do_not_use::printn(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;
}

friend constexpr bool operator < ( const name& a, const name& b ) {
return a.value < b.value;
}


uint64_t value = 0;

CDT_REFLECT(value);
EOSLIB_SERIALIZE( name, (value) )
};

namespace detail {
template <char... Str>
struct to_const_char_arr {
static constexpr const char value[] = {Str...};
};
}
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
template <typename T, T... Str>
inline constexpr eosio::name operator""_n() {
constexpr auto x = eosio::name{std::string_view{eosio::detail::to_const_char_arr<Str...>::value, sizeof...(Str)}};
return x;
}
#pragma clang diagnostic pop

Updated on 2022-12-05 at 15:38:08 +0000