C
Christof Warlich
Hi,
I'm trying to build an _efficient_, _purely_ _abstract_ API for inter
process(or) communication, _completely_ hiding any implementation
details. The core components are "Buffer", "Address" and "Process".
They may be instantiated by a "Factory". Here is a simplified, but
compilable version:
// Abstract Interface
enum OsSelector {
POSIX,
WIN32
};
class Buffer {
public:
virtual void *payload(void) const = 0;
virtual void release(void) = 0;
};
struct Address;
extern const unsigned int addressSize;
class Process {
public:
virtual Address *address(void) = 0;
virtual void release(void) = 0;
};
class Callback {
public:
virtual void receive(Buffer *buffer) = 0;
Process *process;
};
class Factory {
public:
static Factory *create(OsSelector osSelector = POSIX);
virtual Buffer *buffer(unsigned int size,
void *data = 0) = 0;
virtual Process *process(const char *processName,
Callback *callback,
int prio = 0,
unsigned int stackSize = 0xffff) = 0;
virtual Address *lookup(const char *processName,
const char *processorName = 0) = 0;
virtual void send(Address *address, Buffer *buffer) = 0;
};
A simple application, sending a message to another "Process",
may look like this:
// Application
#include <string.h>
struct Data {
unsigned int data1;
unsigned int data2;
};
class TaskCallback: public Callback {
void receive(Buffer *buffer) {
this->process->release();
}
};
int main(void) {
TaskCallback taskCallback;
Factory *factory = Factory::create(POSIX);
Process *process = factory->process("process", &taskCallback);
Buffer *buffer = factory->buffer(addressSize + sizeof(Data));
char *sender = (char *) buffer->payload();
Data *data = (Data *) (sender + addressSize);
memcpy(sender, process->address(), addressSize);
data->data1 = 1;
data->data2 = 2;
factory->send(process->address(), buffer);
}
While this interface fulfills the outlined needs, it is somewhat
cumbersome to use when "Address"es should be sent to another
"Process" intermixed with other data: Typically, one would like to
define a structure containing the "Address"es and the other data
members to easily fill the payload of the "Buffer" to be sent. But
since "Address" is an incomplete type, this is not possible. Instead,
filling "Address"es into the payload requires employing pointer
arithmetic, using the variable "addressSize" provided by the interface.
Finally coming to my point: I know that there are good reasons why
the "sizeof()" operator cannot be overloaded, most notably because
the sizes of structure members must be known at compile time already.
But having seen many discussions that simply state that one can not
even imagine only _one_ example where it would be nice to overload
sizeof(), could you agree that here, it would be perfect if one
could replace the incomplete type "Address" by something like:
class Address {
public:
virtual size_t operator sizeof() = 0;
};
Assuming that types may then be created at runtime, it
would be possible to use the comfort of a structure even when
"Address"es are involved, provided that the implementation of
the overloaded sizeof() operator returns the size of the implementation
for "Address".
As I don't expect that sizeof() will become overloadable soon
just because I wish it could be ;-), does anyone know a more elegant
approach than my pointer arithmetics to fill "Buffer"s with huge
amount of ordinary data intermixed with the abstract "Address"es?
Restricting the presence of "Address"es to fixed locations in the
payload is not an option as the processor the SW is running on is
part of a network with legacy code that makes extensive use of
sending (fixed size) addresses.
Many thanks for the patience to read until this point, and even more
thanks for any good idea!
Regards,
Christof
I'm trying to build an _efficient_, _purely_ _abstract_ API for inter
process(or) communication, _completely_ hiding any implementation
details. The core components are "Buffer", "Address" and "Process".
They may be instantiated by a "Factory". Here is a simplified, but
compilable version:
// Abstract Interface
enum OsSelector {
POSIX,
WIN32
};
class Buffer {
public:
virtual void *payload(void) const = 0;
virtual void release(void) = 0;
};
struct Address;
extern const unsigned int addressSize;
class Process {
public:
virtual Address *address(void) = 0;
virtual void release(void) = 0;
};
class Callback {
public:
virtual void receive(Buffer *buffer) = 0;
Process *process;
};
class Factory {
public:
static Factory *create(OsSelector osSelector = POSIX);
virtual Buffer *buffer(unsigned int size,
void *data = 0) = 0;
virtual Process *process(const char *processName,
Callback *callback,
int prio = 0,
unsigned int stackSize = 0xffff) = 0;
virtual Address *lookup(const char *processName,
const char *processorName = 0) = 0;
virtual void send(Address *address, Buffer *buffer) = 0;
};
A simple application, sending a message to another "Process",
may look like this:
// Application
#include <string.h>
struct Data {
unsigned int data1;
unsigned int data2;
};
class TaskCallback: public Callback {
void receive(Buffer *buffer) {
this->process->release();
}
};
int main(void) {
TaskCallback taskCallback;
Factory *factory = Factory::create(POSIX);
Process *process = factory->process("process", &taskCallback);
Buffer *buffer = factory->buffer(addressSize + sizeof(Data));
char *sender = (char *) buffer->payload();
Data *data = (Data *) (sender + addressSize);
memcpy(sender, process->address(), addressSize);
data->data1 = 1;
data->data2 = 2;
factory->send(process->address(), buffer);
}
While this interface fulfills the outlined needs, it is somewhat
cumbersome to use when "Address"es should be sent to another
"Process" intermixed with other data: Typically, one would like to
define a structure containing the "Address"es and the other data
members to easily fill the payload of the "Buffer" to be sent. But
since "Address" is an incomplete type, this is not possible. Instead,
filling "Address"es into the payload requires employing pointer
arithmetic, using the variable "addressSize" provided by the interface.
Finally coming to my point: I know that there are good reasons why
the "sizeof()" operator cannot be overloaded, most notably because
the sizes of structure members must be known at compile time already.
But having seen many discussions that simply state that one can not
even imagine only _one_ example where it would be nice to overload
sizeof(), could you agree that here, it would be perfect if one
could replace the incomplete type "Address" by something like:
class Address {
public:
virtual size_t operator sizeof() = 0;
};
Assuming that types may then be created at runtime, it
would be possible to use the comfort of a structure even when
"Address"es are involved, provided that the implementation of
the overloaded sizeof() operator returns the size of the implementation
for "Address".
As I don't expect that sizeof() will become overloadable soon
just because I wish it could be ;-), does anyone know a more elegant
approach than my pointer arithmetics to fill "Buffer"s with huge
amount of ordinary data intermixed with the abstract "Address"es?
Restricting the presence of "Address"es to fixed locations in the
payload is not an option as the processor the SW is running on is
part of a network with legacy code that makes extensive use of
sending (fixed size) addresses.
Many thanks for the patience to read until this point, and even more
thanks for any good idea!
Regards,
Christof