Cookies & Maths

21 07 2010

Finished the Vectors side of the library today. Mostly anyway, I’ve left it somewhat unoptimized at the moment, ran some preliminary tests which told me that premature optimization is the root of all evil and that the vectors are performing within the acceptable performace ratio [in theory].

I’ve used templates quite heavily throughout the vector functions themselves, so that the functions would work on any object which inherits from the vector base. But maybe I’m jumping the gun here. Let me take a step back and just walk down the path of my concepts and prototypes.

One of the things I found the hardest to approach was the basic design of an extensible Vector class. I know that the most used objects are Vector2, Vector3 and Vector4, but there are also uses for Vector6 and Vector7 and having to rewrite every single function for every single object just struck me as, well, not something I’d endorse. Enter templates…

Now, making a template Vector class for all dimensions and for some value type is quite easy:
template<const unsigned Dimension, typename ValueTyp>
class Vector
{
  public:
    typedef ValueType value_type;
    enum { size=Dimension };
    /*operators*/
    /*Functions*/
  private:
    value_type m[size];
};

On the surface it looks good, easy to use, easy to define as many types of Vectors as I need, but there’s a little, and not so little, annoying aspect of this class. There’s no way to provide it with a custom constructor for different sizes and there’s no way to provide read/write data functions [or references if that tickles yer fancy].

The other point I’d like to make about this class, before moving on, is the use of the enum and the typedef. For those who read this thing [other than me] and have had experience with template and/or meta-programming, will quickly recognize these as defining the traits of the class. Traits are quite important to any meta-program as they allow us to query information of the class/object at compile time [and runtime of course] and are a cental feature of writing proper meta-functions which work on objects that have these traits. I’ll write more on this subject in the next post.

Back to my Vector.

My first idea was to extract the data itself from the Vector object and into what I’ve termed the DataDescriptor and inherit from this object on construction of the Vector template. The code would look like this:
template<typename DataDescriptor>
class Vector : public DataDescriptor
{
  public:
    typedef DataDescriptor data;
    /*operators*/
    /*functions*/
};

A data descriptor, for example could be:
class VectorXY
{
  public:
    enum { size=2 };
    typedef float value_type;
    value_type& x() return { m[0]; }
    value_type& y() return { m[1]; }
    VectorXY(value_type x, value_type y);
  protected:
    value_type m[size];
};

Looks good, and supplies everything I need, right? not quite. Having the main Vector class inheriting from the data descriptor forced me to overwrite the Vector copy constructor to allow the usage of the DataDescriptor’s custom constructor which lead to code that looked like this:
typedef Storm::Vector<VectorXY> vector2;
vector2 vec1(vector2::data(1.0f, 1.0f);

Not too bad, but still annoying. It also forced me to either provide a direct accessor for the underlying data of the DataDescriptor so that the vector functions could access it, or scope the underlying data as protected [as in the example]. I’m a great believer that data should either be public or private, and it shouldn’t be public. Any data at the protected scope is essentially half a step away from being public and I’d rather avoid using it altogether.

To conclude, it’s clear, that while this approach is more extensible then having a separate class for each vector type with its own specialized functions, it is still not quite there. Having the DataDescriptor as the base class still involves writing far too much code than is needed and also forces some not-so-desirable convensions on the DataDescriptor’s writer. But what other alternatives did I find?

That’s an excellent question. But it’s 3:49 in the morning and the dishes aren’t done [again] so the answer will have to wait until my next post [which should be either tomorrow night, or Friday night].

We are the road crew

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: