Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #9239 > unrolled thread

Mapping operations to codes

Started by"Default User" <defaultuserbr@yahoo.com>
First post2011-08-23 11:17 -0500
Last post2011-08-24 03:23 -0700
Articles 9 — 3 participants

Back to article view | Back to comp.lang.c++


Contents

  Mapping operations to codes "Default User" <defaultuserbr@yahoo.com> - 2011-08-23 11:17 -0500
    Re: Mapping operations to codes Paul <pchristor@yahoo.co.uk> - 2011-08-23 10:33 -0700
    Re: Mapping operations to codes Victor Bazarov <v.bazarov@comcast.invalid> - 2011-08-23 13:51 -0400
      Re: Mapping operations to codes "Default User" <defaultuserbr@yahoo.com> - 2011-08-23 14:30 -0500
        Re: Mapping operations to codes Victor Bazarov <v.bazarov@comcast.invalid> - 2011-08-23 16:23 -0400
          Re: Mapping operations to codes "Default User" <defaultuserbr@yahoo.com> - 2011-08-23 16:01 -0500
            Re: Mapping operations to codes Victor Bazarov <v.bazarov@comcast.invalid> - 2011-08-23 17:42 -0400
              Re: Mapping operations to codes "Default User" <defaultuserbr@yahoo.com> - 2011-08-23 17:05 -0500
                Re: Mapping operations to codes Paul <pchristor@yahoo.co.uk> - 2011-08-24 03:23 -0700

#9239 — Mapping operations to codes

From"Default User" <defaultuserbr@yahoo.com>
Date2011-08-23 11:17 -0500
SubjectMapping operations to codes
Message-ID<9bi243F224U1@mid.individual.net>
I'm not sure how well that subject captured the topic. Anyway, this is a 
branching from my previous topic "Fun with member-function pointers".

The general problem is that we have a number of  "drivers" for instruments. 
These are essentially an abstraction layer than translates control messages 
from higher-level modules into something the particular hardware can 
understand. The API for this is a system of operation codes and an 
associated data word that has bits set or cleared for various options.

My current solution is to map the op codes to pointers to member functions 
that handle the particular operation. There's also a requirement that each 
driver be able to respond with a list of the supported op codes. The problem 
is that it results in a lot of very similar code in each driver. I had 
wanted to push down as much behavior as possible to the base class. My 
initial thoughts (see other thread) look like they result in undefined 
behavior, so no good.

Below is a small representation of the problem. It's not the real code 
(which would be very large), so it's not necessary to suggest improvements 
in layout or that sort of thing. Thoughts on attacking the general problem 
would be welcome.


Brian


================= code =================

#include <iostream>
#include <map>
#define CALL_HANDLER(object,ptrToMember)((object).*(ptrToMember))

class tbase
{
public:

protected:
   tbase()
   {
   }
   virtual ~tbase()
   {
   }
};

class test : public tbase
{
public:
   typedef int (test::*HandlerPtr)(int);

   test() // sets up the map of handlers to op codes
   {
      handlers[0] = &test::H0;
      handlers[4] = &test::H4;
   }
   virtual ~tbase()
   {
   }
   virtual int H0(int data)
   {
      std::cout << "test::H0: " << data << "\n";
      return data;
   }
   int H4(int data)
   {
      std::cout << "test::H4: " << data << "\n";
      return data;
   }
   void write(int data, int code) // finds the handler and passes data
   {
      std::map<int, HandlerPtr>::iterator it;
      it = handlers.find(code);
      if (it != handlers.end())
      {
         // Found, call the function pointer
         CALL_HANDLER(*this, it->second)(data);
      }
      else // unhandled code
      {
         // error handling
      }
   }
   void list() // just prints supported op codes
   {
      std::map<int, HandlerPtr>::iterator it = handlers.begin();

      std::cout << "Supported Op codes:\n";
      while (it != handlers.end())
      {
         std::cout << it->first << "\n";
         it++;
      }
   }
private:
   std::map<int, HandlerPtr> handlers;
};

int main()
{
   test t;
   t.list();
   t.write(123, 0);
   t.write(456, 4);
   return 0;
}

[toc] | [next] | [standalone]


#9243

FromPaul <pchristor@yahoo.co.uk>
Date2011-08-23 10:33 -0700
Message-ID<6f27dbb6-07fe-48af-a5f2-74cb94bc3eff@er4g2000vbb.googlegroups.com>
In reply to#9239
On Aug 23, 5:17 pm, "Default User" <defaultuse...@yahoo.com> wrote:
> I'm not sure how well that subject captured the topic. Anyway, this is a
> branching from my previous topic "Fun with member-function pointers".
>
> The general problem is that we have a number of  "drivers" for instruments.
> These are essentially an abstraction layer than translates control messages
> from higher-level modules into something the particular hardware can
> understand. The API for this is a system of operation codes and an
> associated data word that has bits set or cleared for various options.
>
> My current solution is to map the op codes to pointers to member functions
> that handle the particular operation. There's also a requirement that each
> driver be able to respond with a list of the supported op codes. The problem
> is that it results in a lot of very similar code in each driver. I had
> wanted to push down as much behavior as possible to the base class. My
> initial thoughts (see other thread) look like they result in undefined
> behavior, so no good.
>
> Below is a small representation of the problem. It's not the real code
> (which would be very large), so it's not necessary to suggest improvements
> in layout or that sort of thing. Thoughts on attacking the general problem
> would be welcome.
>
> Brian
>
> ================= code =================
>
> #include <iostream>
> #include <map>
> #define CALL_HANDLER(object,ptrToMember)((object).*(ptrToMember))
>
> class tbase
> {
> public:
>
> protected:
>    tbase()
>    {
>    }
>    virtual ~tbase()
>    {
>    }
>
> };
>
> class test : public tbase
> {
> public:
>    typedef int (test::*HandlerPtr)(int);
>
>    test() // sets up the map of handlers to op codes
>    {
>       handlers[0] = &test::H0;
>       handlers[4] = &test::H4;
>    }
>    virtual ~tbase()
>    {
>    }
>    virtual int H0(int data)
>    {
>       std::cout << "test::H0: " << data << "\n";
>       return data;
>    }
Why is the above virtual? just a mistake?

>    int H4(int data)
>    {
>       std::cout << "test::H4: " << data << "\n";
>       return data;
>    }
>    void write(int data, int code) // finds the handler and passes data
>    {
>       std::map<int, HandlerPtr>::iterator it;
>       it = handlers.find(code);
It maybe worth while implementing this as a switch case block and do
away with the map altogether, you'd only need one function pointer.

switch(code){
case(123)
fnctptr = &test::H0;
break;
case(456)
fnctptr = &test::H4;
break;
default //catch errors;
}

this->*fnctptr(data);

It may look like more code, if there are alot of "op codes", but the
compiler may optimise this to be faster than a map search.
Are the "op codes" a pre defined set of integers?
If so what range etc?


>       if (it != handlers.end())
>       {
>          // Found, call the function pointer
>          CALL_HANDLER(*this, it->second)(data);
I dunno why you have a macro in there.

>       }
>       else // unhandled code
>       {
>          // error handling
>       }
>    }
>    void list() // just prints supported op codes
>    {
>       std::map<int, HandlerPtr>::iterator it = handlers.begin();
>
>       std::cout << "Supported Op codes:\n";
>       while (it != handlers.end())
>       {
>          std::cout << it->first << "\n";
>          it++;
>       }
I think the above could probably be more efficient but again need to
know the details of the "op codes" before thinking about it. For
example you could just store a string containing all the ops codes,
and print it out.

>    }
> private:
>    std::map<int, HandlerPtr> handlers;
>
> };
>
> int main()
> {
>    test t;
>    t.list();
>    t.write(123, 0);
>    t.write(456, 4);
>    return 0;
>
You also want to think about copying and assignments?

If you have only one set of pre-defined "op-codes" you don't really
want to be copying that map across multiple objects.
I think alot of this depends on these "op codes", Are they a
predefined set?

HTH

[toc] | [prev] | [next] | [standalone]


#9245

FromVictor Bazarov <v.bazarov@comcast.invalid>
Date2011-08-23 13:51 -0400
Message-ID<j30pb0$1pi$1@dont-email.me>
In reply to#9239
On 8/23/2011 12:17 PM, Default User wrote:
> I'm not sure how well that subject captured the topic. Anyway, this is a
> branching from my previous topic "Fun with member-function pointers".
>
> The general problem is that we have a number of  "drivers" for instruments.
> These are essentially an abstraction layer than translates control messages
> from higher-level modules into something the particular hardware can
> understand. The API for this is a system of operation codes and an
> associated data word that has bits set or cleared for various options.
>
> My current solution is to map the op codes to pointers to member functions
> that handle the particular operation. There's also a requirement that each
> driver be able to respond with a list of the supported op codes. The problem
> is that it results in a lot of very similar code in each driver. I had
> wanted to push down as much behavior as possible to the base class. My
> initial thoughts (see other thread) look like they result in undefined
> behavior, so no good.

The maps don't seem to be needed per instance of class ('test') but 
rather per class (i.e. they should probably be static).  That's all I 
have so far.  I would probably try rewriting the code so that 'write' 
and 'list' functions were static as well.

Currently there seems to be no need in using the 'this' to call the H0 
or H4 members - you're not using any instance specific data here. 
Hence, there is no need for H0 or H4 to be non-static either.  Hence 
your "pointer to member" statement is unsubstantiated.  Each "method" 
for dealing with "code" could just as well be static...

Please supply a more complete design that would prove the need to use 
non-static driving methods.

It would be nice to see the need for more than one 'test'.  Perhaps the 
'main' should define two different "drivers" (or even two instances of 
each of the two different "drivers") to demonstrate the need for keeping 
the maps of members in the instance, and not per class.  So far even if 
you are trying to use non-static data in those H0 and H4 member 
functions, the *map* still doesn't have to be per instance.

>
> Below is a small representation of the problem. It's not the real code
> (which would be very large), so it's not necessary to suggest improvements
> in layout or that sort of thing. Thoughts on attacking the general problem
> would be welcome.
>
>
> Brian
>
>
> ================= code =================
>
> #include<iostream>
> #include<map>
> #define CALL_HANDLER(object,ptrToMember)((object).*(ptrToMember))
>
> class tbase
> {
> public:
>
> protected:
>     tbase()
>     {
>     }
>     virtual ~tbase()
>     {
>     }
> };
>
> class test : public tbase
> {
> public:
>     typedef int (test::*HandlerPtr)(int);
>
>     test() // sets up the map of handlers to op codes
>     {
>        handlers[0] =&test::H0;
>        handlers[4] =&test::H4;
>     }
>     virtual ~tbase()
>     {
>     }
>     virtual int H0(int data)
>     {
>        std::cout<<  "test::H0: "<<  data<<  "\n";
>        return data;
>     }
>     int H4(int data)
>     {
>        std::cout<<  "test::H4: "<<  data<<  "\n";
>        return data;
>     }

Not sure how it plays into your goals, so is there a reason why one is 
virtual and the other isn't?

>     void write(int data, int code) // finds the handler and passes data
>     {
>        std::map<int, HandlerPtr>::iterator it;
>        it = handlers.find(code);
>        if (it != handlers.end())
>        {
>           // Found, call the function pointer
>           CALL_HANDLER(*this, it->second)(data);
>        }
>        else // unhandled code
>        {
>           // error handling
>        }
>     }
>     void list() // just prints supported op codes
>     {
>        std::map<int, HandlerPtr>::iterator it = handlers.begin();
>
>        std::cout<<  "Supported Op codes:\n";
>        while (it != handlers.end())
>        {
>           std::cout<<  it->first<<  "\n";
>           it++;
>        }
>     }
> private:
>     std::map<int, HandlerPtr>  handlers;
> };
>
> int main()
> {
>     test t;
>     t.list();
>     t.write(123, 0);
>     t.write(456, 4);
>     return 0;
> }
>
>

V
-- 
I do not respond to top-posted replies, please don't ask

[toc] | [prev] | [next] | [standalone]


#9250

From"Default User" <defaultuserbr@yahoo.com>
Date2011-08-23 14:30 -0500
Message-ID<9bidfjFom5U1@mid.individual.net>
In reply to#9245
"Victor Bazarov" <v.bazarov@comcast.invalid> wrote in message 
news:j30pb0$1pi$1@dont-email.me...
> The maps don't seem to be needed per instance of class ('test') but rather 
> per class (i.e. they should probably be static).  That's all I have so 
> far.  I would probably try rewriting the code so that 'write' and 'list' 
> functions were static as well.

I fear I haven't given enough information, and my example was too sketchy.

1. There will be a number of different drivers, one for each instrument, all 
of with derive from the base class.
2. The driver objects will be contained by other, higher-level ones. These 
higher level "device" modules are derived from a common base class 
themselves. That base class has a pointer to the driver base class. The 
derived class objects will populate that pointer with the particular driver 
that they need.
3. The "device" objects will call the small set of public methods using 
polymorphism. Some methods are in the base class, others specific to a 
particular device. Mostly these route op codes and data to the driver, or 
retrieve data pulled from the instrument.
4. The drivers will have class attributes that contain state information 
about the particular instrument associated with the driver. The op code 
handlers can't be static. Here my example really failed. Mentally add 
several attributes, if you would.



Brian

[toc] | [prev] | [next] | [standalone]


#9251

FromVictor Bazarov <v.bazarov@comcast.invalid>
Date2011-08-23 16:23 -0400
Message-ID<j3128j$2kc$1@dont-email.me>
In reply to#9250
On 8/23/2011 3:30 PM, Default User wrote:
> "Victor Bazarov"<v.bazarov@comcast.invalid>  wrote in message
> news:j30pb0$1pi$1@dont-email.me...
>> The maps don't seem to be needed per instance of class ('test') but rather
>> per class (i.e. they should probably be static).  That's all I have so
>> far.  I would probably try rewriting the code so that 'write' and 'list'
>> functions were static as well.
>
> I fear I haven't given enough information, and my example was too sketchy.
>
> 1. There will be a number of different drivers, one for each instrument, all
> of with derive from the base class.

That's your design.  That's not the problem definition, though.

> 2. The driver objects will be contained by other, higher-level ones. These
> higher level "device" modules are derived from a common base class
> themselves.

OK.  A device consists of (or contains) a collection of drivers.  Let's 
go with that.

 > That base class has a pointer to the driver base class.

A *single* pointer?  How does that work with the collection (see above)?

 > The
> derived class objects will populate that pointer with the particular driver
> that they need.

A single pointer?  Is that some kind of an "active" driver?  From where 
do those get populated?  Is there a repository of driver objects?

> 3. The "device" objects will call the small set of public methods using
> polymorphism.

Whose methods?  Driver's?

 > Some methods are in the base class, others specific to a
> particular device. Mostly these route op codes and data to the driver, or
> retrieve data pulled from the instrument.

"The" instrument?  The "active" one?  There is only one instrument at a 
time?  Can there be the need to retrieve data from a driver/instrument 
that is not active?

> 4. The drivers will have class attributes that contain state information
> about the particular instrument associated with the driver. The op code
> handlers can't be static. Here my example really failed. Mentally add
> several attributes, if you would.

You're explaining your design instead of explaining the problem.  Can 
one device have drivers that serve the same operation?  If not, then 
each driver (op server or whatever you decide to call it) is unique at 
the *device* level, and there seems to be no sense to map its operation 
to its function at the level of the *driver*.  Place a master map at the 
device level.

V
-- 
I do not respond to top-posted replies, please don't ask

[toc] | [prev] | [next] | [standalone]


#9252

From"Default User" <defaultuserbr@yahoo.com>
Date2011-08-23 16:01 -0500
Message-ID<9biiotF1hlU1@mid.individual.net>
In reply to#9251
"Victor Bazarov" <v.bazarov@comcast.invalid> wrote in message 
news:j3128j$2kc$1@dont-email.me...
> On 8/23/2011 3:30 PM, Default User wrote:
>> "Victor Bazarov"<v.bazarov@comcast.invalid>  wrote in message
>> news:j30pb0$1pi$1@dont-email.me...
>>> The maps don't seem to be needed per instance of class ('test') but 
>>> rather
>>> per class (i.e. they should probably be static).  That's all I have so
>>> far.  I would probably try rewriting the code so that 'write' and 'list'
>>> functions were static as well.
>>
>> I fear I haven't given enough information, and my example was too 
>> sketchy.
>>
>> 1. There will be a number of different drivers, one for each instrument, 
>> all
>> of with derive from the base class.
>
> That's your design.  That's not the problem definition, though.

Unfortunately, not being a start-from-scratch exercise, we have to go with 
the design as it is so far. Again, my attempts at explanation have had 
serious gaps, and I apologize for that.

> You're explaining your design instead of explaining the problem.  Can one 
> device have drivers that serve the same operation?  If not, then each 
> driver (op server or whatever you decide to call it) is unique at the 
> *device* level, and there seems to be no sense to map its operation to its 
> function at the level of the *driver*.  Place a master map at the device 
> level.

The central system will hit certain conditions that require service from an 
instrument. At that time, there will be a device code that indicates which 
device should handle the situation, an operation code that indicates what to 
do, and a data word with specific information. None of that can be changed. 
The design of most of this is well along and can't be changed. For good or 
for ill.

At the driver level, I need to map operation codes to driver functions. The 
original code had large case statements. I've been breaking that into 
smaller "handlers" for the various op codes.



Brian

[toc] | [prev] | [next] | [standalone]


#9254

FromVictor Bazarov <v.bazarov@comcast.invalid>
Date2011-08-23 17:42 -0400
Message-ID<j316se$3vm$1@dont-email.me>
In reply to#9252
On 8/23/2011 5:01 PM, Default User wrote:
> [..]
> At the driver level, I need to map operation codes to driver functions. The
> original code had large case statements. I've been breaking that into
> smaller "handlers" for the various op codes.

I still don't see the need to keep a map at the driver level and per 
instance, sorry.  It can only be necessary if two drivers of the *same* 
type could report different pointers-to-member for the same op code, in 
certain conditions (say, depending on their states).  Perhaps it's just 
me, and somebody will step up and offer a brilliant solution within your 
limitations.

V
-- 
I do not respond to top-posted replies, please don't ask

[toc] | [prev] | [next] | [standalone]


#9256

From"Default User" <defaultuserbr@yahoo.com>
Date2011-08-23 17:05 -0500
Message-ID<9bimhfFsesU1@mid.individual.net>
In reply to#9254
"Victor Bazarov" <v.bazarov@comcast.invalid> wrote in message 
news:j316se$3vm$1@dont-email.me...
> On 8/23/2011 5:01 PM, Default User wrote:
>> [..]
>> At the driver level, I need to map operation codes to driver functions. 
>> The
>> original code had large case statements. I've been breaking that into
>> smaller "handlers" for the various op codes.
>
> I still don't see the need to keep a map at the driver level and per 
> instance, sorry.  It can only be necessary if two drivers of the *same* 
> type could report different pointers-to-member for the same op code, in 
> certain conditions (say, depending on their states).

Where would you want to map them?


Brian


[toc] | [prev] | [next] | [standalone]


#9280

FromPaul <pchristor@yahoo.co.uk>
Date2011-08-24 03:23 -0700
Message-ID<2a986f3e-29b5-40eb-8de5-2c6597aef9c9@l4g2000vbz.googlegroups.com>
In reply to#9256
On Aug 23, 11:05 pm, "Default User" <defaultuse...@yahoo.com> wrote:
> "Victor Bazarov" <v.baza...@comcast.invalid> wrote in message
>
> news:j316se$3vm$1@dont-email.me...
>
> > On 8/23/2011 5:01 PM, Default User wrote:
> >> [..]
> >> At the driver level, I need to map operation codes to driver functions.
> >> The
> >> original code had large case statements. I've been breaking that into
> >> smaller "handlers" for the various op codes.
>
> > I still don't see the need to keep a map at the driver level and per
> > instance, sorry.  It can only be necessary if two drivers of the *same*
> > type could report different pointers-to-member for the same op code, in
> > certain conditions (say, depending on their states).
Even with these conditions its not necessary to store a map per
instance.
>
> Where would you want to map them?
>
There are a few different options. :)

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web