需要对solidity的应用二进制接口进行编码,因此简单的模仿json库的类型格式进行封装。
头文件如下:
#pragma once
#include "define.h"
enum ValueType {
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
longlongValue,
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
ListStringValue, ///< array value (ordered list)
ListDoubleValue,
ListIntValue,
AddressValue,
ListAddressValue,
ByteValue ///< object value (collection of name/value pairs).
};
const int INTMAX = 2147483647;
const int INTMIN = -2147483647;
const unsigned int TOTALMIN = 4294967295;
typedef list<string> listStr;
typedef list<int> listInt;
typedef list<double> listDouble;
typedef list<Address*> listAddress;
class EthType
{
public:
EthType(ValueType type = nullValue);
EthType(int value);
EthType(unsigned int value);
EthType(int64_t value);
EthType(uint64_t value);
EthType(Address *value);
EthType(float value);
EthType(double value);
EthType(const string& value);
EthType(const char *value);
EthType(bool value);
EthType(const EthType& other);
EthType(listStr *value);
EthType(listAddress *value);
EthType(list<double> *value);
EthType(list<int> *value);
EthType(byte *value);
~EthType();
int asInt()const;
unsigned int asUint()const;
int64_t asInt64()const;
uint64_t asUint64()const;
float asFloat()const;
double asDouble()const;
bool asBool()const;
string asString()const;
listStr asListString();
list<double> asListDouble();
list<int> asListint();
byte* asBytes();
Address* asAddress()const;
listAddress asListAddress()const;
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isDouble() const;
bool isString() const;
bool isBytes() const;
bool isListString()const;
bool isListDouble()const;
bool isListint()const;
bool isAddress()const;
bool isListAddress()const;
bool empty() const;
void setType(ValueType type_);
ValueType getType()const;
void setStringValue(const string& value);
void setAddressValue(Address* value);
void setIntValue(int value);
void setUIntValue(unsigned int value);
void setInt64Value(int64_t value);
void setUInt64Value(uint64_t value);
void setFloatValue(float value);
void setDoubleValue(double value);
void setCharsValue(const char *value);
void setBoolValue(bool value);
void setListStringValue(listStr *value);
void setListDoubleValue(list<double> *value);
void setListIntValue(list<int> *value);
void setBytesValue(byte *value);
void setListAddressValue(listAddress *value);
private:
union ValueHolder {
long long int_;
unsigned long long uint_;
double real_;
bool bool_;
char* string_; // if allocated_, ptr to { unsigned, char[] }.
listStr *l_str;
listInt *l_int;
listDouble *l_double;
byte *bytes;
Address* addr;
listAddress*l_addr;
} value_;
//此处使用联合体来进行存储数据(占用同一空间)
bool isAllocated = false;
ValueType type;
};
cpp文件:
#include "TypeValue.h"
static inline char* duplicateAndPrefixStringValue(const char* value,
unsigned int length) {
if (value == nullptr) return nullptr;
auto newString = (char *)malloc(length + 1);
memcpy(newString, value, length + 1);
return newString;
}
EthType::EthType(ValueType type)
{
this->type = type;
}
EthType::EthType(int value)
{
setIntValue(value);
}
void EthType::setIntValue(int value)
{
type = intValue;
value_.int_ = value;
}
EthType::EthType(unsigned int value)
{
setUIntValue(value);
}
void EthType::setUIntValue(unsigned int value)
{
type = uintValue;
value_.uint_ = value;
}
EthType::EthType(int64_t value)
{
setInt64Value(value);
}
void EthType::setInt64Value(int64_t value)
{
type = longlongValue;
value_.int_ = value;
}
void EthType::setUInt64Value(uint64_t value)
{
type = uintValue;
value_.uint_ = value;
}
EthType::EthType(uint64_t value)
{
setUInt64Value(value);
}
EthType::EthType(float value)
{
setFloatValue(value);
}
EthType::EthType(double value)
{
setDoubleValue(value);
}
void EthType::setFloatValue(float value)
{
type = realValue;
value_.real_ = value;
}
void EthType::setDoubleValue(double value)
{
type = realValue;
value_.real_ = value;
}
EthType::EthType(const string& value)
{
setStringValue(value);
}
void EthType::setStringValue(const string &value)
{
type = stringValue;
if (value_.string_ != nullptr && isAllocated)
{
free(value_.string_);
value_.string_ = nullptr;
}
value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
isAllocated = true;
}
EthType::EthType(const char *value)
{
setCharsValue(value);
}
void EthType::setCharsValue(const char *value)
{
type = stringValue;
if (value_.string_ != nullptr&& isAllocated)
{
free(value_.string_);
value_.string_ = nullptr;
}
value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
isAllocated = true;
}
void EthType::setBoolValue(bool value)
{
type = booleanValue;
value_.bool_ = value;
}
EthType::EthType(bool value)
{
setBoolValue(value);
}
EthType::EthType(const EthType& other)
{
this->type = other.type;
if (type == stringValue)
{
string cc = other.asString();
if (value_.string_ != nullptr&& isAllocated)
{
free(value_.string_);
value_.string_ = nullptr;
}
value_.string_ = duplicateAndPrefixStringValue(cc.data(), static_cast<unsigned>(cc.length()));
isAllocated = true;
}
}
void EthType::setType(ValueType type_)
{
type = type_;
}
ValueType EthType::getType()const
{
return type;
}
EthType::~EthType()
{
if (value_.string_ != nullptr && type == stringValue)
free(value_.string_);
// value_.uint_ = 0;
}
int EthType::asInt()const
{
switch (type)
{
case intValue:
return value_.int_;
case uintValue:
return (unsigned int)value_.int_;
case realValue:
return (int)value_.real_;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
return false;
}
unsigned int EthType::asUint()const
{
switch (type)
{
case intValue:
return (unsigned int)value_.int_;
case uintValue:
return value_.int_;
case realValue:
return (unsigned int)value_.real_;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
return false;
}
int64_t EthType::asInt64()const
{
switch (type)
{
case intValue:
return value_.int_;
case uintValue:
return value_.int_;
case realValue:
return (int64_t)value_.real_;
case longlongValue:
return (int64_t)value_.int_;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
return false;
}
uint64_t EthType::asUint64()const
{
switch (type)
{
case intValue:
return value_.int_;
case uintValue:
return value_.int_;
case realValue:
return (uint64_t)value_.real_;
case longlongValue:
return (uint64_t)value_.int_;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
return false;
}
float EthType::asFloat()const
{
switch (type)
{
case intValue:
return (float)value_.int_;
case uintValue:
return (float)value_.uint_;
case longlongValue:
return (float)value_.int_;
case realValue:
return value_.real_;
default:
break;
}
return false;
}
double EthType::asDouble()const
{
switch (type)
{
case intValue:
return (double)value_.int_;
case uintValue:
return (double)value_.uint_;
case longlongValue:
return (double)value_.int_;
case realValue:
return value_.real_;
default:
break;
}
return false;
}
bool EthType::asBool()const
{
switch (type)
{
case intValue:
return value_.int_;
case uintValue:
return value_.uint_;
case longlongValue:
return value_.int_;
case realValue:
return value_.real_;
case stringValue:
return value_.string_;
case booleanValue:
return value_.bool_;
default:
break;
}
return false;
}
string EthType::asString()const
{
switch (type) {
case nullValue:
return "";
case stringValue:
{
if (value_.string_ == nullptr)
return "";
return string(value_.string_);
}
case booleanValue:
return value_.bool_ ? "true" : "false";
case intValue:
return to_string(value_.int_);
case uintValue:
return to_string(value_.uint_);
case realValue:
return to_string(value_.real_);
default:
cout << "type is not convertible to string";
}
return "";
}
bool EthType::isNull() const
{
return type == nullValue;
}
bool EthType::isBool() const
{
return type == booleanValue;
}
bool EthType::isInt() const
{
switch (type)
{
case nullValue:
break;
case intValue:
return value_.int_ > INTMIN && value_.int_ <= INTMAX;
case uintValue:
return value_.int_ >= 0 && value_.int_ <= INTMAX;
case longlongValue:
return value_.int_ < INTMAX;
case realValue:
break;
default:
break;
}
return false;
}
bool EthType::isInt64() const
{
return type == intValue;
}
bool EthType::isUInt() const
{
return type == uintValue;
}
bool EthType::isUInt64() const
{
return type == uintValue;
}
bool EthType::isDouble() const
{
return type == intValue || type == uintValue || type == realValue;
}
bool EthType::isString() const
{
return type == stringValue;
}
bool EthType::empty() const
{
return type == nullValue;
}
listStr EthType::asListString()
{
if (type == ListStringValue)
{
return *value_.l_str;
}
else
return listStr();
}
EthType::EthType(listStr *value)
{
setListStringValue(value);
}
EthType::EthType(list<double> *value)
{
setListDoubleValue(value);
}
EthType::EthType(list<int> *value)
{
setListIntValue(value);
}
list<double> EthType::asListDouble()
{
if (type == ListDoubleValue)
{
return *value_.l_double;
}
else
return list<double>();
}
list<int> EthType::asListint()
{
if (type == ListIntValue)
{
return *value_.l_int;
}
else
return list<int>();
}
void EthType::setListStringValue(listStr *value)
{
type = ListStringValue;
value_.l_str = value;
}
void EthType::setListDoubleValue(list<double> *value)
{
type = ListDoubleValue;
value_.l_double = value;
}
void EthType::setListIntValue(list<int> *value)
{
type = ListIntValue;
value_.l_int = value;
}
void EthType::setBytesValue(byte *value)
{
type = ByteValue;
if (value_.bytes != nullptr && isAllocated)
{
free(value_.bytes);
value_.bytes = nullptr;
}
value_.bytes = value;
isAllocated = true;
}
EthType::EthType(byte *value)
{
setBytesValue(value);
}
byte* EthType::asBytes()
{
return value_.bytes;
}
bool EthType::isBytes() const
{
return type == ByteValue;
}
bool EthType::isListString()const
{
return type == ListStringValue;
}
bool EthType::isListDouble()const
{
return type == ListDoubleValue;
}
bool EthType::isListint()const
{
return type == ListIntValue;
}
EthType::EthType(Address *value)
{
setAddressValue(value);
}
void EthType::setAddressValue(Address* value)
{
type = AddressValue;
if (value != nullptr)
{
value_.addr = value;
}
}
bool EthType::isAddress()const
{
return type == AddressValue;
}
Address* EthType::asAddress()const
{
if (type == AddressValue)
{
return value_.addr;
}
else
return nullptr;
}
EthType::EthType(listAddress *value)
{
setListAddressValue(value);
}
listAddress EthType::asListAddress()const
{
if (type == ListAddressValue)
return *value_.l_addr;
return listAddress();
}
bool EthType::isListAddress()const
{
return type == ListAddressValue;
}
void EthType::setListAddressValue(listAddress * value)
{
type = ListAddressValue;
value_.l_addr = value;
}
为什么要进行类型的封装呢?主要是方便于后期对应用二进制接口编码时好进行相关的操作。(代码比较粗糙,没有进行优化)
对于address类型的封装,我用得比较笨的方式去实现(类里面存储一个string变量),为什么不直接存储string的原因是,address 和 string应用二进制接口编码不一样,所以才进行这样的封装。
class Address
{
public:
Address(std::string hexVal);
std::string getValue();
std::string getType();
private:
std::string value;
};
Address::Address(std::string hexVal)
{
value = hexVal;
}
std::string Address::getValue()
{
return value;
}
std::string Address::getType() {
return "Address";
}
在这里只是为了实现功能,达到相关的目的,没有对其进行重构优化等。