Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Code duplication with template type

18 views
Skip to first unread message

Frederick Gotham

unread,
Mar 23, 2020, 4:55:54 AM3/23/20
to

The only difference between the following two functions is that I have

::Encryption

instead of

::Decryption

Is there any way of getting rid of this code duplication? (By the way I realise I can use the C preprocessor but I'd like to find a better solution before resorting to that).

CryptoPP::BlockTransformation &GetAlgorithm_Forward(unsigned const i)
{
static thread_local CryptoPP:: AES ::Encryption a(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::Twofish::Encryption b(Kalpha,g_KEYSIZE);
static thread_local TDES16::Encryption c(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::CAST256::Encryption d(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::Serpent::Encryption e(Kalpha,g_KEYSIZE);

switch ( i )
{
case 0: return a;
case 1: return b;
case 2: return c;
case 3: return d;
case 4: return e;
}

assert(0 == "Control should never reach here");
}

CryptoPP::BlockTransformation &GetAlgorithm_Backward(unsigned const i)
{
static thread_local CryptoPP:: AES ::Decryption a(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::Twofish::Decryption b(Kalpha,g_KEYSIZE);
static thread_local TDES16::Decryption c(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::CAST256::Decryption d(Kalpha,g_KEYSIZE);
static thread_local CryptoPP::Serpent::Decryption e(Kalpha,g_KEYSIZE);

switch ( i )
{
case 0: return a;
case 1: return b;
case 2: return c;
case 3: return d;
case 4: return e;
}

assert(0 == "Control should never reach here");
}

Maciej Sobczak

unread,
Mar 23, 2020, 7:29:56 AM3/23/20
to

> The only difference between the following two functions is that I have
>
> ::Encryption
>
> instead of
>
> ::Decryption

And from the remaining code I can deduce that these are classes deriving from a common base class BlockTransformation, with very likely a single operation that does one or the other thing.

Note, however, that the similarity of class names is just a coincidence and that was your choice.
If you have pairs of classes that are so tightly bound that it does not make sense to use them separately (or to mix them between pairs), then perhaps having them as separate classes was a mistake in the first place? Why these classes are separate if in fact they are bound by an algorithm?
What about having a single class with two operations instead?
Like:

class AES : public ...
{
public:
virtual ... encrypt(...);
virtual ... decrypt(...);

// ...
};

Then there would be duplication in your code, and the number of leaf classes would be halved. A single class would then encapsulate the single algorithm (and there is a chance that both encrypt and decrypt operations reuse a common computational mechanics anyway).

In other words, you have code duplication, because you have designed your class hierarchy with too fine granularity in the first place.

I don't claim that the above is certainly better, without knowing the rest of your design - and there is a chance that removing some code duplication in one place will generate it in some other place. You have to judge this trade off on your own. :-)

--
Maciej Sobczak * http://www.inspirel.com

Öö Tiib

unread,
Mar 23, 2020, 7:34:20 AM3/23/20
to
I would do it using a random idea of selecting between types compile
time. Like that:

#include <iostream> // I/O of current garbage
#include <type_traits> // std::conditional
#include <cassert> // old school assert

// just classes for demoing
enum Direction {Error, Decrypt, Encrypt};
struct Encryption {Encryption() {std::cout << "Encryption made\n";} };
struct Decryption { Decryption() {std::cout << "Decryption made\n";} };
struct Disaster { Disaster() {assert(not "Disaster useful");} };

template<Direction D>
using Transformation = std::conditional<D == Decrypt, Decryption
, typename std::conditional<D == Encrypt, Encryption
, Disaster
>::type>::type;

int main()
{
Transformation<Encrypt> a;
Transformation<Decrypt> b;
Transformation<Error> c;
}

Trying on gcc version 9.2.0 gave that (did not try elsewhere):

a.out: main.cpp:9: Disaster::Disaster(): Assertion `not "Disaster useful"' failed.
Encryption constructed
Decryption constructed
bash: line 7: 15254 Aborted (core dumped) ./a.out

Alf P. Steinbach

unread,
Mar 23, 2020, 7:44:03 AM3/23/20
to
In this code CryptoCPP is a namespace and AES, Twofish, TDES16, CAST256
and Serpent are classes.

You can do things like (off the cuff)

struct Which_way{ enum Enum{ encrypt, decrypt }; };

template< class Cipher, Which_way::Enum >
struct Transformation_;

template< class Cipher >
struct Transformation_<Cipher, Which_way::encrypt>
{
using T = Cipher::Encryption;
};


template< class Cipher >
struct Transformation_<Cipher, Which_way::decrypt>
{
using T = Cipher::Decryption;
};

template< Which_way::Enum direction >
auto algorithm( const int i )
-> CryptoPP::BlockTransformation&
{
static thread_local typename
Transformation_<CryptoPP::AES, direction>::T a(Kalpha,g_KEYSIZE);
// Etc.
}

- Alf
0 new messages