Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
5 contributors

Users who have contributed to this file

@larryk85 @dskvr @arhag @fingera @conr2d
275 lines (236 sloc) 9.02 KB
/**
* @file
* @copyright defined in eos/LICENSE
*/
#pragma once
#include "system.hpp"
#include "serialize.hpp"
#include <string>
#include <string_view>
#warning "<eosiolib/name.hpp> is deprecated use <eosio/name.hpp>"
namespace eosio {
/**
* @defgroup name
* @ingroup types
* @brief EOSIO Types
* @{
/*
* Wraps a %uint64_t to ensure it is only passed to methods that expect a %name.
* Ensures value is only passed to methods that expect a %name and that no mathematical
* operations occur. Also enables specialization of print
*/
struct name {
public:
enum class raw : uint64_t {};
/**
* Construct a new name
*
* @brief Construct a new name object defaulting to a value of 0
*
*/
constexpr name() : value(0) {}
/**
* Construct a new name given a unit64_t value
*
* @brief Construct a new name object initialising value with v
* @param v - The unit64_t value
*
*/
constexpr explicit name( uint64_t v )
:value(v)
{}
/**
* Construct a new name given a scoped enumerated type of raw (uint64_t).
*
* @brief Construct a new name object initialising value with r
* @param r - The raw value which is a scoped enumerated type of unit64_t
*
*/
constexpr explicit name( name::raw r )
:value(static_cast<uint64_t>(r))
{}
/**
* Construct a new name given an string.
*
* @brief Construct a new name object initialising value with str
* @param str - The string value which validated then converted to unit64_t
*
*/
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;
}
}
/**
* Converts a %name Base32 symbol into its corresponding value
*
* @param c - Character to be converted
* @return constexpr char - Converted value
*/
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
}
/**
* Returns the length of the %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;
}
/**
* Returns the suffix of the %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 ) { // 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)) };
}
/**
* Casts a name to raw
*
* @return Returns an instance of raw based on the value of a name
*/
constexpr operator raw()const { return raw(value); }
/**
* Explicit cast to bool of the uint64_t value of the name
*
* @return Returns true if the name is set to the default value of 0 else true.
*/
constexpr explicit operator bool()const { return value != 0; }
/**
* Writes the %name as a string to the provided char buffer
*
* @pre The range [begin, end) must be a valid range of memory to write to.
* @param begin - The start of the char buffer
* @param end - Just past the end of the char buffer
* @param dry_run - If true, do not actually write anything into the range.
* @return char* - Just past the end of the last character that would be written assuming dry_run == false and end was large enough to provide sufficient space. (Meaning only applies if returned pointer >= begin.)
* @post If the output string fits within the range [begin, end) and dry_run == false, the range [begin, returned pointer) contains the string representation of the %name. Nothing is written if dry_run == true or returned pointer > end (insufficient space) or if returned pointer < begin (overflow in calculating desired end).
*/
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;
}
/**
* Returns the name as a string.
*
* @brief Returns the name value as a string by calling write_as_string() and returning the buffer produced by write_as_string()
*/
std::string to_string()const {
char buffer[13];
auto end = write_as_string( buffer, buffer + sizeof(buffer) );
return {buffer, end};
}
/**
* Equivalency operator. Returns true if a == b (are the same)
*
* @return boolean - true if both provided %name values are the same
*/
friend constexpr bool operator == ( const name& a, const name& b ) {
return a.value == b.value;
}
/**
* Inverted equivalency operator. Returns true if a != b (are different)
*
* @return boolean - true if both provided %name values are not the same
*/
friend constexpr bool operator != ( const name& a, const name& b ) {
return a.value != b.value;
}
/**
* Less than operator. Returns true if a < b.
*
* @return boolean - true if %name `a` is less than `b`
*/
friend constexpr bool operator < ( const name& a, const name& b ) {
return a.value < b.value;
}
uint64_t value = 0;
EOSLIB_SERIALIZE( name, (value) )
};
namespace detail {
template <char... Str>
struct to_const_char_arr {
static constexpr const char value[] = {Str...};
};
} /// namespace detail
} /// namespace eosio
/**
* %name literal operator
*
* @brief "foo"_n is a shortcut for name("foo")
*/
#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
You can’t perform that action at this time.