Skip to content

Instantly share code, notes, and snippets.

@sumerman
Created April 29, 2011 16:47
Show Gist options
  • Save sumerman/948605 to your computer and use it in GitHub Desktop.
Save sumerman/948605 to your computer and use it in GitHub Desktop.
Type encoding and conversion of encoded types through metaprogramming
#include <cstdlib>
#include <cstdio>
#include <iostream>
using namespace std;
template <typename T1, typename T2>
class Cast {
private:
struct BigType {
char a[2];
};
template <typename T>
static T makeT(void);
static char test(...);
static BigType test(T2 t);
public:
enum {
exists = sizeof(test(makeT<T1>())) == sizeof(BigType)
};
};
namespace Encoding {
template <typename H, typename T>
struct TL {
typedef H Head;
typedef T Tail;
};
template <typename T, char c>
struct EP {
typedef T Type;
static const char code = c;
};
template <typename Head>
struct PairParser;
template <typename T, char enc>
struct PairParser<EP<T, enc> > {
typedef T Type;
static const char encoding = enc;
};
struct NullType;
//typedef TL<EP<int, 'i'>, TL<EP<char, 'c'>, TL<EP<float, 'f'>, TL<EP<double, 'd'>, TL<EP<bool, 'b'>, NullType> > > > > Encodings;
typedef
TL<EP<char, 'c'>, TL<EP<char *, 'C'>, TL<EP<bool *, 'B'>, TL<EP<int *, 'I'>, TL<EP<int, 'i'>, TL<EP<double *, 'D'>, TL<EP<double, 'd'>, TL<EP<short, 'h'>, TL<EP<short *, 'H'>, TL<EP<bool, 'b'>, TL<EP<float, 'f'>, TL<EP<long, 'l'>, TL<EP<long *, 'L'>, TL<EP<float *, 'F'>, NullType > > > > > > > > > > > > > >
Encodings;
template <typename List, typename T>
struct EncFor {
static const char result = 0;
};
template <typename T>
struct EncFor<NullType, T> {
static const char result = 0;
};
template <typename T, typename Tail, char c>
struct EncFor<TL<EP<T, c>, Tail>, T> {
static const char result = EP<T, c>::code;
};
template <typename T, typename Wrong, typename Tail, char c>
struct EncFor<TL<EP<Wrong, c>, Tail>, T> {
static const char result = EncFor<Tail, T>::result;
};
template <typename T>
inline char encodeType(void) {
return EncFor<Encodings, T>::result;
}
template <typename T>
inline char encodeVarType(T t) {
return encodeType<T>();
}
typedef void (*Conversion)(void*, void*);
template <typename X, typename Y>
class ConversionFor {
template <typename A, typename B>
static inline void conversionA2B(void *a, void *b) {
*(B *)b = (B)(*(A *)a); // vandalism
}
template <int exists, typename A, typename B>
struct ConvCase {
static inline Conversion conv(void) {
return conversionA2B<A, B>;
}
};
template <typename A, typename B>
struct ConvCase<0, A, B> {
static inline Conversion conv(void) {
return 0;
}
};
public:
static inline Conversion conversion(void) {
return ConvCase<Cast<X, Y>::exists, X, Y>::conv();
}
};
class TableHolder {
enum {
tableSize = sizeof(char)*256 //TODO
};
public:
Conversion conversions[tableSize][tableSize];
size_t sizes[tableSize];
TableHolder() {
for(size_t i = 0; i < tableSize; ++i)
for(size_t j = 0; j < tableSize; ++j)
conversions[i][j] = 0;
for(size_t i = 0; i < tableSize; ++i)
sizes[i] = 0;
}
};
template <typename X, typename List>
struct BuildLine {};
template <typename _>
struct BuildLine<_, NullType> {};
template <typename X, typename Head, typename Tail>
struct BuildLine<X, TL<Head, Tail> >: public BuildLine<X, Tail>, virtual public TableHolder {
typedef PairParser<X> XP;
typedef PairParser<Head> YP;
BuildLine(void) {
conversions[(size_t)XP::encoding][(size_t)YP::encoding] =
ConversionFor<typename XP::Type, typename YP::Type>::conversion();
}
};
template <typename List>
struct BuildTables {};
template <>
struct BuildTables<NullType> {};
template <typename Head, typename Tail>
struct BuildTables<TL<Head, Tail> >:
public BuildLine<Head, TL<Head, Tail> >,
public BuildTables<Tail>,
virtual public TableHolder {
typedef PairParser<Head> P;
BuildTables(void) {
sizes[(size_t)P::encoding] = sizeof(typename P::Type);
}
};
}
using namespace Encoding;
int main(int argc, char **argv) {
printf("%c\n", encodeType<int>());
int i = 100;
double d = 0.5;
BuildTables<Encodings> cts;
Conversion i2d = cts.conversions[(int)encodeVarType(i)][(int)encodeVarType(d)];
(*i2d)(&i, &d);
cout << d << endl;
cout << cts.sizes['d'] << " | " << cts.sizes['i'] << endl;
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment