libraries/eosiolib/core/eosio/name.hpp
Namespaces
| Name | 
|---|
| eosio | 
| eosio::internal_use_do_not_use | 
| eosio::detail | 
Classes
| Name | |
|---|---|
| struct | eosio::name | 
| struct | eosio::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