M
ma740988
I've provided a stripped down version - as best I could - to get us by.
That said, I'm in a quandry with respect to a design here.
Consider:
// stream.h
#ifndef STREAM_H
#define STREAM_H
# pragma warning (disable : 4786) // if using microsofts compiler ver6
# include <iostream>
# include <string>
# include <map>
# include <typeinfo>
using namespace std;
struct stream
{
string classId;
string buffer;
size_t curPos;
stream(string clsId)
: classId(clsId), curPos(0)
{}
stream(char* buf, size_t size)
: curPos(0)
{
string temp(buf, size);
size_t pos = temp.find(':');
if (pos == string::npos || pos == 0 || pos == size-1)
return;
classId = temp.substr(0, pos);
buffer = temp.substr(pos+1);
}
bool isValid() { return curPos <= buffer.length(); }
operator bool() { return isValid(); }
size_t getBufferSize() {
return isValid()? classId.size() + 1 + buffer.size() : 0;
}
size_t getBuffer(char*& buf, size_t siz)
{
size_t sizNeeded = getBufferSize();
return sizNeeded;
}
};
template <class T>
inline stream& operator>>(stream& ds, T& t) {
// stuff
return ds;
}
template <class T>
inline stream& operator<<(stream& ds, T& t) {
// stuff
return ds;
}
// more
#endif
// factory.h
#ifndef FACTORY_H
#define FACTORY_H
# include<map>
# include<string>
# include "stream.h"
class factory;
typedef factory* (*CreateInstanceFunc)();
struct stream;
using namespace std;
class factory
{
// factory map is mapping class names to create functions
static std::map<std::string, CreateInstanceFunc> factoryMap;
public:
virtual std::string getClassId() = 0;
virtual bool load(stream& ds) = 0;
virtual bool store(stream& ds) = 0;
virtual void execute() = 0;
static factory* createInstance(const stream& ds)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(ds.classId)) == factoryMap.end())
return NULL;
return (it->second)();
}
static bool registerClass(
const std::string& className,
CreateInstanceFunc createFunc
)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(className)) != factoryMap.end())
return false; // already registered
factoryMap[className] = createFunc;
return true;
}
stream* store();
};
std::map<string, CreateInstanceFunc> factory::factoryMap;
#endif
// now we're ready file: test.cpp
# include <iostream>
# include <string>
# include "factory.h"
# include "stream.h"
using namespace std;
struct test_struct
: public factory
{
int idx;
test_struct() : idx(99) {}
std::string getClassId() {
return "test_struct";
}
bool store(stream& ds) {
ds >> idx;
return ds.isValid();
}
bool load(stream& ds) {
ds << idx;
return ds.isValid();
}
static factory* create_msg () {
return new test_struct;
}
void execute () {
}
};
/////////////////////////////////////////////////////////////////
// the registration below is REALLY bad news. Need to rethink this
// static initilization order stuff.
//factory::registerClass("test_struct", test_struct::create_msg);
class test {
test_struct* ptr_msg;
public:
test() : ptr_msg(0) {
factory::registerClass("test_struct", test_struct::create_msg);
}
void get_data()
{
char buffer[4096] = { "test_struct:99" };
size_t len = sizeof buffer / sizeof *buffer;
stream st (buffer, len);
if (st)
{
ptr_msg = (test_struct*)factory::createInstance(st); // 99
if (ptr_msg != NULL)
{
cout << " success " << endl;
if (ptr_msg->idx == 99)
cout << " even more success " << endl;
}
}
}
};
int main()
{
test t;
t.get_data();
}
The line marked '99' is a cast from a polymorphic type to a test_struct
object. So I thought it would nice to eliminate that ugly cast, hence
the addition of the 'execute' function in persistent.
Trouble is, the execute function creates a problem for two reasons:
1. I could modify the source in get_data to look like:
if (st)
{
//ptr_msg = (test_struct*)factory::createInstance(st);
factory* pfact = factory::createInstance(st);
if (pfact != NULL)
{
cout << " success " << endl;
pfact->execute();
//if (ptr_msg->idx == 99)
// cout << " even more success " << endl;
}
}
Except now I need a way to move from the factory object to a
test_struct object so that I could do:
if (ptr_msg->idx == 99)
// do a special thing.
One thought was to modify execute in the test_struc class to look like:
void execute () {
t.update(this); // call some update function in test
}
Trouble is. I now need a 'global' initilization of t. Not good. It
gets worse. In my real code, the initilization of t is wrapped in a
try catch handler so that there goes the global initilization.
2. In theory my 'struct's are defined as incoming and outging msg
structs. So now:
struct outgoing_msg
: public factory
{};
struct incoming_msg
: public factory
{};
The only struct that needs to go through these 'hoops' is the
incoming_msg struct. That said, I would have an execute member
function in the outgoing_msg struct for NO reason.
In the end I suspect I'm just forced to live with the cast from a
polymorphic object to a test_struct.
ptr_msg = (test_struct*)factory::createInstance(st);
Thoughts/ideas?
Thanks in advance
That said, I'm in a quandry with respect to a design here.
Consider:
// stream.h
#ifndef STREAM_H
#define STREAM_H
# pragma warning (disable : 4786) // if using microsofts compiler ver6
# include <iostream>
# include <string>
# include <map>
# include <typeinfo>
using namespace std;
struct stream
{
string classId;
string buffer;
size_t curPos;
stream(string clsId)
: classId(clsId), curPos(0)
{}
stream(char* buf, size_t size)
: curPos(0)
{
string temp(buf, size);
size_t pos = temp.find(':');
if (pos == string::npos || pos == 0 || pos == size-1)
return;
classId = temp.substr(0, pos);
buffer = temp.substr(pos+1);
}
bool isValid() { return curPos <= buffer.length(); }
operator bool() { return isValid(); }
size_t getBufferSize() {
return isValid()? classId.size() + 1 + buffer.size() : 0;
}
size_t getBuffer(char*& buf, size_t siz)
{
size_t sizNeeded = getBufferSize();
return sizNeeded;
}
};
template <class T>
inline stream& operator>>(stream& ds, T& t) {
// stuff
return ds;
}
template <class T>
inline stream& operator<<(stream& ds, T& t) {
// stuff
return ds;
}
// more
#endif
// factory.h
#ifndef FACTORY_H
#define FACTORY_H
# include<map>
# include<string>
# include "stream.h"
class factory;
typedef factory* (*CreateInstanceFunc)();
struct stream;
using namespace std;
class factory
{
// factory map is mapping class names to create functions
static std::map<std::string, CreateInstanceFunc> factoryMap;
public:
virtual std::string getClassId() = 0;
virtual bool load(stream& ds) = 0;
virtual bool store(stream& ds) = 0;
virtual void execute() = 0;
static factory* createInstance(const stream& ds)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(ds.classId)) == factoryMap.end())
return NULL;
return (it->second)();
}
static bool registerClass(
const std::string& className,
CreateInstanceFunc createFunc
)
{
map<string, CreateInstanceFunc>::iterator it;
if ((it = factoryMap.find(className)) != factoryMap.end())
return false; // already registered
factoryMap[className] = createFunc;
return true;
}
stream* store();
};
std::map<string, CreateInstanceFunc> factory::factoryMap;
#endif
// now we're ready file: test.cpp
# include <iostream>
# include <string>
# include "factory.h"
# include "stream.h"
using namespace std;
struct test_struct
: public factory
{
int idx;
test_struct() : idx(99) {}
std::string getClassId() {
return "test_struct";
}
bool store(stream& ds) {
ds >> idx;
return ds.isValid();
}
bool load(stream& ds) {
ds << idx;
return ds.isValid();
}
static factory* create_msg () {
return new test_struct;
}
void execute () {
}
};
/////////////////////////////////////////////////////////////////
// the registration below is REALLY bad news. Need to rethink this
// static initilization order stuff.
//factory::registerClass("test_struct", test_struct::create_msg);
class test {
test_struct* ptr_msg;
public:
test() : ptr_msg(0) {
factory::registerClass("test_struct", test_struct::create_msg);
}
void get_data()
{
char buffer[4096] = { "test_struct:99" };
size_t len = sizeof buffer / sizeof *buffer;
stream st (buffer, len);
if (st)
{
ptr_msg = (test_struct*)factory::createInstance(st); // 99
if (ptr_msg != NULL)
{
cout << " success " << endl;
if (ptr_msg->idx == 99)
cout << " even more success " << endl;
}
}
}
};
int main()
{
test t;
t.get_data();
}
The line marked '99' is a cast from a polymorphic type to a test_struct
object. So I thought it would nice to eliminate that ugly cast, hence
the addition of the 'execute' function in persistent.
Trouble is, the execute function creates a problem for two reasons:
1. I could modify the source in get_data to look like:
if (st)
{
//ptr_msg = (test_struct*)factory::createInstance(st);
factory* pfact = factory::createInstance(st);
if (pfact != NULL)
{
cout << " success " << endl;
pfact->execute();
//if (ptr_msg->idx == 99)
// cout << " even more success " << endl;
}
}
Except now I need a way to move from the factory object to a
test_struct object so that I could do:
if (ptr_msg->idx == 99)
// do a special thing.
One thought was to modify execute in the test_struc class to look like:
void execute () {
t.update(this); // call some update function in test
}
Trouble is. I now need a 'global' initilization of t. Not good. It
gets worse. In my real code, the initilization of t is wrapped in a
try catch handler so that there goes the global initilization.
2. In theory my 'struct's are defined as incoming and outging msg
structs. So now:
struct outgoing_msg
: public factory
{};
struct incoming_msg
: public factory
{};
The only struct that needs to go through these 'hoops' is the
incoming_msg struct. That said, I would have an execute member
function in the outgoing_msg struct for NO reason.
In the end I suspect I'm just forced to live with the cast from a
polymorphic object to a test_struct.
ptr_msg = (test_struct*)factory::createInstance(st);
Thoughts/ideas?
Thanks in advance