Skip to content

Instantly share code, notes, and snippets.

@iscgar
Last active February 15, 2016 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iscgar/9ba8fc9348af4389b26b to your computer and use it in GitHub Desktop.
Save iscgar/9ba8fc9348af4389b26b to your computer and use it in GitHub Desktop.
Abusing type lists for easier generic development
#include <stdio.h>
#include <string.h>
#include <ctype.h>
namespace detail
{
template<typename T>
bool detail_echo(const T *obj, const char *arg)
{
if (!obj)
{
return false;
}
obj->echo(arg);
return true;
}
}
struct nil_tl {};
template<typename T, typename U = nil_tl>
struct typelist
{
T head;
U tail;
};
template<typename TL> class echoer;
template<typename H>
class echoer<typelist<H, nil_tl> >
{
public:
inline echoer() : m_object(), m_echoer() {}
inline bool init(const char *name)
{
bool can_set = m_object.equals(name);
if (can_set)
{
this->m_echoer.set(detail::detail_echo<H>, &m_object);
}
return can_set;
}
inline bool echo(const char *val) { return this->m_echoer.call(val); }
inline void reset() { this->m_echoer.set(NULL, NULL); }
protected:
template<typename V>
inline void reset(bool (*func)(const V *, const char *), const V *echoer)
{
this->m_echoer.set(func, echoer);
}
private:
struct prv_detail
{
inline prv_detail() : m_func(NULL), m_obj(NULL) {}
template<typename V>
inline void set(bool (*func)(const V *, const char *), const V *echoer)
{
this->m_func = reinterpret_cast<bool (*)(const void *, const char *)>(func);
this->m_obj = echoer;
}
inline bool call(const char *value)
{
if (!this->m_func)
{
return false;
}
// UB?
return (*this->m_func)(this->m_obj, value);
}
private:
bool (*m_func)(const void *, const char *);
const void *m_obj;
};
const H m_object;
prv_detail m_echoer;
};
template<typename H, typename T>
class echoer<typelist<H, T> > : public echoer<T>
{
public:
inline echoer() : m_object() {}
using echoer<T>::echo;
using echoer<T>::reset;
bool init(const char *name);
private:
const H m_object;
};
template<typename H, typename T>
bool echoer<typelist<H, T> >::init(const char *name)
{
if (this->m_object.equals(name))
{
this->reset(detail::detail_echo<H>, &this->m_object);
return true;
}
return echoer<T>::init(name);
}
struct lower_echoer
{
inline bool equals(const char *name) const { return name && stricmp(name, "lower") == 0; }
void echo(const char *value) const
{
while (*value)
{
fputc(tolower(*value), stdout);
++value;
}
}
};
struct upper_echoer
{
inline bool equals(const char *name) const { return name && stricmp(name, "upper") == 0; }
void echo(const char *value) const
{
while (*value)
{
fputc(toupper(*value), stdout);
++value;
}
}
};
struct normal_echoer : lower_echoer, upper_echoer
{
virtual bool equals(const char *name) const { return name && stricmp(name, "normal") == 0; }
virtual void echo(const char *value) const
{
char data[] = " ";
bool begin = true;
while (*value)
{
data[0] = *value;
if (begin)
{
upper_echoer::echo(data);
}
else
{
lower_echoer::echo(data);
}
begin = isspace(*value);
++value;
}
}
};
struct rnormal_echoer : normal_echoer
{
virtual bool equals(const char *name) const { return name && stricmp(name, "rnormal") == 0; }
virtual void echo(const char *value) const
{
char data[] = " ";
bool end = false;
while (*value)
{
data[0] = *value;
end = !isalpha(value[1]);
if (end)
{
upper_echoer::echo(data);
}
else
{
lower_echoer::echo(data);
}
++value;
}
}
};
int main(int argc, char const *argv[])
{
if (argc < 2)
{
printf("Usage: echoer <name> [words ...]\n");
}
else
{
typedef typelist<lower_echoer, typelist<upper_echoer, typelist<normal_echoer, typelist<rnormal_echoer, nil_tl> > > > echoers;
echoer<echoers> ech_handler;
if (!ech_handler.init(argv[1]))
{
fprintf(stderr, "ERROR: Could not find `%s\'\n", argv[1]);
}
else if (argc > 2)
{
switch (argc)
{
default:
for (int i = 2; i < argc - 1; ++i)
{
ech_handler.echo(argv[i]);
ech_handler.echo(" ");
}
case 3:
ech_handler.echo(argv[argc - 1]);
ech_handler.echo("\n");
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment