I have a big factory, and I'm trying to figure out how to make it look pretty.
There are about 40 possible object/constructor combinations:
if(algorithm == "SHA-1")
return new HashImpl<...>(algorithm, seed, size);
if(algorithm == "SHA-224")
return new HashImpl<...>(algorithm, seed, size);
if(algorithm == "SHA-256")
return new HashImpl<...>(algorithm, seed, size);
...
if(algorithm == "AES" || algorithm == "AES128")
return new BlockCipherImpl<...>(algorithm, seed, size);
...
if(algorithm == "HmacSHA1")
return new HmacImpl<...>(algorithm, seed, size);
...
Is there a way to put this into a map so I can at least do away with the sequential search? I'm having problems figuring out how to make the constructor a functor.
EDIT: The code can be found here:
http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/src/crypto/SecureRandomImpl.cpp, starting around line 130.
No need to use them fancy newfangled maps.
template <class Impl>
BaseImplementation* makeAlgo (const std::string& algo,
const byte* seed, size_t size)
{
return new Impl(algo, seed, size);
}
typedef BaseImplementation* makeAlgo_t (const std::string& algo,
const byte* seed, size_t size);
typedef struct { std::string name; makeAlgo_t func; } NamedAlgoMaker_t;
NamedAlgoMaker_t factory[] = {
{ "SHA-1", makeAlgo< HashImpl <...> > },
...
{ "HmacSHA1", makeAlgo< HmacImpl <...> > },
...
};
If you keep the array sorted, you can use binary search to find the algorithm quickly.
Of course you can build a map (or hash/unordered map) out of these things too, if you want to.
You can use either a map of lambda functions perhaps
So it will still be visually ugly. But you can make it faster in the following way:
Create ~40 factory methods, each of which returns one of these choices.
Create a map where fnPointerTypedef is the return type of your factory method.
Do a dictionary look up, and return the result of whichever function you look up.
Create an enum that gives a number for each option (e.g. SHA-1 = 0, SHA-224 = 1, etc..).
Create a map that maps the string name to the {int|enum}.
Create an array of function pointers, and have each spot in the array point to the correct corresponding factory method.
Do a dictionary look up and return functionArray[enumInt];
(Edit: Thanks n.m. for more direct implementation)
Related
The obvious way is to just write two functions, but then they are almost identical. What I'm doing now is a function template with the return type (either bool or vector<something>) as the argument
template<typename ReturnType>
ReturnType foo(...){
constexpr bool return_bool = std::is_same<ReturnType, bool>::value;
ResultType results; //hopefully, the compiler takes it out in the bool case
And the plan is to use if constexpr(return_bool) when needed. But then I get this reoccurring piece of code
ReturnType result = foo<ResultType>(...);
if constexpr(return_bool){
if(result) return true;
}else std::copy(result.begin(), result.end(), std::back_inserter(results));
The return statement makes it hard to use standard anti-repetition techniques. I could use macros but then perhaps the repetition is better. Getting either all solutions or just the information whether one exists seems like a fairly general problem, is there a better way to do it?
I should've added that the function is performance-critical in the "does a solution exist?" case. That's why I want to have another version there and also why I don't want any costly abstractions.
You want two opposite features :
Reusing one solution in the other to avoid replication
Having an optimized version for solutionExists() to avoid a full result search
You didn't specify what is the solution your function returns, so I will explain why you can't have both using a simple example : your function is returning the number of ocurences of 0 in a vector of integers.
The function returning all solutions would look like this :
int GetNumberOfOccurencesOf0(const vector<int>& data)
{
int occurences = 0;
for (int i : data)
{
if (i == 0)
++occurences;
}
return occurences;
}
If you are not concerned about performance, your function for returning if there is a solution can be :
bool AreThereOccurencesOf0(const vector<int>& data)
{
return (GetNumberOfOccurencesOf0(data) > 0);
}
Note that there is no code duplication but the solution is not optimal : the data vector is iterated entirely. If you want an optimized solution, it would look like this :
bool AreThereOccurencesOf0(const vector<int>& data)
{
for (int i : data)
{
if (i == 0)
return true;
}
return false;
}
If your problem requires an optimized version of solutionExists(), you should write it and it should not need to reuse code from the getAllSolutions() function.
CppCheck suggest me to replace one of my code by a STL algorithm, I'm not against it, but I don't know how to replace it. I'm pretty sure this is a bad suggestion (There is warning about experimental functionalities in CppCheck).
Here is the code :
/* Cutted beginning of the function ... */
for ( const auto & program : m_programs )
{
if ( program->compare(vertexShader, tesselationControlShader, tesselationEvaluationShader, geometryShader, fragmentShader) )
{
TraceInfo(Classname, "A program has been found matching every shaders.");
return program;
}
}
return nullptr;
} /* End of the function */
And near the if condition I got : "Consider using std::find_if algorithm instead of a raw loop."
I tried to use it, but I can't get the return working anymore... Should I ignore this suggestion ?
I suppose you may need to use that finding function not once. So, according to DRY, you need to separate the block where you invoke an std::find_if algorithm to a distinct wrapper function.
{
// ... function beginning
auto found = std::find_if(m_programs.cbegin(), m_programs.cend(),
[&](const auto& prog)
{
bool b = prog->compare(...);
if (b)
TraceInfo(...);
return b;
});
if (found == m_programs.cend())
return nullptr;
return *found;
}
The suggestion is good. An STL algorithm migth be able to choose an appropriate
approach based on your container type.
Furthermore, I suggest you to use a self-balancing container like an std::set.
// I don't know what kind of a pointer you use.
using pProgType = std::shared_pointer<ProgType>;
bool compare_progs(const pProgType &a, const pProgType &b)
{
return std::less(*a, *b);
}
std::set<std::shared_pointer<prog_type>,
std::integral_constant<decltype(&compare_progs), &compare_progs>> progs.
This is a sorted container, so you will spend less time for searching a program by a value, given you implement a compare operator (which is invoked by std::less).
If you can use an stl function, use it. This way you will not have to remember what you invented, because stl is properly documented and safe to use.
(This could be an XY Problem, so I'm providing some background information prior to the actual question.)
Background
I currently have a function (not a template) that computes different hash types (CRC32, MD5, SHA1, etc.) The data comes from a provider that can only provide a pointer to a chunk of the data at a time. The function computes the hashes on chunks of data iteratively.
Advancing to the next chunk is a very costly operation (involves decompression) and it can only go forward. Also the architecture must be kept zero-copy. As a result, all the selected hashes must be computed at once while iterating on the same chunks of data. Hash type selection is done through bool parameters:
std::tuple<uint32_t, QByteArray, QByteArray, QByteArray>
computeHashes(DataProvider& data, bool do_crc, bool do_md5, bool do_sha1,
bool do_sha256);
If one of the flags is false, the caller ignores the corresponding empty tuple element.
Actual Question
I am very unhappy with the above API. So I decided to write a cleaner looking function template. No boolean switches and no dummy tuple elements in the return value:
auto [crc, sha256] = computeHashes<Hash::CRC32, Hash::MD5>(data_provider);
I got the code mostly working, except for the last step where I need to actually return the results. This is trimmed down from the real code, and with only two hash functions in order to keep the example as short as possible:
enum class Hash { CRC32, MD5 };
template <HashType> struct Hasher
{};
template<> struct Hasher<HashType::CRC32>
{
void addData(const char* data, int len);
uint32_t result() const;
};
template<> struct Hasher<HashType::MD5>
{
void addData(const char* data, int len);
QByteArray result() const;
};
template <HashType... hash_types>
auto computeHashes(DataProvider& provider)
{
std::tuple<Hasher<hash_types>...> hashers;
while (provider.hasMoreChunks()) {
auto [chunk, len] = provider.nextChunk();
std::apply([chunk, len](auto&... hasher)
{ (..., hasher.addData(chunk, len); },
hashers);
}
return std::make_tuple( ??? );
}
I'm stuck at the last step: how do I return each result? A hard-coded return would look this:
return std::make_tuple(res, std::get<0>(hashers).result(),
std::get<1>(hashers).result());
This isn't suitable of course. How do I do this?
since std::apply forwards returned values by decltype(auto) you can just construct a tuple with std::apply and return it.
This can be coalesced with your transformations into one call.
template <HashType... hash_types>
static auto computeHashes(DataProvider& provider)
{
return std::apply(
[&provider](auto&&... hashers) {
while (provider.hasMoreChunks())
{
auto [chunk, len] = provider.nextChunk();
(..., hashers.addData(chunk, len));
}
return std::make_tuple(std::move(hashers.result())...);
},
std::tuple<Hasher<hash_types>...>{}
);
}
I have a question about modifying elements in boost::multi_index container.
What I have is the structure, containing some pre-defined parameters and
a number of parameters, which are defined at run-time, and stored in a map.
Here is a simplified version of the structure:
class Sdata{
QMap<ParamName, Param> params; // parameters defined at run-time
public:
int num;
QString key;
// more pre-defined parameters
// methods to modify the map
// as an example - mock version of a function to add the parameter
// there are more functions operating on the QMAP<...>, which follow the same
// rule - return true if they operated successfully, false otherwise.
bool add_param(ParamName name, Param value){
if (params.contains(name)) return false;
params.insert(name, value);
return true;
}
};
Now, I want to iterate over different combinations of the pre-defined parameters
of Sdata. To do this, I went for boost::multi_index:
typedef multi_index_container<Sdata,
indexed_by <
// by insertion order
random_access<>,
//by key
hashed_unique<
tag<sdata_tags::byKey>,
const_mem_fun<Sdata, SdataKey, &Sdata::get_key>
>,
//by TS
ordered_non_unique<
tag<sdata_tags::byTS>,
const_mem_fun<Sdata, TS, &Sdata::get_ts>
>,
/// more keys and composite-keys
>//end indexed by
> SdataDB;
And now, I want to access and modify the parameters inside the QMap<...>.
Q1 Do I get it correctly that to modify any field (even those unrelated to
the index), one needs to use functors and do something as below?
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, Functor(...))
Q2 How to get the result of the method using the functor? I.e., I have a functor:
struct SdataRemoveParam : public std::unary_function<Sdata, void>{
ParamName name;
SdataRemoveParam(ParamName h): name(h){}
void operator ()(Sdata &sdata){
sdata.remove_param (name); // this returns false if there is no param
}
};
How to know if the remove_param returned true or false in this example:
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, SdataRemoveParam("myname"));
What I've arrived to so far is to throw an exception, so that the modify
method of boost::multi_index, when using with Rollback functor will return
false:
struct SdataRemoveParam : public std::unary_function<Sdata, void>{
ParamName name;
SdataRemoveParam(ParamName h): name(h){}
void operator ()(Sdata &sdata){
if (!sdata.remove_param (name)) throw std::exception("Remove failed");
}
};
// in some other place
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
bool res = l.modify(it, SdataRemoveParam("myname"), Rollback);
However, I do not like the decision, because it increases the risk of deleting
the entry from the container.
Q3 are there any better solutions?
Q1 Do I get it correctly that to modify any field (even those
unrelated to the index), one needs to use functors and do something as
below?
Short answer is yes, use modify for safety. If you're absolutely sure that the data you modify does not belong to any index, then you can get by with an ugly cast:
const_cast<Sdata&>(*it).remove_param("myname");
but this is strongly discouraged. With C++11 (which you seem to be using), you can use lambdas rather than cumbersome user-defined functors:
Sdatas_byKey &l = sdatas.get<sdata_tags::byKey>(); // note, this can't be const
auto it = l.find(key);
l.modify(it, [](Sdata& s){
s.remove_param("myname");
});
Q2 How to get the result of the method using the functor?
Again, with lambdas this is very simple:
bool res;
l.modify(it, [&](Sdata& s){
res=s.remove_param("myname");
});
With functors you can do the same but it requires more boilerplate (basically, have SdataRemoveParam store a pointer to res).
The following is just for fun: if you're using C++14 you can encapsulate the whole idiom very tersely like this (C++11 would be slightly harder):
template<typename Index,typename Iterator,typename F>
auto modify_inner_result(Index& i,Iterator it,F f)
{
decltype(f(std::declval<typename Index::value_type&>())) res;
i.modify(it,[&](auto& x){res=f(x);});
return res;
}
...
bool res=modify_inner_result(l,it, [&](Sdata& s){
return s.remove_param("myname");
});
How did Boost implement Tuple before C++11 and Variadic Templates?
In other words:
Is it possible to implement a Variadic Templates class or function by not using built-in Variadic Templates feature in C++11?
Boost had a limit for the size of the tuple. As in most real-world scenarios you don't need more than 10 elements, you won't mind this limitation. As a library maintainer, I guess, the world became much simpler with variadic templates. No more macro hacks...
Here is an insightful discussion about the size limit of Boost tuple and its implementation:
boost tuple: increasing maximum number of elements
To answer your second question: No, it is not possible. At least not for an unlimited number of elements.
There are 2 common use cases I've seen, as a library developer, for variadic templates. You can build a work around for both.
Case 1: Function objects
std::function<> and lambdas are very nice, but even c++11 only gives you a fairly basic set of things you can do with them "out of the box". To implement really cool things and utilities on top of them, you need to support variadic templates because std::function can be used with any normal function signature.
Workaround:
A recursive call using std::bind is your friend. It IS less efficient than real variadic templates (and some tricks like perfect forwarding probably won't work), but it'll work okay for modest #s of template arguments until you port to c++11.
Case 2: Ordinary classes
Sometimes you need an ordinary class to manage generic std::function<>s (see above) or expose an API like "printf". Workarounds here come down to details and what each API of the class is doing.
APIs that merely manipulate variadic template data but don't need to store it can run as recursive calls. You need to write them so that they "consume" one argument at a time, and stop when they run out of arguments.
APIs (including constructors) that need to STORE variadic template data are harder- you're screwed if the types are really unlimited and could be anything. BUT, if they're always going to be primitives that map deterministically to binary, you can do it. Just write a "Serialize" call taking all the types you support, then use it to serialize the entire set into a binary buffer and build a vector of "type info" data you use to fetch & set them. Its actually a better solution than std::tuple in terms of memory and performance in the special cases its available.
Here's the "serialize tuple" trick:
// MemoryBuffer: A basic byte buffer w/ its size
class MemoryBuffer {
private:
void* buffer;
int size;
int currentSeekPt;
protected:
void ResizeBuffer() {
int newSz = size << 1; // Multiply by 2
void* newBuf = calloc( newSz, 1); // Make sure it is zeroed
memcpy( newBuf, buffer, target->size);
free( buffer);
size = newSz;
buffer = newBuf;
}
public:
MemoryBuffer(int initSize)
: buffer(0), size(initSize), currentSeekPt(0)
{
buffer = calloc( size, 1);
}
~MemoryBuffer() {
if(buffer) {
free( buffer);
}
}
// Add data to buffer
bool AddData(const void* data, int dataSz) {
if(!data || !dataSz) return false;
if(dataSz + currentSeekPt > size) { // resize to hold data
ResizeBuffer();
}
memcpy( buffer, data, dataSz);
return true;
}
void* GetDataPtr() const { return buffer; }
int GetSeekOffset() const { return currentSeekPt; }
int GetTotalSize() const { return size; }
};
struct BinaryTypeInfo {
std::type_info type; // RTTI type_info struct. You can use an "enum"
// instead- code will be faster, but harder to maintain.
ui64 bufferOffset; // Lets me "jump" into the buffer to
}
// Versions of "Serialize" for all 'tuple' data types I support
template<typename BASIC>
bool Serialize(BASIC data, MemoryBuffer* target,
std::vector<BinaryTypeInfo>& types)
{
// Handle boneheads
if(!target) return false;
// Setup our type info structure
BinaryTypeInfo info;
info.type = typeid(data);
info.bufferOffset = target->GetSeekOffset();
int binarySz = sizeof(data);
void* binaryVersion = malloc( binarySz);
if(!binaryVersion) return false;
memcpy( binaryVersion, &data, binarySz); // Data type must support this
if(!target->AddData( binaryVersion, binarySz)) {
free( binaryVersion);
return false;
}
free( binaryVersion);
// Populate type vector
types.push_back( info);
return true;
}
This is just a quick & dirty version; you'd hide the real thing better and probably combine the pieces into 1 reusable class. Note that you need a special version of Serialize() if you wish to handle std::string and more complex types.