Thursday, September 27, 2012

Tablified Traits

Here is simple c++ trait wrapper that goes around the old standard c++ array of structs lookup table. It handles the forward and reverse lookup of the trait entry via its main key and an attrib and then the access of the various attributes from the resulting row.

There are some caveats to it. The Enum id cant be sparse. and the UNKNOWN entry needs to be second last before the MAX entry marker.

#include <iostream>

template<int LAST, typename R, typename T>
R lookup(T* table, R T::*member, int key) 
{
  if (key < LAST) return table[key].*member;
  return table[LAST].*member;
}

template<int LAST, typename R, typename T>
int locate(T* table, R T::*member, R target) 
{
  int k = 0;
  while (k < LAST)
    {
      if (table[k].*member ==  target)
 return k;
      k++;
    }
  return LAST;
}

template<int LAST, typename T>
int locate(T* table, const char* T::*member, const char* target) 
{
  int k = 0;
  while (k < LAST)
    {
      if (std::string(table[k].*member) == std::string(target))
 return k;
      k++;
    }
  return LAST;
}

class TableTrait
{
public:
  enum Key
    {
      ITEM1,
      ITEM2,
      ITEM3,
      ITEM4,
      ITEM5,
      UNKNOWN, //Must be second last
      MAX      //Must be last
    };    

private:  
  struct TableEntry
  {
    Key         key;
    int         attribA;
    bool        attribB;
    const char* attribC;
  };

  static TableEntry lookup_table[MAX];

  int key_;
public:
  TableTrait(int key) :
    key_(lookup<UNKNOWN>(lookup_table, &TableEntry::key, key))
  {}

  TableTrait(const char* rev_key) :
    key_(locate<UNKNOWN>(lookup_table, &TableEntry::attribC, rev_key))
  {}

  bool        valid()   { return key_ != UNKNOWN; }
  Key         key()     { return static_cast<Key>(key_); }
  int         attribA() { return lookup<UNKNOWN>(lookup_table, &TableEntry::attribA, key_); }
  bool        attribB() { return lookup<UNKNOWN>(lookup_table, &TableEntry::attribB, key_); }
  const char* attribC() { return lookup<UNKNOWN>(lookup_table, &TableEntry::attribC, key_); }  
};

TableTrait::TableEntry TableTrait::lookup_table[TableTrait::MAX] =
{
  { ITEM1,   3, false, "ITEM1"   },
  { ITEM2,   2, true,  "ITEM2"   },
  { ITEM3,   6, false, "ITEM3"   },
  { ITEM4,   5, true,  "ITEM4"   },
  { ITEM5,   8, false, "ITEM5"   },
  { UNKNOWN, 0, false, "UNKNOWN" }
};

int main()
{
  std::cout << "lookup: " << TableTrait(TableTrait::ITEM1).attribC() << "\n";
  std::cout << "lookup: " << TableTrait(TableTrait::ITEM2).attribB() << "\n";
  std::cout << "locate: " << TableTrait("ITEM3"          ).attribA() << "\n";
  std::cout << "locate: " << TableTrait("ITEM2"          ).key()     << "\n";
  std::cout << "locate: " << TableTrait("Blah"           ).attribC() << "\n";
}

No comments:

Post a Comment