Common algorithm for maps with different comparison functions - c++

I have a common algorithm for 2 maps that uses find() and operator[] to access the map. However, elsewhere in the code I need to iterate over these maps and one of them needs to be sorted with a reverse comparison from the other. I ended up using the reverse iterator for that map, but profiling shows me that a huge amount of time is wasted on dereferencing the reverse iterator. I tried to do the following, but it obviously didn't work:
struct Custom
{
list<double> Doubles;
int Integer = 0;
};
typedef map<double, Custom> CustomMap;
typedef map<double, Custom, std::greater<double>> CustomMapGreater;
CustomMap A;
CustomMapGreater B;
...
void Algorithm(bool aChosen)
{
CustomMap* chosenMap;
if (aChosen)
{
chosenMap = &A;
}
else
{
chosenMap = &B; // Conversion not possible
}
// Algorithm that uses chosenMap follows
...
}
Any ideas on how I can get this to work? I have a feeling something can be done with templates, but I'm not very proficient with generic programming.

The template way look like:
template <typename Map>
void Algorithm(Map& map)
{
// ...
}
or, in your specific case, even
template <typename Comp>
void Algorithm(std::map<double, Custom, Comp>& map)
{
// ...
}
and then
void AlgorithmChooser(bool aChosen)
{
if (aChosen) {
Algorithm(A);
} else {
Algorithm(B);
}
}

You can use the same type for both maps:
typedef map<double, Custom, std::binary_function<const Custom &, const Custom &,bool>> CustomMap;
CustomMap lessMap( std::less<Custom>() );
CustomMap greaterMap( std::greater<Custom>() );
then you can pass them as the same type to a function or assign them to a pointer to CustomMap. Or for C++11 and later:
typedef map<double, Custom, std::function<bool( const Custom &, const Custom &)>> CustomMap;

Related

std::set. Custom set of sets

Word.
I have a struct, containing a single field that I would like set to use for comparison and equivalence, and other fields as metadata:
struct read_tag{
unsigned int read_id; // want std::set to use this
int offset; // metadata
bool orientation; // metadata
};
I have a functor to do the job:
struct read_tag_compare {
bool operator() (const read_tag &a, const read_tag &b) const {
return a.read_id > b.read_id
}
};
and decl. the required set as
std::set<read_tag, read_tag_compare> block;
Everything so far compiles. The problem is below:
How do I make a set containing std::set<read_tag, read_tag_compare>. I want something like this:
std::set< std::set<read_tag, read_tag_compare> > blocks;
blocks.insert(a_block); // comp error
But this gives me a very large, and hard to decipher error.
I thought it would recursively check how the inner sets are compared and extend this to the outer sets. All one had to do is define the comparator for the inner most set.
For example
std::set<std:set<unsigned int>> set_o_sets;
works fine, without me having to define how to compare std::set<unsigned int>
Any help is mucho appreciated :D
The <-comparison on std::set uses std::lexicographical_compare without comparator, i.e. it just forwards to < on the element type. (This is a limitation of the standard library, since this is defined for all containers, not just the ordered-associative ones.) So what you need is a custom comparator for sets of sets that uses the correct overload of lexicographical comparison:
using read_tag_set = std::set<read_tag, read_tag_compare>;
struct read_tag_set_compare {
bool operator()(const read_tag_set &a, const read_tag_set &b) const noexcept {
return std::lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end(), a.key_comp());
// ^^^^^^^^^^^^
}
};
Now use: std::set<read_tag_set, read_tag_set_compare>
The code shows why there isn't an obvious "fix" to the ordered associative containers that would make this "just work": If the containers use custom, stateful predicates, then it's not in general guaranteed that the members of two distinct containers can actually be compared with one another at all. All you know is that the elements within one container are comparable with that container's comparator. So when you're using a custom comparator, you better also say explicitly how two distinct containers relate, and you assert explicitly that it makes sense to compare two containers.
It compiled with no error with my g++-5.3.1 ubuntu..
#include<set>
#include<iostream>
using namespace std;
struct read_tag{
unsigned int read_id; // want std::set to use this
int offset; // metadata
bool orientation; // metadata
};
struct read_tag_compare {
bool operator() (const read_tag &a, const read_tag &b) const {
return a.read_id > b.read_id;
}
};
struct read_compare {
bool operator() (const set<read_tag, read_tag_compare> &a, const set<read_tag, read_tag_compare> &b) const {
return true;
}
};
int main()
{
set<read_tag, read_tag_compare> block;
set<set<read_tag, read_tag_compare>, read_compare> blocks;
blocks.insert(block)
}
Above was what I compiled.

two way associative container

I am looking for a data type (or at least a correct name for it) or a map like data structure that allows fast look ups in both directions.
something like:
class DoubleMap{
int getA(int b){
return b2a[b];
}
int getB(int a){
return a2b[a];
}
void insert(int a, int b){
a2b[a] = b;
b2a[b] = a;
}
std::map<int, int> a2b;
std::map<int, int> b2a;
};
of course templated and more sophisticated.
Is there a name for it and some std container or something from Qt or boost?
I suggest using a boost::bimap this is designed for lookups by the key or value.
So in your case you can just do:
#include <boost/bimap.hpp>
typedef boost::bimap< int, int > bm_type;
bm_type doubleMap;
then to perform lookup by key:
doubleMap.left.find(key)
lookup by value:
doubleMap.right.find(val)

Using Both Map and List for Same Objects

I'm trying to use both a list and an unordered_map to store the same set of objects. I'm new to C++, so still getting comfortable with iterators.
Say I have the following test code:
class Test {
public:
int x;
int y;
int z;
Test (int, int, int);
}
Test t1 = Test(1,2,3);
Test t2 = Test(2,4,6);
Test t3 = Test(3,6,9);
std::list<Test> list;
std::unordered_map<int, Test> map;
list.push_back(t3);
list.push_back(t2);
list.push_back(t1);
map[101] = t1;
map[102] = t2;
map[103] = t3;
Is it possible to look up an object by key, and then generate a list iterator from the reference of the object (or from the unordered_map generator?)
So if I have the key 102, I could look up t2 in constant time. I then want to iterate forward/backward/insert/delete relative to t2's position in the list.
I can use find to get a unordered_map iterator pointing to t2. I don't know how to generate a list iterator that starts at t2 (I can only generate iterators at the beginning or the end of the list, and iterate through.)
Would appreciate anyone pointing me to good tutorials on the STL and iterators.
Thanks!
Afterthought:
Is this an acceptable approach? I have many objects and need to efficiently look them up by integer key. I also need to preserve their order (unrelated to these integer keys) and insert/delete/traverse efficiently.
If what you want to do is this:
Is it possible to look up an object by key, and then generate a list iterator from the reference of the object (or from the unordered_map generator?)
Then you can take advantage of the fact that list iterators aren't invalidated on insertion or erase (unless you erase that particular iterator) and reorganize your structures like this:
std::list<Test> list;
std::unordered_map<int, std::list<Test>::iterator> map;
map.insert(std::make_pair(101,
list.insert(list.end(), t1)));
map.insert(std::make_pair(102,
list.insert(list.end(), t2)));
map.insert(std::make_pair(103,
list.insert(list.end(), t3)));
That way your map lookup gives you exactly what you want: a list iterator.
While Barry's approach is good, there is another one, more advanced and complicated. You can put your data object, (integer) key, and all bookkeeping bits in a single chunk of memory. Thus data locality will be improved and pressure on memory allocator will be less. Example, using boost::intrusive:
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/unordered_set.hpp>
#include <array>
using namespace boost::intrusive;
class Foo {
// bookkeeping bits
list_member_hook<> list_hook;
unordered_set_member_hook<> set_hook;
const int key;
// some payload...
public:
// there is even more options to configure container types
using list_type = list<Foo, member_hook<Foo, list_member_hook<>, &Foo::list_hook>>;
using set_type = unordered_set<Foo, member_hook<Foo, unordered_set_member_hook<>, &Foo::set_hook>>;
Foo(int key): key(key) {};
bool operator ==(const Foo &rhs) const {
return key == rhs.key;
}
friend std::size_t hash_value(const Foo &foo) {
return std::hash<int>()(foo.key);
}
};
class Bar {
Foo::list_type list;
std::array<Foo::set_type::bucket_type, 17> buckets;
Foo::set_type set{Foo::set_type::bucket_traits(buckets.data(), buckets.size())};
public:
template<typename... Args>
Foo &emplace(Args&&... args) {
auto foo = new Foo(std::forward<Args>(args)...);
// no more allocations
list.push_front(*foo);
set.insert(*foo);
return *foo;
}
void pop(const Foo &foo) {
set.erase(foo);
list.erase(list.iterator_to(foo));
// Lifetime management fun...
delete &foo;
}
};
int main() {
Bar bar;
auto &foo = bar.emplace(42);
bar.pop(foo);
}
Measure how good are both algorithms on your data. My idea may give you nothing but greater code complexity.

STL like iterator over a collection of hash maps

I'm looking for a way to create a forward iterator which allows to iterate over a collection of hash maps.
An exemplary class which holds several maps looks like follows. (I'm using boost for unordered_map and shared_ptr, but C++11 would provide those classes as well).
In my particular application I'm using this construct to represent sparse hierarchical 2D grid locations; i.e. KeyT is a 2D location, ValueT is an integral counter and the different levels represent different resolutions of the grid.
template <typename KeyT, typename ValueT>
class MapCollection
{
public:
// type-definitions for the map and a shared pointer to the map
typedef boost::unordered_map<KeyT, ValueT> Map;
typedef boost::shared_ptr<Map> MapPtr;
// Constructor for class
MapCollection (int num_levels)
{
levels_.reserve (num_levels);
for (int i = 0; i < num_levels; ++i)
levels_.push_back (MapPtr (new Map()));
}
// adds a key-value pair to the map on the given level
void addValue (const KeyT &key, const ValueT &value)
{
int level = getLevelForKey (key);
(*levels_[level])[key] = value;
}
// TODO define const_iterator for this class
// TODO define member function begin(), returning levels_.front()->begin()
// TODO define member function end(), returning levels_.back()->end()
private:
// return the hierarchy level for the given key
int getLevelForKey (const KeyT &key) { return /* ... */ };
// collection of maps
std::vector<MapPtr> levels_;
};
Within an application I would now like to be able to iterate over all entries of all maps, similarly to what is possible if one just iterates over a single map, i.e.
int main (int argc, char *argv[])
{
int num_levels = 5;
MapCollection maps (num_levels);
// fill maps
maps.addValue ( /* ... */ )
// iterator over all entries
MapCollection::const_iterator iter = maps.begin();
for (; iter != maps.end(); ++iter)
{
std::cout << "Key: " << iter->first << " | Value: " << iter->second << std::endl;
}
return EXIT_SUCCESS;
}
Obviously it would be possible to iterator over the different levels and for each level over it's map, but I would like to hide the creation of different levels for the user.
What is the correct way to define an (const_)iterator for the class MapCollection?
Thanks for your help!
You could use boost iterator facade, that will help you with the task of implementing custom iterators. The idea would be:
1-maintain a reference to the vector containing the maps (levels_).
2-a iterator indicating what element of the previous vector the custom iterator is iterating (of type std::vector<MapPtr>::iterator or std::vector<MapPtr>::const_iterator) or a index with the same info (to retrieve the end of level_[index]).
3-a iterator with current element of the iteration of the previous iterator (the actual element of the iteration).
Some sample code:
#include <boost/iterator/iterator_facade.hpp>
namespace impl
{
template <class Value>
class iterator
: public boost::iterator_facade<
config_iterator<Value>
, Value
, boost::forward_traversal_tag
>
{
public:
config_iterator() {...}
explicit config_iterator(parameters) { /*your specific contructor*/ }
private:
template <class OtherValue>
config_iterator(config_iterator<OtherValue> const& other);
friend class boost::iterator_core_access;
template <class> friend class config_iterator;
template <class OtherValue>
bool equal(config_iterator<OtherValue> const& other) const { } // Verify is two iterators are equals (used to verify if it == end)
void increment() {} // Logic for incrementing the iterator
Value& dereference() const {} // Returning the actual value
// members
};
}
typedef impl::iterator<type> iterator;
This is a template file for very simple iterator (forward), read the Iterator Help for more info, the same can be implementing overloading the right operators (++ post a pre increment, *, ->, etc...), by boost provide a ways of defining the minimum necessary to implement the rest.

C++ Hash function for string in unordered_map

It seems as if C++ does not have a hash function for strings in the standard library. Is this true?
What is a working example of using a string as a key in an unordered_map that will work with any c++ compiler?
C++ STL provides template specializations of std::hash for the various string classes. You could just specify std::string as key type for std::unordered_map:
#include <string>
#include <unordered_map>
int main()
{
std::unordered_map<std::string, int> map;
map["string"] = 10;
return 0;
}
I ran into this today (actually with wstring, not string, but it's the same deal): using wstring as a key in an unordered_map generates an error about no hash function being available for that type.
The solution for me was to add:
#include <string>
Believe it or not, without the #include directive I still had the wstring type available but apparently NOT the ancillary functions like the hash. Simply adding the include above fixed it.
Actually, there is std::hash<std::string>
But there it is how you can use another hash function:
struct StringHasher {
size_t operator()(const std::string& t) const {
//calculate hash here.
}
}
unordered_map<std::string, ValueType, StringHasher>
If you have a CustomType and you want to plug into the STL infrastructure this is what you could do.
namespace std
{
//namespace tr1
//{
// Specializations for unordered containers
template <>
struct hash<CustomType> : public unary_function<CustomType, size_t>
{
size_t operator()(const CustomType& value) const
{
return 0;
}
};
//} // namespace tr1
template <>
struct equal_to<CustomType> : public unary_function<CustomType, bool>
{
bool operator()(const CustomType& x, const CustomType& y) const
{
return false;
}
};
} // namespace std
If you then want to create say a std::unordered_map<CustomType> the STL will find the hash and equal_to functions without you having to do anything more with the template. This is how I like to write my custom equality comparer that support unordered data structures.
In my case it was really distraction.
I had a type X for which I implemented hashing for const& X an utilized it somewhere with
std::unordered_map<const X, int> m_map;
Then I wanted to have another map which key are of the type X and did:
std::unordered_map<X, int> map_x;
Notice the LACK of const on the second case.