Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-time 'String' Manipulation with Variadic Templates

Hey all, I'm currently trying to write a compile-time string encryption (using the words 'string' and 'encryption' quite loosely) lib.

What I have so far is as follows:

// Cacluate narrow string length at compile-time
template <char... ArgsT>
struct CountArgs
{
 template <char... ArgsInnerT> struct Counter;

 template <char Cur, char... Tail>
 struct Counter<Cur, Tail...>
 {
  static unsigned long const Value = Counter<Tail...>::Value + 1;
 };

 template <char Cur>
 struct Counter<Cur>
 {
  static unsigned long const Value = 1;
 };

 static unsigned long const Value = Counter<ArgsT...>::Value;
};

// 'Encrypt' narrow string at compile-time
template <char... Chars>
struct EncryptCharsA
{
 static const char Value[CountArgs<Chars...>::Value + 1];
};

template<char... Chars>
char const EncryptCharsA<Chars...>::Value[CountArgs<Chars...>::Value + 1] =
{
 Chars...
};

However I can't figure out how to perform operations on the characters as I expand them into the static array. I'd just like to execute a simple operation on each character (e.g. '(((c ^ 0x12) ^ 0x55) + 1)' where c is the character).

A shove in the right direction would be greatly appreciated.

Thanks all.

like image 416
RaptorFactor Avatar asked Aug 16 '10 11:08

RaptorFactor


2 Answers

If you just want to operate on one character at a time its easy:

template<char c> struct add_three {
    enum { value = c+3 };
};

template <char... Chars> struct EncryptCharsA {
    static const char value[sizeof...(Chars) + 1];
};

template<char... Chars>
char const EncryptCharsA<Chars...>::value[sizeof...(Chars) + 1] = {
    add_three<Chars>::value...
};

int main() {   
    std::cout << EncryptCharsA<'A','B','C'>::value << std::endl;
    // prints "DEF"
}

Note that CountArgs is redundant (that's what sizeof... is for) and that this uses element-wise transformation of the elements in a parameter-pack.


To make the transformation dependent on previous results, one option would be to consume the characters recursively, one at a time, and incrementally build a new template from that:

template<char... P> struct StringBuilder {
    template<char C> struct add_char {
        typedef StringBuilder<P..., C> type;
    };

    static const char value[sizeof...(P)+1];
};

template<char... P> const char StringBuilder<P...>::value[sizeof...(P)+1] = {
    P...
};

template<class B, char...> struct EncryptImpl;

template<class B, char Seed, char Head, char... Tail> 
struct EncryptImpl<B, Seed, Head, Tail...> {
    static const char next = Head + Seed; // or whatever
    typedef typename EncryptImpl<
        typename B::template add_char<next>::type,
        next, Tail...
    >::type type;
};

template<class B, char Seed> struct EncryptImpl<B, Seed> {
    typedef B type;
};

template<char... P> struct Encrypt {
    typedef typename EncryptImpl<StringBuilder<>, 0, P...>::type type;
};
like image 70
Georg Fritzsche Avatar answered Sep 21 '22 11:09

Georg Fritzsche


If I understand what you want to do correctly (actually create an array at compile time) I think variadic templates aren't enough and you'll have to wait for constexpr.

If however you don't need an actual array and can instead compromise on using something akin to tuple's get<I> then it's possible (you can then build a char array at runtime).

like image 28
Motti Avatar answered Sep 19 '22 11:09

Motti