views:

78

answers:

2

Hey all, I'm working on cleaning up my code from previous semesters.

Previously I created a 151 color swatch library in c++. However because of my time crunch and lack of experience, I created it entirely as a block of define statements. Which, for hard coding values into spots worked fine. However there are some obvious weaknesses to this approach.

What I have panned out so far, is to create a namespace 'swatch' and inside the namespace I would have an enumeration for the valid colors. I would also have a 'getSwatch' function, or something similar, that would return a vec3 (a class of mine, represents a vector of 3 elemets, with some nice functionality), and the function would use a switch statement to go through the valid swatches.

It would look something like this:

namespace swatch{

    enum color{
        red,
        blue,
        green
    }

    inline
    const vec3 getColor(const color& c){
        // Switch and return red blue or green.
    }
}

My Question: I'd like to know how you might suggest doing this? Benifits of preformance, and usability is what I'm most interested in.

Thanks in advance friends,

Happy coding.

Edit: I just changed the example to make more sense to people who don't know how I use my vec class. (i.e: Everybody but me). Also, you can just look at the other anwsers for usage. They made a good guess on passing rgb values to the constructor, thats not how I did it, but I can still follow along just fine with what you mean.

A: 

You could just use a std::map<color, vec>:

  class ColorClass {
  private:
    std::map<color, vec> colors;
    // ... etc ...

And then you have a big init function that sets it up:

  colors["red"] = new vec(0xFF, 0x00, 0x00);
  colors["blue"] = new vec(0x00, 0xFF, 0x00);
  // ... etc ...

And then your getColor function is just:

  return colors[color];

Done!

jeffamaphone
Well put sir, I like that. Adds some more association to the colors then a switch statement. However, with this method of color sorting, wouldn't I have to hold a copy of every color in memory, all the time?
Xoorath
@Xoorath: So how many colors have you got? If it's less than 10^6, what's the problem?
Mike Dunlavey
@Mike: I have 151. There is no 'problem' necessarily. However I'll be using this in making video games, on platforms with potentially limited memory; Assuming each vec has 4 elements (RGBA), then I'm holding 604 floats or doubles in memory, when I could be using processing power to switch between the colors, rather then storing the data. I'm just wondering if I can find a good middle ground between eating up CPU power versus memory. This is still certainly a viable option though.
Xoorath
Well, you could not initialize the map, then if map::find() doesn't find the color, you add it... or you can just give the enums values that match their hex value.
jeffamaphone
@Xoorath: It sounds to me like all you need is an array of RGBA values. Initialize it in the compiler, so initializing it consumes no code. Index it by an integer enum. You can't get more efficient, in time or memory, than that. I do wonder why you're storing each R/G/B/A value in floating point. Wouldn't a fixed-point fraction do just as well, of 8 or 16 bits, with no floating-point conversion overhead? Basically @adf88's solution.
Mike Dunlavey
@Mike Dunlavey: Well put Mike, I'm still going to have to play around with it some, but this really does help point me in the right direction, for sure. As for the floating point storage, when programing in openGL last semester, my text book used floats for all color data, and I assumed it to be the best way of doing so. I'll have to look into fixed-point fractions, because I've never worked with them before.
Xoorath
@Xoorath: Well, like @adf88 said, you could store your numbers as unsigned chars 0-255. That's a fixed-point fraction. Apollo went to the moon on fixed-point fractions. Like if you've got a 36-bit word, just imagine the "decimal point" is in the middle. Not much else to it.
Mike Dunlavey
Using std::map is terrible waste here! When comparing to lookup table: memory - about 2 times more, speed - few hundred times slower (or more!), initialization - few hundred times slower (or more).
adf88
@adf88: If the map is only 2 times slower, I'd be really surprised. More like 10-20 if I had to guess.
Mike Dunlavey
If I find time, I'll compare the two in direct context of what I'm doing and report back with performance benefits. The only reason it may be harder to judge from research alone, is because I will have to initialize the values outside of the constructor, because I'm actually using a vec class, not a vec3 class, so the constructor takes the number of elements as the argument.
Xoorath
Reading that over, it sounds pretty dumb. But I can't find a better way to word it.
Xoorath
Using a map really is over kill, but it fits semantically with what you asked for, and if this is your biggest performance problem then you *freaking win*. But I applaud measuring instead of listening to us yahoos.
jeffamaphone
@jeffamaphone: Totally off-topic, but what is that computer in your home-page icon? It looks a bit like an old 360, but I know it's not that. 7094? Univac? Burroughs? British machine?
Mike Dunlavey
It's SAGE, from the computer history museum in Mountain View, CA.
jeffamaphone
@jeffamaphone: I admit, I didn't guess that.
Mike Dunlavey
+1  A: 

Use a lookup table:

/************* .h *************/

enum color{
    red,
    blue,
    green,

    colors_count
}

const vec3 &getColor(color c)
{
    extern const vec3 colors_table[colors_count];
    return colors_table[c];
}

/************* .cpp *************/

extern const vec3 colors_table[colors_count] = {
    vec3(255, 0, 0), // red
    vec3(0, 0, 255), // blue
    vec3(0, 255, 0), // green
};

You didn't write anything about purpose of using templates so I just eliminated them. If you explain more then I will help maybe.

// EDIT
It's very simple and very fast.
In c++, enum values are not just some identifiers, they are numbers. If you don't specify other they will be fallowing numbers starting from 0: 'red' is 0, 'blue' is 1, 'green' is 2 and 'colors_count' is 3 (see http://www.google.com/search?q=c%2B%2B+enum). You can use these numbers to index an array. Then you simply pick an item from an array at given index.

adf88
Yeah, sorry, I'll nix the template from the example above shortly. This is interesting though. I'll have to do a bit of reading, and try this out. I'm actually not sure how this would work exactly.
Xoorath
I made some editing, now it should be all clear.
adf88
Yeah. Looks great man, thank you.
Xoorath