implementation details

Discussion in 'C++' started by MPowell, Oct 2, 2003.

  1. MPowell

    MPowell Guest

    Lets suppose the return value on new_command is MSG2_STATUS

    My intent then is to memcpy the data via the call to CMDHolder and
    have a function that'll retrieve a copy of the 'stored' data. The
    latter I'm unsure how to do. Any help appreaciated.


    #include <iostream>
    #include <map>


    using namespace std;

    int msg2_status_index = 0;
    int msg1_status_index = 0;
    int msg1_cmd_index = 0;

    MSG2_STATUS _msg2_stat[ 2 ]; // used for double buffering
    MSG1_STATUS _msg1_stat[ 2 ]; // used for double buffering
    MSG1_CMD _msg1_cmd[ 2 ]; // used for double buffering

    typedef enum
    {
    _msg1_cmd = 0,
    _msg1_status,
    _msg2_status
    } MSG_ID;

    typedef struct // this is ++. Why use typedef. 'details' I suppose
    {
    MSG_ID source;
    unsigned int msg_length : 12;
    unsigned int count : 4;
    } MSG_HEADER;

    typedef struct _MSG2_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 24;
    unsigned int ldx : 32;
    } MSG2_STATUS;

    typedef struct _MSG1_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 8;
    } MSG1_STATUS;

    typedef struct _MSG1_CMD
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    } MSG1_CMD;



    class CMDBase
    {
    public:
    virtual ~CMDBase(){}
    /* what operations do you perform on these commands?
    virtual void operation1() = 0;
    virtual void operation2() = 0; */
    };


    template <class CMD>
    class CMDHolder: public CMDBase
    {
    public:
    CMDHolder(unsigned char const* buffer)
    {
    memcpy(&m_CMDStruct, buffer, sizeof m_CMDStruct);
    }

    /* virtual void operation1()
    {
    //use overloaded global functions?
    structOperation1(m_CMDStruct);
    }

    virtual void operation2()
    {
    structOperation2(m_CMDStruct);
    } */
    private:
    CMD m_CMDStruct;
    };

    class CMDFactory
    {
    public:
    static CMDFactory& instance()
    {
    CMDFactory fact;
    return fact;
    }

    // Register the creator
    template <class T> void Register(int Id)
    {
    m_creators[Id] = CMDCreator<T>;
    }
    // unregister creator
    bool Unregister( const int& Id )
    {
    return m_creators.erase( Id ) == 1;
    }

    CMDBase* Create(unsigned char const* buffer)
    {
    //MSG_HEADER* msg_id = reinterpret_cast<MSG_HEADER*>(buffer);
    MSG_HEADER* msg_id; // only here because reinterpret_cast error
    complaint

    //insert error checking!
    return (m_creators[msg_id->source])(buffer);
    }


    reinterpret_cast generates an error with respect to the constant
    buffer and the non constant MSG_HEADER*. ??

    return (m_creators[msg_id->source])(buffer); // return here might be
    a bit confusing

    private:
    typedef CMDBase* (*CMDCreator_t)(unsigned char const*);

    template <class T>
    static CMDBase* CMDCreator(unsigned char const* buffer)
    {
    return new T(buffer);
    }

    std::map<int, CMDCreator_t> m_creators;
    };

    int main ( void )
    {
    //called once, in initialization function:
    CMDFactory::instance().Register<MSG2_STATUS> (1);
    CMDFactory::instance().Register<MSG1_STATUS> (2);


    // inside your command processing loop:
    unsigned char buffer[512];
    // Read_1553_Data(CHANNEL_FIVE, &buffer);
    CMDBase* newCommand = CMDFactory::instance().Create(buffer);

    // newCommand->operation1(); //whatever you want to do with it
    //maybe add it to a queue<CMDBase*>?
    //myqueue.push(newCommand);

    return EXIT_SUCCESS;
    }
     
    MPowell, Oct 2, 2003
    #1
    1. Advertising

  2. MPowell

    tom_usenet Guest

    On 2 Oct 2003 03:57:29 -0700, (MPowell) wrote:

    >Lets suppose the return value on new_command is MSG2_STATUS
    >
    >My intent then is to memcpy the data via the call to CMDHolder and
    >have a function that'll retrieve a copy of the 'stored' data. The
    >latter I'm unsure how to do. Any help appreaciated.


    Well, I can fix the errors in the code, but you'll have to explain
    what the code is meant to do. What do you want to do with the messages
    that you receive? Do you need to perform some action depending on the
    type of message you receive?

    > CMDBase* Create(unsigned char const* buffer)
    > {
    > //MSG_HEADER* msg_id = reinterpret_cast<MSG_HEADER*>(buffer);
    > MSG_HEADER* msg_id; // only here because reinterpret_cast error
    >complaint
    >
    > //insert error checking!
    > return (m_creators[msg_id->source])(buffer);
    > }


    The above function should go more like this:

    CMDBase* Create(unsigned char const* buffer)
    {
    MSG_HEADER const* msg_id = reinterpret_cast<MSG_HEADER
    const*>(buffer);
    map_t::const_iterator i = m_creators.find(msg_id->source);
    if (i == m_creators.end())
    {
    throw runtime_error("Invalid source");
    }
    else
    {
    //call create function through pointer.
    return (i->second)(buffer);
    }

    >reinterpret_cast generates an error with respect to the constant
    >buffer and the non constant MSG_HEADER*. ??


    Making the header const fixes your problem.

    >return (m_creators[msg_id->source])(buffer); // return here might be
    >a bit confusing


    The above is actuall a function call made through a function pointer.
    m_creators maps source id onto a creation function pointer than can
    create the Holder object for messages of that type. The above accesses
    that function pointer and calls the function, passing "buffer" as the
    first parameter. That function in tern returns a new Holder object,
    initialized with the buffer.

    Tom
     
    tom_usenet, Oct 2, 2003
    #2
    1. Advertising

  3. MPowell wrote:

    <snip>
    >
    > MSG2_STATUS _msg2_stat[ 2 ]; // used for double buffering
    > MSG1_STATUS _msg1_stat[ 2 ]; // used for double buffering
    > MSG1_CMD _msg1_cmd[ 2 ]; // used for double buffering
    >
    > typedef enum
    > {
    > _msg1_cmd = 0,
    > _msg1_status,
    > _msg2_status
    > } MSG_ID;


    Every one of these variables and enumerators is illegal. Identifiers
    beginning with an underscore followed by a lowercase letter are reserved
    in the global namespace.

    Just don't use identifiers beginning with an underscore. It's the
    easiest way to avoid this problem.

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
     
    Kevin Goodsell, Oct 2, 2003
    #3
  4. MPowell

    MPowell Guest

    > Well, I can fix the errors in the code, but you'll have to explain
    > what the code is meant to do. What do you want to do with the messages
    > that you receive? Do you need to perform some action depending on the
    > type of message you receive?


    Consider

    #define ID_ERROR_MASK 0x08 // #defined at top of the translation unit
    #define ID_MASK 0x07 // #defined at top of the translation unit


    int _msg2_header_error_count = 0;
    int _msg1_header_error_count = 0;

    int _msg2_message_index = 0;
    int _msg1_message_index = 0;
    // lots more

    struct _MSG2_STATUS // here for demo and lots more of these
    {
    // for simplicity strip out 'stuff'.
    unsigned int idx : 1;
    unsigned int ldx : 32;
    } MSG2_STATUS;

    MSG2_STATUS _msg2_message[ 2 ]; // for double buffering
    // lots more

    The Create function will look at the msg_id (which it does) then check
    for error.

    if (msg_id & ID_ERROR_MASK) == 0 )
    {
    // if no error look at msg_type
    MSG_HEADER msg_type =
    (((( msg_id >> 4 ) & ID_MASK ) <<3 )) | ( msg_id &
    ID_MASK );

    Lets suppose now the msg_type maps to MSG2_STATUS defined above

    switch (msg_type)
    {
    case _msg2_status: //got a status 2 message

    // double buffer it
    i = _msg2_message_index ^ 1;
    memcpy( &_msg2_message, buffer, sizeof(MSG2_STATUS) );
    _msg2_message_index ^= 1;
    _msg2_message_ready = TRUE;
    break;

    case _msg1_status: //got a status 1 message

    // double buffer it
    i = _msg1_message_index ^ 1;
    memcpy( &_msg1_message, buffer, sizeof(MSG1_STATUS) );
    _msg1_message_index ^= 1;
    _msg1_message_ready = TRUE;
    break;
    // and so on
    default:
    break;
    }
    else
    {
    switch( msg_id )
    {
    case _msg2_header_error: //got a status 2 message
    _msg2_header_error_count++;
    printf (" msg2_header_error = &d ", msg2_header_error);
    break;
    case _msg1_header_error: //got a status 2 message
    _msg1_header_error_count++;

    // I suspect it'd be prudent to pass in the counters and
    have values returend by the ++ ostream approach
    printf (" msg1_header_error = &d ", msg1_header_error);
    break;
    // and so on
    default:
    break;
    }
    }

    So now, double buffer the data,increment a counter, then set a flag -
    for no errors. For errors, increment an error counter. The current
    template style approach is certainly more elegant

    A separate function within the class should retrieve the most current
    double buffer data. I suspect (assuming i understand templates) each
    buffered data will be 'pushed' into a container/holder/?? and when
    necessary (a 120hz processing rountine retrieves the latest) retrieved
    via a call to some function with the template parameter being the
    appropriate struct.

    Lastly, the individual structs form a part of an overall struct. ie
    struct OVERALL
    {
    MSG1_TYPE msg1;
    MSG2_TYPE msg2;
    lots more.
    }

    A separate function will retrieve the 'overall'.

    In essence, a template to 'get' the data and hold data for the
    requestor

    >
    > > CMDBase* Create(unsigned char const* buffer)
    > > {
    > > //MSG_HEADER* msg_id = reinterpret_cast<MSG_HEADER*>(buffer);
    > > MSG_HEADER* msg_id; // only here because reinterpret_cast error
    > >complaint
    > >
    > > //insert error checking!
    > > return (m_creators[msg_id->source])(buffer);
    > > }

    >
    > The above function should go more like this:
    >
    > CMDBase* Create(unsigned char const* buffer)
    > {
    > MSG_HEADER const* msg_id = reinterpret_cast<MSG_HEADER
    > const*>(buffer);
    > map_t::const_iterator i = m_creators.find(msg_id->source);


    map_t error ??

    > if (i == m_creators.end())
    > {
    > throw runtime_error("Invalid source");
    > }
    > else
    > {
    > //call create function through pointer.
    > return (i->second)(buffer);
    > }
    >
    > >reinterpret_cast generates an error with respect to the constant
    > >buffer and the non constant MSG_HEADER*. ??

    >
    > Making the header const fixes your problem.
    >
    > >return (m_creators[msg_id->source])(buffer); // return here might be
    > >a bit confusing

    >
    > The above is actuall a function call made through a function pointer.
    > m_creators maps source id onto a creation function pointer than can
    > create the Holder object for messages of that type. The above accesses
    > that function pointer and calls the function, passing "buffer" as the
    > first parameter. That function in tern returns a new Holder object,
    > initialized with the buffer.
    >
    > Tom


    Tom, truly appreaciate the assistance. Feel free to use my email
    address if necessary.
     
    MPowell, Oct 2, 2003
    #4
  5. MPowell wrote:

    <snip>

    >
    > int _msg2_header_error_count = 0;
    > int _msg1_header_error_count = 0;
    >
    > int _msg2_message_index = 0;
    > int _msg1_message_index = 0;


    These are all illegal (assuming this is the global namespace).

    > // lots more
    >
    > struct _MSG2_STATUS // here for demo and lots more of these


    This is illegal anywhere. From the standard:

    17.4.3.1.2 Global names [lib.global.names]

    1 Certain sets of names and function signatures are always reserved to
    the implementation:

    --Each name that contains a double underscore __) or begins with an
    underscore followed by an uppercase letter (_lex.key_) is reserved
    to the implementation for any use.

    --Each name that begins with an underscore is reserved to the imple-
    mentation for use as a name in the global namespace.


    I still don't understand your question - can it be demonstrated in a
    smaller, simpler code sample?

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
     
    Kevin Goodsell, Oct 2, 2003
    #5
  6. MPowell

    tom_usenet Guest

    On 2 Oct 2003 13:47:49 -0700, (MPowell) wrote:

    >> Well, I can fix the errors in the code, but you'll have to explain
    >> what the code is meant to do. What do you want to do with the messages
    >> that you receive? Do you need to perform some action depending on the
    >> type of message you receive?

    >
    >Consider


    The below doesn't answer the question, a couple of paragraphs of text
    might.

    >
    >#define ID_ERROR_MASK 0x08 // #defined at top of the translation unit
    >#define ID_MASK 0x07 // #defined at top of the translation unit
    >
    >
    >int _msg2_header_error_count = 0;
    >int _msg1_header_error_count = 0;
    >
    >int _msg2_message_index = 0;
    >int _msg1_message_index = 0;
    >// lots more
    >
    >struct _MSG2_STATUS // here for demo and lots more of these
    >{
    > // for simplicity strip out 'stuff'.
    > unsigned int idx : 1;
    > unsigned int ldx : 32;
    >} MSG2_STATUS;
    >
    >MSG2_STATUS _msg2_message[ 2 ]; // for double buffering


    I now finally understand what you mean by double buffering - you want
    to keep the last two messages of each type.

    >// lots more
    >
    >The Create function will look at the msg_id (which it does) then check
    >for error.
    >
    > if (msg_id & ID_ERROR_MASK) == 0 )
    > {
    > // if no error look at msg_type
    > MSG_HEADER msg_type =
    > (((( msg_id >> 4 ) & ID_MASK ) <<3 )) | ( msg_id &
    >ID_MASK );
    >
    >Lets suppose now the msg_type maps to MSG2_STATUS defined above
    >
    > switch (msg_type)
    > {
    > case _msg2_status: //got a status 2 message
    >
    > // double buffer it
    > i = _msg2_message_index ^ 1;
    > memcpy( &_msg2_message, buffer, sizeof(MSG2_STATUS) );
    > _msg2_message_index ^= 1;
    > _msg2_message_ready = TRUE;
    > break;
    >
    > case _msg1_status: //got a status 1 message
    >
    > // double buffer it
    > i = _msg1_message_index ^ 1;
    > memcpy( &_msg1_message, buffer, sizeof(MSG1_STATUS) );
    > _msg1_message_index ^= 1;
    > _msg1_message_ready = TRUE;
    > break;
    > // and so on
    > default:
    > break;


    The above code doesn't really do anything. Instead, you should
    probably just add the message to a queue and signal a condition
    variable on that queue so that another thread whose job is to process
    these messages can do so.

    > }
    > else
    > {
    > switch( msg_id )
    > {
    > case _msg2_header_error: //got a status 2 message
    > _msg2_header_error_count++;
    > printf (" msg2_header_error = &d ", msg2_header_error);
    > break;
    > case _msg1_header_error: //got a status 2 message
    > _msg1_header_error_count++;
    >
    > // I suspect it'd be prudent to pass in the counters and
    >have values returend by the ++ ostream approach
    > printf (" msg1_header_error = &d ", msg1_header_error);
    > break;
    > // and so on
    > default:
    > break;
    > }
    > }
    >
    >So now, double buffer the data,increment a counter, then set a flag -
    >for no errors. For errors, increment an error counter. The current
    >template style approach is certainly more elegant


    Yes, since all messages can be treated the same - no switch
    statements. Polymorphism is the important thing here though -
    templates are just an implementation detail.

    >A separate function within the class should retrieve the most current
    >double buffer data.


    Does this operate in the same thread? It might be good to put it in
    another thread.

    I suspect (assuming i understand templates) each
    >buffered data will be 'pushed' into a container/holder/??


    Seems like a good idea.

    and when
    >necessary (a 120hz processing rountine retrieves the latest) retrieved
    >via a call to some function with the template parameter being the
    >appropriate struct.


    Yes, something like that. You could use the visitor pattern as Gianni
    suggested.

    >Lastly, the individual structs form a part of an overall struct. ie
    >struct OVERALL
    >{
    > MSG1_TYPE msg1;
    > MSG2_TYPE msg2;
    > lots more.
    >}
    >
    >A separate function will retrieve the 'overall'.


    Now I'm confused - aren't the messages separate? What *are* these
    messages? What do they signify? Where do they come from? Some hardware
    device? How are you meant to react to different messages? Why is there
    more than one message type?

    >In essence, a template to 'get' the data and hold data for the
    >requestor
    >
    >>
    >> > CMDBase* Create(unsigned char const* buffer)
    >> > {
    >> > //MSG_HEADER* msg_id = reinterpret_cast<MSG_HEADER*>(buffer);
    >> > MSG_HEADER* msg_id; // only here because reinterpret_cast error
    >> >complaint
    >> >
    >> > //insert error checking!
    >> > return (m_creators[msg_id->source])(buffer);
    >> > }

    >>
    >> The above function should go more like this:
    >>
    >> CMDBase* Create(unsigned char const* buffer)
    >> {
    >> MSG_HEADER const* msg_id = reinterpret_cast<MSG_HEADER
    >> const*>(buffer);
    >> map_t::const_iterator i = m_creators.find(msg_id->source);

    >
    >map_t error ??


    Whoops, that's meant to be a typedef for the map type that you need to
    add to your class definition. e.g.
    typedef std::map<int, Creator*> map_t;

    Following is some complete compileable code that might help. It
    basically shows how to enqueue all messages onto a queue, and how you
    might go about processing those messages. If you might need different
    processors for the messages in different circumstances, then the
    visitor pattern might be appropriate. This is rather a lot to take in
    if you are quite new to C++, but I hope it helps in any case.

    #include <iostream>
    #include <map>
    #include <queue>

    using namespace std;

    //message queue
    class CMDBase;
    queue<CMDBase*> CMDQueue;

    enum MSG_ID
    {
    msg1_cmd = 0,
    msg1_status = 1,
    msg2_status = 2
    };

    struct MSG_HEADER
    {
    MSG_ID source;
    unsigned int msg_length : 12;
    unsigned int count : 4;
    };

    struct MSG2_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 24;
    unsigned int ldx : 32;
    };

    struct MSG1_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 8;
    };

    struct MSG1_CMD
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    };

    class CMDProcessor
    {
    public:
    void process(MSG2_STATUS& msg)
    {
    std::cout << "MSG2_STATUS processed\n";
    }

    void process(MSG1_STATUS& msg)
    {
    std::cout << "MSG1_STATUS processed\n";
    }

    void process(MSG1_CMD& cmd)
    {
    std::cout << "MSG1_CMD processed\n";
    }
    };

    class CMDBase
    {
    public:
    virtual ~CMDBase(){}
    virtual void process(CMDProcessor* processor) = 0;
    };


    template <class CMD>
    class CMDHolder: public CMDBase
    {
    public:
    CMDHolder(unsigned char const* buffer)
    {
    memcpy(&m_CMDStruct, buffer, sizeof m_CMDStruct);
    }

    virtual void process(CMDProcessor* processor)
    {
    processor->process(m_CMDStruct);
    }

    private:
    CMD m_CMDStruct;
    };

    class CMDFactory
    {
    public:
    static CMDFactory& instance()
    {
    static CMDFactory fact;
    return fact;
    }

    // Register the creator
    template <class T> void Register(int Id)
    {
    m_creators[Id] = CMDCreator<CMDHolder<T> >;
    }
    // unregister creator
    bool Unregister( const int& Id )
    {
    return m_creators.erase( Id ) == 1;
    }

    CMDBase* Create(unsigned char const* buffer)
    {
    MSG_HEADER const* msg_id = reinterpret_cast<MSG_HEADER
    const*>(buffer);
    map_t::const_iterator i = m_creators.find(msg_id->source);

    if (i == m_creators.end())
    {
    throw runtime_error("Invalid source");
    }
    else
    {
    //call create function through pointer.
    return (i->second)(buffer);
    }
    }
    private:
    typedef CMDBase* (*CMDCreator_t)(unsigned char const*);

    template <class T>
    static CMDBase* CMDCreator(unsigned char const* buffer)
    {
    return new T(buffer);
    }

    typedef std::map<int, CMDCreator_t> map_t;
    map_t m_creators;
    };

    void register_types()
    {
    CMDFactory::instance().Register<MSG1_CMD>(0);
    CMDFactory::instance().Register<MSG1_STATUS>(1);
    CMDFactory::instance().Register<MSG2_STATUS>(2);
    }

    size_t ReadData(unsigned char* buffer, size_t size)
    {
    //generate sample data
    static bool doMsg1 = false;
    void* data;
    size_t actualSize;
    MSG1_STATUS msg1 = {};
    MSG2_STATUS msg2 = {};
    if (doMsg1)
    {
    msg1.header.source = msg1_status;
    data = &msg1;
    actualSize = sizeof msg1;
    }
    else
    {
    msg2.header.source = msg2_status;
    data = &msg2;
    actualSize = sizeof msg2;
    }
    if (size < actualSize)
    throw runtime_error("buffer too short");
    memcpy(buffer, data, actualSize);
    doMsg1 = !doMsg1;
    return actualSize;
    }

    CMDProcessor processor;

    void processQueue()
    {
    while (!CMDQueue.empty())
    {
    CMDBase* cmd = CMDQueue.front();
    CMDQueue.pop();
    cmd->process(&processor);
    delete cmd;
    }
    }

    void fillQueue()
    {
    unsigned char buffer[512];
    ReadData(buffer, 512);
    CMDBase* newCommand = CMDFactory::instance().Create(buffer);
    CMDQueue.push(newCommand);
    }

    int main ( void )
    {
    register_types();

    for (int i = 0; i < 5; ++i)
    {
    fillQueue();
    processQueue();
    }

    return EXIT_SUCCESS;
    }
     
    tom_usenet, Oct 3, 2003
    #6
  7. MPowell

    MPowell Guest

    tom_usenet <> wrote in message >

    > Following is some complete compileable code that might help. It
    > basically shows how to enqueue all messages onto a queue, and how you
    > might go about processing those messages. If you might need different
    > processors for the messages in different circumstances, then the
    > visitor pattern might be appropriate. This is rather a lot to take in
    > if you are quite new to C++, but I hope it helps in any case.


    Truly appreaciate the assistance. I'm starting to get a feel for what
    a poster REALLY meant when he highlighted that C is not C++.
    Theoretically I have to change my 'C' style design approach. This was
    truly a lesson in implementation.

    I was reading a post on recommended texts from a Mike Whaler and I've
    since placed some orders.

    Really despise having to continue/drag this post out, nonetheless I've
    got a few more questions on this.


    class CMDProcessor
    {
    public:
    void process(MSG2_STATUS& msg)
    {
    std::cout << "MSG2_STATUS processed\n";
    }
    :
    :
    :
    };

    I assume these process functions is where I need to do my 'double
    buffering'?
    The system like any another is riddled with asynchrous processing. In
    other words assume I had this.
    MSG2_STATUS msg2_stat [ 2 ];
    Now fillQueue() and processQueue(); fills and processes a
    "MSG2_STATUS'. I'll copy the data to msg2_stat [ 0 ]. Lets suppose
    now that we're filling (fillQueue()) and processing (processQueue())
    another MSG2_STATUS BUT while filling or processing a separate 60
    Hertz task (which I have) is getting the most current MSG2_STATUS.
    The 60 Hertz task will grab/read the data in msg2_status[ 0 ] while
    fill (fillQueue()) and process (processQueue()) writes to msg2_status
    [ 1 ].

    Yes, there's the 'unlikely' event where I'll have a race condition
    where they're both trying to read (the 60 Hertz) and write
    (processQueue) to the same location but i've got a handle on that via
    the mechanisms of the RTOS.

    >
    > template <class CMD>
    > class CMDHolder: public CMDBase
    > {
    > public:
    > CMDHolder(unsigned char const* buffer)
    > {
    > memcpy(&m_CMDStruct, buffer, sizeof m_CMDStruct);
    > }
    >
    > virtual void process(CMDProcessor* processor)
    > {
    > processor->process(m_CMDStruct);
    > }
    >
    > private:
    > CMD m_CMDStruct;
    > };
    >
    > class CMDFactory
    > {
    > public:
    > static CMDFactory& instance()
    > {
    > static CMDFactory fact;
    > return fact;
    > }
    >
    > // Register the creator
    > template <class T> void Register(int Id)
    > {
    > m_creators[Id] = CMDCreator<CMDHolder<T> >;
    > }
    > // unregister creator
    > bool Unregister( const int& Id )
    > {
    > return m_creators.erase( Id ) == 1;
    > }
    >
    > CMDBase* Create(unsigned char const* buffer)
    > {
    > MSG_HEADER const* msg_id = reinterpret_cast<MSG_HEADER
    > const*>(buffer);
    > map_t::const_iterator i = m_creators.find(msg_id->source);
    >
    > if (i == m_creators.end())
    > {
    > throw runtime_error("Invalid source");
    > }
    > else
    > {
    > //call create function through pointer.
    > return (i->second)(buffer);


    Get an exception here in Visual C.NET. Not sure if a C style try
    catch handler would be ideal

    > }
    > }
    > private:
    > typedef CMDBase* (*CMDCreator_t)(unsigned char const*);
    >
    > template <class T>
    > static CMDBase* CMDCreator(unsigned char const* buffer)
    > {
    > return new T(buffer);
    > }
    >
    > typedef std::map<int, CMDCreator_t> map_t;
    > map_t m_creators;
    > };
    >
    > void register_types()
    > {
    > CMDFactory::instance().Register<MSG1_CMD>(0);
    > CMDFactory::instance().Register<MSG1_STATUS>(1);
    > CMDFactory::instance().Register<MSG2_STATUS>(2);
    > }
    >
    > size_t ReadData(unsigned char* buffer, size_t size)
    > {
    > //generate sample data
    > static bool doMsg1 = false;
    > void* data;
    > size_t actualSize;
    > MSG1_STATUS msg1 = {};
    > MSG2_STATUS msg2 = {};


    Interesting I had to change above to.
    MSG1_STATUS msg1;
    MSG2_STATUS msg2;

    VC.NET complier complained that 'local function definitions are
    illegal

    > if (doMsg1)
    > {
    > msg1.header.source = msg1_status;
    > data = &msg1;
    > actualSize = sizeof msg1;
    > }
    > else
    > {
    > msg2.header.source = msg2_status;
    > data = &msg2;
    > actualSize = sizeof msg2;
    > }
    > if (size < actualSize)
    > throw runtime_error("buffer too short");
    > memcpy(buffer, data, actualSize);
    > doMsg1 = !doMsg1;
    > return actualSize;
    > }
    >
    > CMDProcessor processor;
    >
    > void processQueue()
    > {
    > while (!CMDQueue.empty())
    > {
    > CMDBase* cmd = CMDQueue.front();
    > CMDQueue.pop();
    > cmd->process(&processor);
    > delete cmd;
    > }
    > }

    I suspect I understand the simplistic version of queues. The
    cmd->process and delete cmd should be placed outside the while loop??
    Each element that gets 'popped' off the queue results in a call to
    cmd-process/delete cmd. so now assume two bytes.

    BYTE1. while !empty 1 results in : <- pop .. cmd->process(byte1)
    BYTE2. while !empty 2 results in : <- pop .. cmd->process(byte2)
    &process is in effect a pass through to
    processor->process(m_CMDStruct);?
    I missed how the CMD type was passed in?


    Thanks again.
     
    MPowell, Oct 3, 2003
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ozgun Erdogan
    Replies:
    0
    Views:
    536
    Ozgun Erdogan
    Aug 13, 2004
  2. =?Utf-8?B?Sm9l?=

    Show Details/Hide Details link button

    =?Utf-8?B?Sm9l?=, Mar 13, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    911
    dkode
    Mar 13, 2006
  3. Replies:
    1
    Views:
    780
    Roedy Green
    Apr 8, 2006
  4. forums_mp

    implementation details

    forums_mp, Oct 25, 2003, in forum: C++
    Replies:
    3
    Views:
    346
    Davlet Panech
    Oct 26, 2003
  5. ma740988

    implementation details

    ma740988, Jan 8, 2004, in forum: C Programming
    Replies:
    11
    Views:
    596
    ma740988
    Jan 16, 2004
Loading...

Share This Page