Using array as key in unordered_set - c++

I want to use an unordered_set having as key an unsigned long long*, but I want to implement the hash and the equal_to using the values stored. For instance:
int size = 4;
typedef unsigned long long verylong;
verylong* x = new verylong[size];
// calc hash and equal using x[0]..x[3]
The easy method is to use a wrapper.
class VeryLong {
verylong* array;
int arraySize;
...
bool operator==(const VeryLong& x) { // use the array and arraySize }
...
};
namespace std {
template <>
class hash<VeryLong>
{
std::size_t operator()(const VeryLong& v) const
{
// Compute hash values for array (using murmur, maybe)
//...
}
};
But I don't want to use a wrapper due to memory consumption. I want something like:
std::unordered_set<verylong*,MyHash,MyEqual> set;
The problem is to implement MyHash and MyEqual, because the arraySize is not constant (I only know arraySize in execution time).
I tried this:
typedef struct MyHash
{
int arraySize;
MyHash(int size) : arraySize(arraySize) {}
long operator() (const verylong* const k) const { return hash(k,size); }
} MyHash;
But I cannot use this, because MyHash is not constexpr.
Is what I want possible to do?
EDIT: If I try using the MyHash implemented above:
int size;
// someone sets size a positive value
std::unordered_set<verylong*,MyHash(size),MyEqual> set;
The following error occurs:
error: temporary of non-literal type 'MyHash' in a constant expression std::unordered_set< verylong*, MyHash(size), MyEquals> set;

The second template argument to std::unordered_set<> should be MyHash rather than MyHash(size), as a type is expected here rather than an object. Change your set declaration to:
std::unordered_set<verylong*, MyHash, MyEqual> set(bucket_count, MyHash(size));
Presumably MyEqual will need a similar argument for size, in which case do:
std::unordered_set<verylong*, MyHash, MyEqual> set(bucket_count, MyHash(size), MyEqual(size));
For bucket_count, use a guesstimate of how many elements will be in your set.
As a side note, don't typedef your structs that way – that's a hideous C-ism that serves no purpose in C++.

Related

How do you assign array values to class member array in constructor, without using the std library?

Trying to understand the proper way to copy values into an class member array. Currently, I take each value of the array and copy them into the corresponding element of the member array:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values[0], values[1], values[2], values[3]}
{
}
const unsigned char values[4];
};
int main(int argc, char** argv)
{
unsigned char values[] = {10, 0, 0, 1};
IPAddress address(values);
return 0;
}
This works, but is there a way to "automagically" copy all the values in the constructor? I mean, what would I do if the values were of a class had 100 elements instead of 4? Or 1000?
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
Any takers?
You should be using std::array. This is one part of the standard library that shouldn't be offensive to embedded programming.
If you don't have access to it, it's not hard to implement a class just like it. It's a straight forward aggregate with saner semantics than raw arrays. It's also likely to be reused, which makes it a good candidate for a utility you should implement.
Failing that, you can rely on delegating c'tors, which I only add here for the intellectual exercise:
struct IPAddress
{
IPAddress(const unsigned char values[4])
: IPAddress(values, std::make_index_sequence<4>{})
{
}
const unsigned char values[4];
private:
template<std::size_t... I>
IPAddress(const unsigned char values[4], std::index_sequence<I...>)
: values{values[I]...}
{
}
};
The key is in the pack expansion values{values[I]...}, which turns into an initializer not unlike your original one. See it live.
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
If you don't want to include array, you can still implement your own type for solving your issue:
template<typename T, std::size_t N>
class values_t {
public:
values_t(const T *ptr) {
// copy N elements
for (std::size_t i = 0; i < N; ++i)
value[i] = ptr[i]; // copy element
}
T& operator[](int i) { return value[i]; }
const T& operator[](int i) const { return value[i]; }
private:
typename std::remove_const<T>::type value[N];
};
Then, initializing the values data member of IPAddress becomes much simpler:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values} {} // <-- copy as a whole
values_t<const unsigned char, 4> values;
};

Initialise a std::vector with data from an array of unions

How might I initialise a std::vector from an array of structs, where the struct contains a union of different types. In other words, the array is used to store a number of values of a specific type, which can be int, char* etc.
This is my solution so far but I'm looking for a better approach:
The convert function returns a vector<int> if it stores ints or a vector<std::string> if it stores char*.
The Value type below is a struct containing a union called value. The Container class below points to a buffer of such Values.
// union member getter
class Getter
{
public:
void operator()(int8_t& i, const Value& value)
{
i = value.value.i;
}
void operator()(std::string& s, const Value& value)
{
s = std::string(value.value.s);
}
...
};
template<class T>
std::vector<T> convert(Container* container)
{
std::vector<T> c;
c.reserve(container->nrOfValues);
Getter g;
for(int i=0;i<container->nrOfValues;i++)
{
T value;
g(value, container->values[i]);
c.push_back(value);
}
return c;
}
Your problem is the union gives a different name to each value, which causes the need for a function that converts a name to a type, such as Getter::operator() returning a type and getting a named member of the union.
There isn't much you can do with this. You can save a variable declaration and a copy/string constructor on each item, but that's about it.
If you can't modify the original struct, you could initialize the vector with a length set of default value (which must be passed in), then iterate through using the getter as:
vector<T> v(length, defaultValue);
typename vector<T>::iterator iter = vec.begin();
for(int index = 0; *iter != vec.end() && index < length; ++iter, ++index) {
converter(*iter, array[index]);
}
Notice that this starts getting cumbersome in iterating the index and the iterator and verifying both are still valid in case of an accident...
If you can modify the original struct:
class Ugly { // or struct, it doesn't matter
public:
union {
char* s;
int i;
} value;
Ugly(char* s) {
value.s = s;
}
Ugly (const int& i) {
value.i = i;
}
operator std::string() const {
return std::string(value.s);
}
operator int() const {
return value.i;
}
};
Then your for loop becomes:
for(int i=0;i<container->nrOfValues;i++)
{
c.push_back(container->values[i]);
}
Note: You might create the vector and pass it as an argument to the copy function since it involves copying the data over during the return.
If you like some template magic, you could do it slightly different way:
// Source union to get data from
union U
{
int i;
char* s;
double d;
};
// Conversion type template function (declared only)
template <class T> T convert(const U& i_u);
// Macro for template specializations definition
#define FIELD_CONV(SrcType, DestField)\
template <> SrcType convert(const U& i_u)\
{ auto p = &DestField; return i_u.*p; }
// Defining conversions: source type -> union field to get data from
FIELD_CONV(int, U::i)
FIELD_CONV(std::string, U::s)
FIELD_CONV(double, U::d)
// Get rid of macro that not needed any more - just for macro haters ;-)
#undef FIELD_CONV
// Usage
template<class T> std::vector<T> convert(Container* container)
{
std::vector<T> c;
c.reserve(container->nrOfValues);
for(int i = 0; i < container->nrOfValues; ++i)
c.push_back(convert<T>(container->values[i]));
return c;
}
The advantage of this approach - it is short, simple and easy to extend. When you add new field to union you just write another FIELD_CONV() definition.
Compiled example is here.

custom hash function for pair of enum values used as unordered_map key

I'm trying to use a std::pair of enum values as key for an unordered_map container, but I have difficulties in defining a custom hash function.
I tried the following:
// Enum and pair declaration
enum ShapeType{ PLANE, BOX, SPHERE };
typedef std::pair<ShapeType, ShapeType> ShapePair;
// unordered_map declaration
typedef void(*CollisionMethod)(const Shape*, const Shape*, CollisionData*);
typedef std::unordered_map<ShapePair, CollisionMethod, ShapePairHash> CollisionMethodsTable;
I don't understand how define correctly ShapePairHash functor. I tried the following:
struct ShapePairHash
{
std::size_t operator()(const ShapePair &pair)
{
return std::hash<std::size_t>()(pair.first) ^ std::hash<std::size_t>()(pair.second);
}
};
but I get error C3840 (expression having type 'type' would lose some const-volatile qualifiers in order to call 'function')on VS compiler.
Can anyone suggest me the right way to declare a custom hash function to be used with unordered_map?
You can define a last enum value, and then use it to generate the hash (actually a perfect hash). Note that this assume that the number of possible enum values is low enough so that (suppose that the number of enum values is N): N * N + N < MAX_UINT
enum class ShapeType : unsigned int { PLANE = 0, BOX = 1, SPHERE = 2, LAST = 3 };
struct ShapePairHash
{
std::size_t operator()(const ShapePair &pair) const
{
return static_cast<std::size_t>(pair.first)
* static_cast<std::size_t>(ShapeType::LAST)
+ static_cast<std::size_t>(pair.second)
}
};
Also, for your compilation problem you just need to declare the function const.
Your operator() method should be const:
std::size_t operator()(const ShapePair &pair) const

How to deduce array size from an enum template argument?

How should I change the code below so that Array<Index> array; is enough and the SIZE is automatically deduced from the enum?
Even if the enum changes, it is guaranteed that it contains SIZE referring to the correct size.
template <typename Enum, int N>
class Array {
public:
int& operator[](Enum index) { return array[index]; }
private:
int array[N];
};
enum Index { X, Y, SIZE };
int main() {
Array<Index, SIZE> array;
array[X] = 1;
return 0;
}
UPDATE: As for "Array<type> means you're creating an array of Type objects" (Jerry) and "the name of class template is a bit misleading" (Nawaz): actually I am creating CustomSqlQueryModel<TableColumns>. The above is just a simplified code, nothing more. Jerry and Nawaz are rigth: this simplified code is unfortunate.
You can write a traits class. This requires a bit of extra work each time you define a new enum type, but no extra work for each occurrence of Array<Index> in user code:
template<class Enum>
struct ArrayTraits;
template<class Enum>
struct Array {
int& operator[](Enum index) { return array[index]; }
private:
int array[ArrayTraits<Enum>::size];
};
enum Index { X, Y, SIZE };
template<>
struct ArrayTraits<Index> {
enum { size = SIZE };
};
int main() {
Array<Index> array;
array[X] = 1;
return 0;
}
One of the advantages of this is you can specialize the traits for external enums you don't control, as long as you know how to get the max size.
As stated, I don't think you can. If, however, you change it to something like:
struct Index {
enum { X, Y, SIZE};
};
Then your template could be something like:
template <class Enum>
class Array {
// ...
private:
int array[Enum::SIZE];
};
...and if the type you pass as Enum doesn't include some positive constant named SIZE,the instantiation won't compile. For the purpose at hand, you'd really kind of prefer that Index was a namespace, but since a namespace isn't a type, I don't think you can use it as a template argument.
I should add, however, that I'm not sure I like this idea at all -- most people are going to think Array<type> means you're creating an array of Type objects, and this is clearly something entirely different from that...
If you want only the size to be template argument, not the type , as from your example it seems that the type of the array would be always int, then why don't you implement this:
template <int size>
class Array {
public:
int& operator[](int index) { return array[index]; }
//Note this addition!
int operator[](int index) const { return array[index]; }
private:
int array[size];
};
int main() {
Array<10> array;
array[0] = 1;
array[1] = 2;
return 0;
}
Note this addition: it's better if you implement const version of operator[] too, so that const Array<> can use it to access the array elements, otherwise your class wouldn't work for const Array<>.

Dynamic hash->class tag

I have:
const unsigned int hash_1 = 0xaf019b0c;
const unsigned int hash_2 = 0xf864e55c;
const unsigned int hash_3 = 0xfaea8ed5;
Hashes come from an automatically generated header. These hashes are indirectly associated with tags 1, 2, 3. The tags are associated with classes through a simple compile-time generated id. That way I can GetTag<Class1>() and get my int-tag for Class1.
My goal is to simplify the hash->tag association. Preferably this should be compile-time generated and O(1) access time. Memory in this case is not an issue. I can not use any third-party software.
I have tried the following:
template<uint32 t> size_t GetTagByHash() { return 0; }
with specific implementations like:
template<> size_t GetTagByHash<hash_1>() { return GetTag<Class1>(); }
but that kind of implementation is difficult to use since if I have a local variable uint32 my_hash; that the compiler can't determine what value it has in compile-time then the compiler is unable to resolve the correct implementation of GetTagByHash() to call.
As I understand it, your problem is how to do this lookup with run-time values as well as compile-time ones.
You've really got two questions. First, what algorithm do you want to use to do the lookup, and second, how do you tell C++ to implement that?
The algorithm to use is somewhat of a non-obvious question; you've got a list of effectively-random numbers, and you want to look up something in that list and return an associated tag. Probably you want some sort of hashtable, but to start with, I'll show some examples with something simpler -- and likely better for small numbers of hashes: A simple O(N) lookup, in pseudocode:
if i = N return tag_N
else if i = N-1 ...
...
else if i = 1 return tag_1
else return tag_0
Now, how do you tell C++ to do this? You've got to create a list of all your hash tags, and instructions for doing that. Here's a simple way:
template<int i> struct lookup
{
int result(int j) { return 0; }
};
const unsigned int hash_1 = 0xaf019b0c;
template<> struct lookup<1>
{
int result(int j)
{
if (j == hash_1)
return GetTag<Class1>();
return lookup<0>::result(j);
}
};
const unsigned int hash_2 = 0xf864e55c;
template<> struct lookup<2>
{
int result(int j)
{
if (j == hash_2)
return GetTag<Class2>();
return lookup<1>::result(j);
}
};
And so forth. Then, at the end, you can have
int hash_lookup(int j)
{
return lookup<last_hash_number>::result(j);
}
Writing out all those identical definitions is a pain, though, so it's best to let C++ do that -- and, to do that, you need to define the hashes in such a way that they can be iterated over. Let's do that:
template<int> struct hash_tag {
static const int value = 0;
typedef type void;
};
#define SET_HASH(I, VALUE, CLASS) \
template<> struct hash_tag<(I)> \
{ \
static const int value = (VALUE); \
typedef type (CLASS); \
}
SET_HASH(1, 0xaf019b0c, Class1);
SET_HASH(2, 0xf864e55c, Class2);
SET_HASH(3, 0xfaea8ed5, Class3);
// Define a general recursive lookup struct.
template<int i> struct lookup
{
int result(int j)
{
if (j == hash_tag<i>::value)
return GetTag<hash_tag<i>::type>;
return lookup<i-1>::result(j);
}
};
// Make sure the recursion terminates.
template<> struct lookup<0>
{
int result(int) { return 0; }
};
Then, you use this as before.
Now, let's return to that first question -- what algorithm do you actually want to use to do the lookup? The advantage of this iterative O(N) lookup is that it's easy to program, and it doesn't require any initialization of any data structures at run-time -- you can just call it. However, as noted, it's O(N). An alternate choice is to use a std::map object; you can use a similar recursive definition to initialize it at runtime, and then use it. That might look something like this:
// Make a typedef to save some typing.
typedef std::map<unsigned int, size_t> Map_type;
typedef std::pair<unsigned int, size_t> Map_value;
// Define a recursion to add hashes to the map.
template<int i> struct add_hash
{
void add(Map_type& hashmap)
{
hashmap.insert(
Map_value(hash_tag<i>::value,
GetTag<hash_tag<i>::type>));
add_hash<i-1>::add(hashmap);
}
};
// Make sure the recursion terminates.
template<> struct lookup<0>
{
void add(Map_type&) {}
};
// Now, create a class to initialize the std::map and do lookup.
class Hash_lookup
{
Hash_lookup() { add_hash<last_hash_number>(map_); }
int result(unsigned int j) { return map_[j]; }
private:
Map_type map_;
}
Personally, I would probably combine this with your GetTagByHash<> idea, and give the Hash_loop a "runtime-computed result" function as I described, as well as a "compile-time-computed result" function that takes a template argument rather than a function argument. But, in general, that's the basic idea for doing runtime lookup -- you put the values you want to look up into a set of templated classes that you can recursively iterate over at compile time, and then you use that recursive iteration to either define a lookup function or initialize a runtime structure that you can use for doing the lookup.