views:

165

answers:

2

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.

+1  A: 

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).

Motti
Ah of course, I didn't think of that. Yes, building the string at runtime from individually 'encrypted' characters is an acceptable solution for now. As long as the actual manipulation of the characters happens at compile time that will be great.Thanks!
RaptorFactor
Ugh, this stuff is so hard to get your head around at first. I have no idea how people can even maintain certain TMP-heavy libs (looking at you Boost! :P).
RaptorFactor
Could you please provide an example of how I'd build the string at runtime? I've added the 'get' function and got it working on a character-by-character basis, but because it's a template I can't just throw it in a loop and build the string at runtime that way. I'm confused about how I'm supposed to do it short of doing it completely manually (i.g. manually calling get<> for each character and manually adding it to my string). I'd greatly appreciate another push in the right direction, I'm pretty new to all this stuff. Thanks. :)
RaptorFactor
Variadic templates combined with element-wise transformation of elements in a parameter-pack are enough for this.
Georg Fritzsche
@Georg: Any chance you could provide a bit more information? I'm still struggling.
RaptorFactor
@Raptor: Right below in my answer :)
Georg Fritzsche
@Georg, you mean above :), nice work.
Motti
I guess i should know by now that the positioning inevitably changes if i write such a comment :)
Georg Fritzsche
+3  A: 

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;
};
Georg Fritzsche
Thanks. Eventually however I wanted to expand it to operate using a more complex algorithm (i.e. using the result of the previous operation as a 'seed' for the 'encryption' of the next character). Is that even possible, or will I need to stick with a single-character solution?EDIT:Just tested your solution btw and it worked! Still curious about whether it's possible to implement it using a more complex algorithm.
RaptorFactor
@Raptor: Hm, thinking about it.
Georg Fritzsche
It's a fun problem. ^_^
RaptorFactor
@Raptor: Indeed, especially if you get confused by [such issues](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653) ;) There might be more elegant options, but this is the only one that i can think of at the moment.
Georg Fritzsche
Thanks, greatly appreciated! :)
RaptorFactor