symbol.hpp 6.1 KB
Newer Older
K
Khaled Al-Hassanieh 已提交
1 2 3 4 5 6 7 8
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <fc/exception/exception.hpp>
#include <eosio/chain/types.hpp>
#include <string>
9
#include <functional>
K
Khaled Al-Hassanieh 已提交
10 11 12

namespace eosio {
   namespace chain {
13 14 15 16 17 18 19 20 21

      /**
         class symbol represents a token and contains precision and name.
         When encoded as a uint64_t, first byte represents the number of decimals, remaining bytes
         represent token name.
         Name must only include upper case alphabets.
         from_string constructs a symbol from an input a string of the form "4,EOS"
         where the integer represents number of decimals. Number of decimals must be larger than zero.
       */
22

23
      static constexpr uint64_t string_to_symbol_c(uint8_t precision, const char* str) {
K
Khaled Al-Hassanieh 已提交
24
         uint32_t len = 0;
25
         while (str[len]) ++len;
26

K
Khaled Al-Hassanieh 已提交
27
         uint64_t result = 0;
28 29
         // No validation is done at compile time
         for (uint32_t i = 0; i < len; ++i) {
30
            result |= (uint64_t(str[i]) << (8*(1+i)));
K
Khaled Al-Hassanieh 已提交
31 32 33 34 35
         }

         result |= uint64_t(precision);
         return result;
      }
36

37
#define SY(P,X) ::eosio::chain::string_to_symbol_c(P,#X)
K
Khaled Al-Hassanieh 已提交
38

39 40 41 42 43 44
      static uint64_t string_to_symbol(uint8_t precision, const char* str) {
         try {
            uint32_t len = 0;
            while(str[len]) ++len;
            uint64_t result = 0;
            for (uint32_t i = 0; i < len; ++i) {
A
Andrianto Lie 已提交
45
               // All characters must be upper case alphabets
46 47 48 49 50 51
               FC_ASSERT (str[i] >= 'A' && str[i] <= 'Z', "invalid character in symbol name");
               result |= (uint64_t(str[i]) << (8*(i+1)));
            }
            result |= uint64_t(precision);
            return result;
         } FC_CAPTURE_LOG_AND_RETHROW((str))
K
Khaled Al-Hassanieh 已提交
52 53
      }

A
arhag 已提交
54
      struct symbol_code {
55
         uint64_t value;
56 57

         operator uint64_t()const { return value; }
58 59
      };

K
Khaled Al-Hassanieh 已提交
60
      class symbol {
61
         public:
62 63 64 65

            static constexpr uint8_t max_precision = 18;

            explicit symbol(uint8_t p, const char* s): m_value(string_to_symbol(p, s)) {
K
Kevin Heifner 已提交
66
               FC_ASSERT(valid(), "invalid symbol", ("s",s));
67 68
            }
            explicit symbol(uint64_t v = SY(4, EOS)): m_value(v) {
K
Kevin Heifner 已提交
69
               FC_ASSERT(valid(), "invalid symbol", ("name",name()));
70
            }
71 72 73 74
            static symbol from_string(const string& from)
            {
               try {
                  string s = fc::trim(from);
75
                  FC_ASSERT(!s.empty(), "creating symbol from empty string");
76
                  auto comma_pos = s.find(',');
77
                  FC_ASSERT(comma_pos != string::npos, "missing comma in symbol");
78 79 80
                  auto prec_part = s.substr(0, comma_pos);
                  uint8_t p = fc::to_int64(prec_part);
                  string name_part = s.substr(comma_pos + 1);
81
                  FC_ASSERT( p <= max_precision, "precision should be <= 18");
82
                  return symbol(string_to_symbol(p, name_part.c_str()));
83
               } FC_CAPTURE_LOG_AND_RETHROW((from))
84 85 86
            }
            uint64_t value() const { return m_value; }
            bool valid() const
87
            {
88
               const auto& s = name();
89
               return decimals() <= max_precision && valid_name(s);
90
            }
91 92 93 94 95
            static bool valid_name(const string& name)
            {
               return all_of(name.begin(), name.end(), [](char c)->bool { return (c >= 'A' && c <= 'Z'); });
            }

96 97 98
            uint8_t decimals() const { return m_value & 0xFF; }
            uint64_t precision() const
            {
M
Matias Romeo 已提交
99 100 101 102 103 104
               uint64_t p10 = 1;
               uint64_t p = decimals();
               while( p > 0  ) {
                  p10 *= 10; --p;
               }
               return p10;
105 106 107 108 109 110 111 112 113 114
            }
            string name() const
            {
               uint64_t v = m_value;
               v >>= 8;
               string result;
               while (v > 0) {
                  char c = v & 0xFF;
                  result += c;
                  v >>= 8;
K
Khaled Al-Hassanieh 已提交
115
               }
116 117
               return result;
            }
118

A
arhag 已提交
119
            symbol_code to_symbol_code()const { return {m_value >> 8}; }
120

121 122 123 124 125 126 127 128 129
            explicit operator string() const
            {
               uint64_t v = m_value;
               uint8_t p = v & 0xFF;
               string ret = eosio::chain::to_string(p);
               ret += ',';
               ret += name();
               return ret;
            }
K
Khaled Al-Hassanieh 已提交
130

131 132 133 134 135 136
            string to_string() const { return string(*this); }
            template <typename DataStream>
            friend DataStream& operator<< (DataStream& ds, const symbol& s)
            {
               return ds << s.to_string();
            }
137

138 139 140
         private:
            uint64_t m_value;
            friend struct fc::reflector<symbol>;
141
      }; // class symbol
K
Khaled Al-Hassanieh 已提交
142

143 144 145 146 147
      struct extended_symbol {
         symbol       sym;
         account_name contract;
      };

K
Khaled Al-Hassanieh 已提交
148 149 150 151
      inline bool operator== (const symbol& lhs, const symbol& rhs)
      {
         return lhs.value() == rhs.value();
      }
152 153 154 155
      inline bool operator!= (const symbol& lhs, const symbol& rhs)
      {
         return lhs.value() != rhs.value();
      }
K
Khaled Al-Hassanieh 已提交
156 157 158 159 160 161 162 163 164
      inline bool operator< (const symbol& lhs, const symbol& rhs)
      {
         return lhs.value() < rhs.value();
      }
      inline bool operator> (const symbol& lhs, const symbol& rhs)
      {
         return lhs.value() > rhs.value();
      }

165
   } // namespace chain
K
Khaled Al-Hassanieh 已提交
166 167 168 169 170 171 172 173 174
} // namespace eosio

namespace fc {
   inline void to_variant(const eosio::chain::symbol& var, fc::variant& vo) { vo = var.to_string(); }
   inline void from_variant(const fc::variant& var, eosio::chain::symbol& vo) {
      vo = eosio::chain::symbol::from_string(var.get_string());
   }
}

175
namespace fc {
A
arhag 已提交
176
   inline void to_variant(const eosio::chain::symbol_code& var, fc::variant& vo) {
177 178
      vo = eosio::chain::symbol(var.value << 8).name();
   }
A
arhag 已提交
179 180
   inline void from_variant(const fc::variant& var, eosio::chain::symbol_code& vo) {
      vo = eosio::chain::symbol(0, var.get_string().c_str()).to_symbol_code();
181 182 183
   }
}

A
arhag 已提交
184
FC_REFLECT(eosio::chain::symbol_code, (value))
K
Khaled Al-Hassanieh 已提交
185
FC_REFLECT(eosio::chain::symbol, (m_value))
186
FC_REFLECT(eosio::chain::extended_symbol, (sym)(contract))