Code improvements:

A way to avoid duplicate field indexes that Arthur came up with.
Abstract out code to create individual fields.
Field index operations.
Flag operations.
Optional field operations.
This commit is contained in:
JoelKatz
2012-03-25 00:04:59 -07:00
parent 4ac2aefe48
commit 38cecf2d8f
5 changed files with 306 additions and 123 deletions

View File

@@ -1,53 +1,100 @@
#include "SerializedObject.h"
STObject::STObject(SOElement* elem, const char *name) : SerializedType(name)
SerializedType* STObject::makeDefaultObject(SerializedTypeID id, const char *name)
{
switch(id)
{
case STI_UINT16:
return new STUInt16(name);
case STI_UINT32:
return new STUInt32(name);
case STI_UINT64:
return new STUInt64(name);
case STI_HASH160:
return new STHash160(name);
case STI_HASH256:
return new STHash256(name);
case STI_VL:
return new STVariableLength(name);
case STI_TL:
return new STTaggedList(name);
#if 0
case STI_ACCOUNT: // CHECKME: Should an account be variable length?
return new STVariableLength(name);
#endif
default:
return NULL;
}
}
SerializedType* STObject::makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator& sit)
{
switch(id)
{
case STI_UINT16:
return STUInt16::construct(sit, name);
case STI_UINT32:
return STUInt32::construct(sit, name);
case STI_UINT64:
return STUInt64::construct(sit, name);
case STI_HASH160:
return STHash160::construct(sit, name);
case STI_HASH256:
return STHash256::construct(sit, name);
case STI_VL:
return STVariableLength::construct(sit, name);
case STI_TL:
return STTaggedList::construct(sit, name);
#if 0
case STI_ACCOUNT: // CHECKME: Should an account be variable length?
return STVariableLength::construct(sit, name);
#endif
default:
return NULL;
}
}
STObject::STObject(SOElement* elem, const char *name) : SerializedType(name), mFlagIdx(-1)
{
while(elem->e_id!=STI_DONE)
{
type.push_back(elem);
if(elem->e_type==SOE_FLAGS) mFlagIdx=mType.size();
mType.push_back(elem);
if( (elem->e_type==SOE_IFFLAG) || (elem->e_type==SOE_IFNFLAG) )
giveObject(new STObject(elem->e_name));
else switch(elem->e_id)
else
{
case STI_UINT16:
giveObject(new STUInt16(elem->e_name));
break;
case STI_UINT32:
giveObject(new STUInt32(elem->e_name));
break;
case STI_UINT64:
giveObject(new STUInt64(elem->e_name));
break;
case STI_HASH160:
giveObject(new STHash160(elem->e_name));
break;
case STI_HASH256:
giveObject(new STHash256(elem->e_name));
break;
case STI_VL:
giveObject(new STVariableLength(elem->e_name));
break;
case STI_TL:
giveObject(new STTaggedList(elem->e_name));
break;
#if 0
case STI_ACCOUNT: // CHECKME: Should an account be variable length?
giveObject(new STVariableLength(elem->e_name));
break;
#endif
default: throw(std::runtime_error("invalid transaction element"));
SerializedType* t=makeDefaultObject(elem->e_id, elem->e_name);
if(!t) throw(std::runtime_error("invalid transaction element"));
giveObject(t);
}
elem++;
}
}
STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) : SerializedType(name)
STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) : SerializedType(name), mFlagIdx(-1)
{
int flags=-1;
while(elem->e_id!=STI_DONE)
{
type.push_back(elem);
mType.push_back(elem);
bool done=false;
if(elem->e_type==SOE_IFFLAG)
{
@@ -63,41 +110,14 @@ STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) :
{
assert(elem->e_id==STI_UINT16);
flags=sit.get16();
giveObject(new STUInt16(elem->e_name, flags));
mFlagIdx=giveObject(new STUInt16(elem->e_name, flags));
done=true;
}
if(!done)
{
switch(elem->e_id)
{
case STI_UINT16:
giveObject(STUInt16::construct(sit, elem->e_name));
break;
case STI_UINT32:
giveObject(STUInt32::construct(sit, elem->e_name));
break;
case STI_UINT64:
giveObject(STUInt64::construct(sit, elem->e_name));
break;
case STI_HASH160:
giveObject(STHash160::construct(sit, elem->e_name));
break;
case STI_HASH256:
giveObject(STHash256::construct(sit, elem->e_name));
break;
case STI_VL:
giveObject(STVariableLength::construct(sit, elem->e_name));
break;
case STI_TL:
giveObject(STTaggedList::construct(sit, elem->e_name));
break;
#if 0
case STI_ACCOUNT: // CHECKME: Should an account be variable length?
giveObject(STVariableLength::construct(sit, elem->e_name));
break;
#endif
default: throw(std::runtime_error("invalid transaction element"));
}
SerializedType* t=makeDeserializedObject(elem->e_id, elem->e_name, sit);
if(!t) throw(std::runtime_error("invalid transaction element"));
giveObject(t);
}
elem++;
}
@@ -112,7 +132,7 @@ std::string STObject::getFullText() const
ret+=" = {";
}
else ret="{";
for(boost::ptr_vector<SerializedType>::const_iterator it=data.begin(), end=data.end(); it!=end; ++it)
for(boost::ptr_vector<SerializedType>::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it)
ret+=it->getFullText();
ret+="}";
return ret;
@@ -121,14 +141,14 @@ std::string STObject::getFullText() const
int STObject::getLength() const
{
int ret=0;
for(boost::ptr_vector<SerializedType>::const_iterator it=data.begin(), end=data.end(); it!=end; ++it)
for(boost::ptr_vector<SerializedType>::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it)
ret+=it->getLength();
return ret;
}
void STObject::add(Serializer& s) const
{
for(boost::ptr_vector<SerializedType>::const_iterator it=data.begin(), end=data.end(); it!=end; ++it)
for(boost::ptr_vector<SerializedType>::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it)
it->add(s);
}
@@ -136,7 +156,7 @@ std::string STObject::getText() const
{
std::string ret="{";
bool first=false;
for(boost::ptr_vector<SerializedType>::const_iterator it=data.begin(), end=data.end(); it!=end; ++it)
for(boost::ptr_vector<SerializedType>::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it)
{
if(!first)
{
@@ -148,3 +168,90 @@ std::string STObject::getText() const
ret+="}";
return ret;
}
int STObject::getFieldIndex(SOE_Field field) const
{
int i=0;
for(std::vector<SOElement*>::const_iterator it=mType.begin(), end=mType.end(); it!=end; ++it, ++i)
if((*it)->e_field==field) return i;
return -1;
}
const SerializedType& STObject::peekAtField(SOE_Field field) const
{
int index=getFieldIndex(field);
if(index==-1) throw std::runtime_error("Field not found");
return peekAtIndex(index);
}
SerializedType& STObject::getField(SOE_Field field)
{
int index=getFieldIndex(field);
if(index==-1) throw std::runtime_error("Field not found");
return getIndex(index);
}
const SerializedType* STObject::peekAtPField(SOE_Field field)
{
int index=getFieldIndex(field);
if(index==-1) return NULL;
return peekAtPIndex(index);
}
SerializedType* STObject::getPField(SOE_Field field)
{
int index=getFieldIndex(field);
if(index==-1) return NULL;
return getPIndex(index);
}
bool STObject::isFieldPresent(SOE_Field field) const
{
int index=getFieldIndex(field);
if(index==-1) return false;
return peekAtIndex(field).getType()==STI_OBJECT;
}
bool STObject::setFlag(int f)
{
if(mFlagIdx<0) return false;
STUInt16* t=dynamic_cast<STUInt16*>(getPIndex(mFlagIdx));
assert(t);
t->setValue(t->getValue() | f);
return true;
}
bool STObject::clearFlag(int f)
{
if(mFlagIdx<0) return false;
STUInt16* t=dynamic_cast<STUInt16*>(getPIndex(mFlagIdx));
assert(t);
t->setValue(t->getValue() & ~f);
return true;
}
int STObject::getFlag(void) const
{
if(mFlagIdx<0) return 0;
const STUInt16* t=dynamic_cast<const STUInt16*>(peekAtPIndex(mFlagIdx));
assert(t);
return t->getValue();
}
void STObject::makeFieldPresent(SOE_Field field)
{
int index=getFieldIndex(field);
if(index==-1) throw std::runtime_error("Field not found");
if(peekAtIndex(field).getType()!=STI_OBJECT) return;
mData.replace(index, makeDefaultObject(mType[index]->e_id, mType[index]->e_name));
setFlag(mType[index]->e_flags);
}
void STObject::makeFieldAbsent(SOE_Field field)
{
int index=getFieldIndex(field);
if(index==-1) throw std::runtime_error("Field not found");
if(peekAtIndex(field).getType()==STI_OBJECT) return;
mData.replace(index, new STObject(mType[index]->e_name));
clearFlag(mType[index]->e_flags);
}

View File

@@ -12,8 +12,22 @@ enum SOE_Type
SOE_NEVER=-1, SOE_REQUIRED=0, SOE_FLAGS, SOE_IFFLAG=1, SOE_IFNFLAG=2
};
enum SOE_Field
{
sfInvalid=-1,
sfGeneric=0,
// common fields
sfFlags, sfSequence, sfExtensions, sfTargetLedger, sfSourceTag, sfIdentifier,
sfDestination, sfTarget, sfAmount, sfCurrency,
sfAmountIn, sfAmountOut, sfCurrencyIn, sfCurrencyOut,
sfInvoiceID,
sfExpireLedger
};
struct SOElement
{ // An element in the description of a serialized object
SOE_Field e_field;
const char *e_name;
SerializedTypeID e_id;
SOE_Type e_type;
@@ -23,11 +37,15 @@ struct SOElement
class STObject : public SerializedType
{
protected:
boost::ptr_vector<SerializedType> data;
std::vector<SOElement*> type;
int mFlagIdx; // the offset to the flags object, -1 if none
boost::ptr_vector<SerializedType> mData;
std::vector<SOElement*> mType;
static SerializedType* makeDefaultObject(SerializedTypeID id, const char *name);
static SerializedType* makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator&);
public:
STObject(const char *n=NULL) : SerializedType(n) { ; }
STObject(const char *n=NULL) : SerializedType(n), mFlagIdx(-1) { ; }
STObject(SOElement *t, const char *n=NULL);
STObject(SOElement *t, SerializerIterator& u, const char *n=NULL);
virtual ~STObject() { ; }
@@ -40,16 +58,33 @@ public:
std::string getFullText() const;
std::string getText() const;
void addObject(const SerializedType& t) { data.push_back(t.duplicate()); }
void giveObject(SerializedType* t) { data.push_back(t); }
const boost::ptr_vector<SerializedType>& peekData() const { return data; }
boost::ptr_vector<SerializedType>& peekData() { return data; }
int addObject(const SerializedType& t) { mData.push_back(t.duplicate()); return mData.size()-1; }
int giveObject(SerializedType* t) { mData.push_back(t); return mData.size()-1; }
const boost::ptr_vector<SerializedType>& peekData() const { return mData; }
boost::ptr_vector<SerializedType>& peekData() { return mData; }
int getCount() const { return data.size(); }
const SerializedType& peekAt(int offset) const { return data[offset]; }
SerializedType& getAt(int offset) { return data[offset]; }
const SerializedType* peekAtP(int offset) const { return &(data[offset]); }
SerializedType* getAtP(int offset) { return &(data[offset]); }
int getCount() const { return mData.size(); }
bool setFlag(int);
bool clearFlag(int);
int getFlag() const;
const SerializedType& peekAtIndex(int offset) const { return mData[offset]; }
SerializedType& getIndex(int offset) { return mData[offset]; }
const SerializedType* peekAtPIndex(int offset) const { return &(mData[offset]); }
SerializedType* getPIndex(int offset) { return &(mData[offset]); }
int getFieldIndex(SOE_Field field) const;
const SerializedType& peekAtField(SOE_Field field) const;
SerializedType& getField(SOE_Field field);
const SerializedType* peekAtPField(SOE_Field field);
SerializedType* getPField(SOE_Field field);
const SOElement* getFieldType(SOE_Field field) const;
bool isFieldPresent(SOE_Field field) const;
void makeFieldPresent(SOE_Field field);
void makeFieldAbsent(SOE_Field field);
};

View File

@@ -103,28 +103,64 @@ void SerializedTransaction::setSignature(const std::vector<unsigned char>& sig)
uint32 SerializedTransaction::getVersion() const
{
const STUInt32* v=dynamic_cast<const STUInt32*>(mMiddleTxn.peekAtP(0));
const STUInt32* v=dynamic_cast<const STUInt32*>(mMiddleTxn.peekAtPIndex(0));
if(!v) throw(std::runtime_error("corrupt transaction"));
return v->getValue();
}
void SerializedTransaction::setVersion(uint32 ver)
{
STUInt32* v=dynamic_cast<STUInt32*>(mMiddleTxn.getAtP(0));
STUInt32* v=dynamic_cast<STUInt32*>(mMiddleTxn.getPIndex(0));
if(!v) throw(std::runtime_error("corrupt transaction"));
v->setValue(ver);
}
uint64 SerializedTransaction::getTransactionFee() const
{
const STUInt64* v=dynamic_cast<const STUInt64*>(mMiddleTxn.peekAtP(3));
const STUInt64* v=dynamic_cast<const STUInt64*>(mMiddleTxn.peekAtPIndex(3));
if(!v) throw(std::runtime_error("corrupt transaction"));
return v->getValue();
}
void SerializedTransaction::setTransactionFee(uint64 fee)
{
STUInt64* v=dynamic_cast<STUInt64*>(mMiddleTxn.getAtP(3));
STUInt64* v=dynamic_cast<STUInt64*>(mMiddleTxn.getPIndex(3));
if(!v) throw(std::runtime_error("corrupt transaction"));
v->setValue(fee);
}
int SerializedTransaction::getITFieldIndex(SOE_Field field) const
{
return mInnerTxn.getFieldIndex(field);
}
int SerializedTransaction::getITFieldCount() const
{
return mInnerTxn.getCount();
}
bool SerializedTransaction::getITFieldPresent(SOE_Field field) const
{
return mInnerTxn.isFieldPresent(field);
}
const SerializedType& SerializedTransaction::peekITField(SOE_Field field)
{
return mInnerTxn.peekAtField(field);
}
SerializedType& SerializedTransaction::getITField(SOE_Field field)
{
return mInnerTxn.getField(field);
}
void SerializedTransaction::makeITFieldPresent(SOE_Field field)
{
return mInnerTxn.makeFieldPresent(field);
}
void SerializedTransaction::makeITFieldAbsent(SOE_Field field)
{
return mInnerTxn.makeFieldAbsent(field);
}

View File

@@ -49,12 +49,15 @@ public:
void setSequence(uint32);
// inner transaction field functions
int getITFieldIndex(const char *) const;
int getITFieldIndex(SOE_Field field) const;
int getITFieldCount() const;
bool getITFieldPresent(int index) const;
const SerializedType& peekITField(int index);
SerializedType& getITField(int index);
void makeITFieldPresent(int index);
const SerializedType& peekITField(SOE_Field field);
SerializedType& getITField(SOE_Field field);
// optional field functions
bool getITFieldPresent(SOE_Field field) const;
void makeITFieldPresent(SOE_Field field);
void makeITFieldAbsent(SOE_Field field);
// whole transaction functions
int getTransaction(Serializer& s, bool include_length) const;

View File

@@ -1,49 +1,51 @@
#include "TransactionFormats.h"
#define S_FIELD(x) sf##x, #x
TransactionFormat InnerTxnFormats[]=
{
{ "MakePayment", ttMAKE_PAYMENT, {
{ "Flags", STI_UINT16, SOE_FLAGS, 0 },
{ "Sequence", STI_UINT32, SOE_REQUIRED, 0 },
{ "Destination", STI_ACCOUNT, SOE_REQUIRED, 0 },
{ "Amount", STI_UINT64, SOE_REQUIRED, 0 },
{ "Currency", STI_HASH160, SOE_IFFLAG, 1 },
{ "SourceTag", STI_UINT32, SOE_IFFLAG, 2 },
{ "TargetLedger", STI_UINT32, SOE_IFFLAG, 4 },
{ "InvoiceID", STI_HASH256, SOE_IFFLAG, 8 },
{ "Extensions", STI_TL, SOE_IFFLAG, 32768 },
{ NULL, STI_DONE, SOE_NEVER, -1 } }
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Amount), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Invoice", ttINVOICE, {
{ "Flags", STI_UINT16, SOE_FLAGS, 0 },
{ "Sequence", STI_UINT32, SOE_REQUIRED, 0 },
{ "Target", STI_ACCOUNT, SOE_REQUIRED, 0 },
{ "Amount", STI_UINT64, SOE_REQUIRED, 0 },
{ "Currency", STI_HASH160, SOE_IFFLAG, 1 },
{ "SourceTag", STI_UINT32, SOE_IFFLAG, 2 },
{ "Destination", STI_ACCOUNT, SOE_IFFLAG, 4 },
{ "TargetLedger", STI_UINT32, SOE_IFFLAG, 8 },
{ "Identifier", STI_VL, SOE_IFFLAG, 16 },
{ "Extensions", STI_TL, SOE_IFFLAG, 32768 },
{ NULL, STI_DONE, SOE_NEVER, -1 } }
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Amount), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 16 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Offer", ttEXCHANGE_OFFER, {
{ "Flags", STI_UINT16, SOE_FLAGS, 0 },
{ "Sequence", STI_UINT32, SOE_REQUIRED, 0 },
{ "AmountIn", STI_UINT64, SOE_REQUIRED, 0 },
{ "CurrencyIn", STI_HASH160, SOE_IFFLAG, 2 },
{ "AmountOut", STI_UINT64, SOE_REQUIRED, 0 },
{ "CurrencyOut", STI_HASH160, SOE_IFFLAG, 4 },
{ "SourceTag", STI_UINT32, SOE_IFFLAG, 8 },
{ "Destination", STI_ACCOUNT, SOE_IFFLAG, 16 },
{ "TargetLedger", STI_UINT32, SOE_IFFLAG, 32 },
{ "ExpireLedger", STI_UINT32, SOE_IFFLAG, 64 },
{ "Identifier", STI_VL, SOE_IFFLAG, 128 },
{ "Extensions", STI_TL, SOE_IFFLAG, 32768 },
{ NULL, STI_DONE, SOE_NEVER, -1 } }
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(AmountIn), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(CurrencyIn), STI_HASH160, SOE_IFFLAG, 2 },
{ S_FIELD(AmountOut), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(CurrencyOut), STI_HASH160, SOE_IFFLAG, 4 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 16 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 32 },
{ S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 64 },
{ S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 128 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ NULL, ttINVALID }
{ NULL, ttINVALID }
};
TransactionFormat* getFormat(TransactionType t)