A
Andrea Crotti
I've been working on this project for quite a long time, and still I'm
not satisfied by the basic design and can't find a better way.
Instead of writing what I've done I'll write what I would like to have
(as a programmer-user) and then how I tried to solve it.
I have different types of packets, with a base header and some extra
fields depending on what the packet is for, like.
Packet
- field1
- field2
+ Packet2
- field3
and so on.
I would like to be able to:
Packet pkt(field1, field2);
sendStream(pkt.toNetworkStream());
and toNetworkStream is defined only once also for the derived packets.
I would like also that if I do
Packet *pkt = new Packet2(Packet1&, field3);
pkt.get("field3");
works too, without having to do dynamic_cast.
So what I have now is something like this:
--8<---------------cut here---------------start------------->8---
// class for managing the low level packets
class Packet : public Serializable
{
public:
Packet() {}
Packet(PACKET_TYPE);
PACKET_TYPE type;
std::vector<Serializable *> fields;
virtual void toBuffer(char *, int *) const;
// this function can't be overriden
Stream toStream() const;
virtual void setFields() {}
};
--8<---------------cut here---------------end--------------->8---
Where a serializable object is something that is able to generate a
stream of chars from itself.
The toStream() works nicely, since every object sets a vector of the
pointers to its fields.
But the initialization of a packet for example is not so nice:
--8<---------------cut here---------------start------------->8---
CoordReq::CoordReq(const PadNodeID& _id_dest,
const PadCoordinate& _coord_dest,
const PadNodeID& _id_src,
const PadCoordinate& _coord_src,
const PadNodeID& _to_find)
: MultiCastPacket(_id_dest, _coord_dest, _id_src, _coord_src),
to_find(_to_find)
{
setFields();
}
void CoordReq::setFields(){
type = COORD_REQ;
fields.push_back(&to_find);
}
--8<---------------cut here---------------end--------------->8---
Here MultiCastPacket has the four fields to initialize and then I add
only one extra field.
About the second problem instead I didn't really find a solution, and
I
ended up doing a dynamic_cast on the pointer to make sure I pass the
right pointer to the functions handling it.
Ending up in something like:
--8<---------------cut here---------------start------------->8---
switch (pkt->type) {
case ADDRESS_UPDATE:
handleAddressUpdate(dynamic_cast<AddressUpdate *>(pkt));
break;
--8<---------------cut here---------------end--------------->8---
I thought that a possible way was to substitute
std::vector<Serializable *> with
std::map<std::string, Serializable *>
And then instead of
obj.variable, only use obj.getField("field_name").
In this way I should solve my problems, but
1. the order of the fields might be messed up
2. I'm quite sure there are better ways even if I don't find them
Any advice?
Thanks,
Andrea
not satisfied by the basic design and can't find a better way.
Instead of writing what I've done I'll write what I would like to have
(as a programmer-user) and then how I tried to solve it.
I have different types of packets, with a base header and some extra
fields depending on what the packet is for, like.
Packet
- field1
- field2
+ Packet2
- field3
and so on.
I would like to be able to:
Packet pkt(field1, field2);
sendStream(pkt.toNetworkStream());
and toNetworkStream is defined only once also for the derived packets.
I would like also that if I do
Packet *pkt = new Packet2(Packet1&, field3);
pkt.get("field3");
works too, without having to do dynamic_cast.
So what I have now is something like this:
--8<---------------cut here---------------start------------->8---
// class for managing the low level packets
class Packet : public Serializable
{
public:
Packet() {}
Packet(PACKET_TYPE);
PACKET_TYPE type;
std::vector<Serializable *> fields;
virtual void toBuffer(char *, int *) const;
// this function can't be overriden
Stream toStream() const;
virtual void setFields() {}
};
--8<---------------cut here---------------end--------------->8---
Where a serializable object is something that is able to generate a
stream of chars from itself.
The toStream() works nicely, since every object sets a vector of the
pointers to its fields.
But the initialization of a packet for example is not so nice:
--8<---------------cut here---------------start------------->8---
CoordReq::CoordReq(const PadNodeID& _id_dest,
const PadCoordinate& _coord_dest,
const PadNodeID& _id_src,
const PadCoordinate& _coord_src,
const PadNodeID& _to_find)
: MultiCastPacket(_id_dest, _coord_dest, _id_src, _coord_src),
to_find(_to_find)
{
setFields();
}
void CoordReq::setFields(){
type = COORD_REQ;
fields.push_back(&to_find);
}
--8<---------------cut here---------------end--------------->8---
Here MultiCastPacket has the four fields to initialize and then I add
only one extra field.
About the second problem instead I didn't really find a solution, and
I
ended up doing a dynamic_cast on the pointer to make sure I pass the
right pointer to the functions handling it.
Ending up in something like:
--8<---------------cut here---------------start------------->8---
switch (pkt->type) {
case ADDRESS_UPDATE:
handleAddressUpdate(dynamic_cast<AddressUpdate *>(pkt));
break;
--8<---------------cut here---------------end--------------->8---
I thought that a possible way was to substitute
std::vector<Serializable *> with
std::map<std::string, Serializable *>
And then instead of
obj.variable, only use obj.getField("field_name").
In this way I should solve my problems, but
1. the order of the fields might be messed up
2. I'm quite sure there are better ways even if I don't find them
Any advice?
Thanks,
Andrea