Monday, October 22, 2012

c++11 universal init vs tuples.

While messing around with tuples I noted a rather large headache with its array initialization. If im not mistaken the problem is caused by the choice to make the constructor explicit. Basically this will ultimately force the user to typedef the tuple and then explicitly construct each of the lines in the array init.


#include <iostream>
#include <tuple>

int array[2]{1,2};

struct TableEntryC
{
  int         a;
  double      b;
  const char* c;
};

TableEntryC tableC[2]
{
  {1,1.1,"test"},
  {2,2.2,"try"}
};

typedef std::tuple<int,double,std::string> TableEntry;

TableEntry entry{ 1, 1.1, "test" };

TableEntry table[2]
{
  TableEntry{1,1.1,"test"},
  TableEntry{2,2.2,"try" }
};

// bad bad bad...
//TableEntry bad_table[2]
//{
//  {1,1.1,"test"},
//  {2,2.2,"try" }
//};


int main()
{
  std::cout << std::get<1>(entry) << std::endl;
  std::cout << std::get<2>(table[1]) << std::endl;
}

Monday, October 1, 2012

c++11 tuples and schema generation

Thanks to the new c++11 its finally possible create a system which can take in generic data structures and convert them automatically into the SQL schema and commands.

To do this you simply have to use the tuple as the class container(which you can typedef however its pleases you) and create the Database Adapter with a few of variadic templates that auto generate the SQL commands for data handling. Here is an example of generating the CREATE TABLE command for an sql-lite database adapter.

#include <iostream>
#include <string>
#include <sstream>

template <typename T>
std::string to_string(T t)
{
  //hmm this is missing!
  std::stringstream ss;
  ss << t;
  return ss.str();
}

template <typename I>
struct SchemaType
{
};

template <>
struct SchemaType<int>
{
  static constexpr const char* type = "INTEGER";
};

template <>
struct SchemaType<float>
{
  static constexpr const char* type = "REAL";
};

template <>
struct SchemaType<char*>
{
  static constexpr const char* type = "TEXT";
};

//CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x DESC));
template <typename... II>
struct AutoSchemaCore;

template <typename I, typename... II>
struct AutoSchemaCore<I, II...>
{
  static std::string create_params()
  {
    std::string ret = "a"
      + to_string(sizeof...(II))
      + " "
      + SchemaType<I>::type;
    if (sizeof...(II) > 0)
      {
     ret += ","
   + AutoSchemaCore<II...>::create_params();
      }
    return ret;
  }
};

template <>
struct AutoSchemaCore<>
{
  static std::string create_params()
  { return ""; }
};

template <typename I, typename... II>
struct AutoSchema
{
  static std::string create_table(const char* tablename)
  {
    // CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x DESC));
    return std::string("CREATE TABLE ") 
      + tablename
      + "("
      + AutoSchemaCore<I,II...>::create_params()
      + ");";
  }
};

int main()
{
  //generate the CREATE TABLE t(...) SQL command 
  std::cout << AutoSchema<float>::create_table("tableA") << "\n";
  std::cout << AutoSchema<int,char*,float>::create_table("tableB") << "\n";
}

Result
CREATE TABLE tableA(a0 REAL);
CREATE TABLE tableB(a2 INTEGER,a1 TEXT,a0 REAL);