CDT  v4.2.0
инструменты разработчика
name.hpp
См. документацию.
1
5#pragma once
6
7#include "check.hpp"
8#include "serialize.hpp"
9#include "reflect.hpp"
10
11#include <string>
12#include <string_view>
13
14namespace eosio {
15 namespace internal_use_do_not_use {
16 extern "C" {
17 __attribute__((eosio_wasm_import))
18 void printn(uint64_t);
19 }
20 }
21
35 struct name {
36 public:
37 enum class raw : uint64_t {};
38
45 constexpr name() : value(0) {}
46
54 constexpr explicit name( uint64_t v )
55 :value(v)
56 {}
57
65 constexpr explicit name( name::raw r )
66 :value(static_cast<uint64_t>(r))
67 {}
68
76 constexpr explicit name( std::string_view str )
77 :value(0)
78 {
79 if( str.size() > 13 ) {
80 eosio::check( false, "string is too long to be a valid name" );
81 }
82 if( str.empty() ) {
83 return;
84 }
85
86 auto n = std::min( (uint32_t)str.size(), (uint32_t)12u );
87 for( decltype(n) i = 0; i < n; ++i ) {
88 value <<= 5;
89 value |= char_to_value( str[i] );
90 }
91 value <<= ( 4 + 5*(12 - n) );
92 if( str.size() == 13 ) {
93 uint64_t v = char_to_value( str[12] );
94 if( v > 0x0Full ) {
95 eosio::check(false, "thirteenth character in name cannot be a letter that comes after j");
96 }
97 value |= v;
98 }
99 }
100
107 static constexpr uint8_t char_to_value( char c ) {
108 if( c == '.')
109 return 0;
110 else if( c >= '1' && c <= '5' )
111 return (c - '1') + 1;
112 else if( c >= 'a' && c <= 'z' )
113 return (c - 'a') + 6;
114 else
115 eosio::check( false, "character is not in allowed character set for names" );
116
117 return 0; // control flow will never reach here; just added to suppress warning
118 }
119
123 constexpr uint8_t length()const {
124 constexpr uint64_t mask = 0xF800000000000000ull;
125
126 if( value == 0 )
127 return 0;
128
129 uint8_t l = 0;
130 uint8_t i = 0;
131 for( auto v = value; i < 13; ++i, v <<= 5 ) {
132 if( (v & mask) > 0 ) {
133 l = i;
134 }
135 }
136
137 return l + 1;
138 }
139
143 constexpr name suffix()const {
144 uint32_t remaining_bits_after_last_actual_dot = 0;
145 uint32_t tmp = 0;
146 for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // Note: remaining_bits must remain signed integer
147 // Get characters one-by-one in name in order from left to right (not including the 13th character)
148 auto c = (value >> remaining_bits) & 0x1Full;
149 if( !c ) { // if this character is a dot
150 tmp = static_cast<uint32_t>(remaining_bits);
151 } else { // if this character is not a dot
152 remaining_bits_after_last_actual_dot = tmp;
153 }
154 }
155
156 uint64_t thirteenth_character = value & 0x0Full;
157 if( thirteenth_character ) { // if 13th character is not a dot
158 remaining_bits_after_last_actual_dot = tmp;
159 }
160
161 if( remaining_bits_after_last_actual_dot == 0 ) // there is no actual dot in the %name other than potentially leading dots
162 return name{value};
163
164 // 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).
165
166 // Mask for remaining bits corresponding to characters after last actual dot, except for 4 least significant bits (corresponds to 13th character).
167 uint64_t mask = (1ull << remaining_bits_after_last_actual_dot) - 16;
168 uint32_t shift = 64 - remaining_bits_after_last_actual_dot;
169
170 return name{ ((value & mask) << shift) + (thirteenth_character << (shift-1)) };
171 }
172
176 constexpr name prefix() const {
178 bool not_dot_character_seen = false;
179 uint64_t mask = 0xFull;
180
181 // Get characters one-by-one in name in order from right to left
182 for( int32_t offset = 0; offset <= 59; ) {
183 auto c = (value >> offset) & mask;
184
185 if( !c ) { // if this character is a dot
186 if(not_dot_character_seen) { // we found the rightmost dot character
187 result = (value >> offset) << offset;
188 break;
189 }
190 } else {
191 not_dot_character_seen = true;
192 }
193
194 if (offset == 0) {
195 offset += 4;
196 mask = 0x1Full;
197 } else {
198 offset += 5;
199 }
200 }
201
202 return name{ result };
203 }
204
210 constexpr operator raw()const { return raw(value); }
211
217 constexpr explicit operator bool()const { return value != 0; }
218
229 char* write_as_string( char* begin, char* end, bool dry_run = false )const {
230 static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
231 constexpr uint64_t mask = 0xF800000000000000ull;
232
233 if( dry_run || (begin + 13 < begin) || (begin + 13 > end) ) {
234 char* actual_end = begin + length();
235 if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end;
236 }
237
238 auto v = value;
239 for( auto i = 0; i < 13; ++i, v <<= 5 ) {
240 if( v == 0 ) return begin;
241
242 auto indx = (v & mask) >> (i == 12 ? 60 : 59);
243 *begin = charmap[indx];
244 ++begin;
245 }
246
247 return begin;
248 }
249
255 std::string to_string()const {
256 char buffer[13];
257 auto end = write_as_string( buffer, buffer + sizeof(buffer) );
258 return {buffer, end};
259 }
260
265 inline void print()const {
266 internal_use_do_not_use::printn(value);
267 }
268
270
276 friend constexpr bool operator == ( const name& a, const name& b ) {
277 return a.value == b.value;
278 }
279
285 friend constexpr bool operator != ( const name& a, const name& b ) {
286 return a.value != b.value;
287 }
288
294 friend constexpr bool operator < ( const name& a, const name& b ) {
295 return a.value < b.value;
296 }
297
299
301
304 };
305
306 namespace detail {
307 template <char... Str>
309 static constexpr const char value[] = {Str...};
310 };
311 }
312}
313
318#pragma clang diagnostic push
319#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
320template <typename T, T... Str>
321inline constexpr eosio::name operator""_n() {
322 constexpr auto x = eosio::name{std::string_view{eosio::detail::to_const_char_arr<Str...>::value, sizeof...(Str)}};
323 return x;
324}
325#pragma clang diagnostic pop