Insert order std::map - c++

I would create an associative array (like std:: map) that stores the elements in order of insertion. I wrote this class:
template <typename K, typename V>
class My_Map : public std::unordered_map<K,V>
{
public:
V& operator[]( const K&& key )
{
typename std::unordered_map<K,V>::iterator __i = find(key);
if (__i == std::unordered_map<K,V>::end()) //se non l'ho trovato...
{
__i = insert(__i, std::make_pair(std::move(key), V()) );
mHistory.push_back(__i);std::cout<<"Sto inserendo: "<<key<<std::endl;
}
return (*__i).second;
}
typename std::unordered_map<K,V>::iterator cbegin() const
{
return *mHistory.cbegin();
}
typename std::unordered_map<K,V>::iterator cend() const
{
return *mHistory.cend();
}
private:
std::list<typename std::unordered_map<K,V>::iterator> mHistory;
};
using namespace std;
int main()
{
My_Map<string,int> myMap;
myMap["1"] = 1;
myMap["23"] = 23;
myMap["-3"] = 3;
myMap["23"] = 28;
myMap["last element"] = 33;
for (auto x = myMap.cbegin(); x != myMap.cend(); ++x)//{std::cout<<"sn dentro\n";}
cout<<(*x).first <<"\t"<<x->second<<endl;
}
I used unordered_map instead std::map because std::map mix iterators when I insert new element.
This code have a problem: the for in main() fails with a segmentation fault. The iterators passed with cbegin() and cend() are not valid...why? What's wrong?

The first thing is that you can't dereference an end iterator of a list. Secondly, I also doubt if yourMap.cend will be necessarily reachable from yourMap.cbegin.
It looks like you might need an adaptor for the list iterator that automatically dereferences the stored map iterator pointer to map item.
In any case, you need to iterate over the list, not from a random point in the unordered_map to another random point therein.
Also: adding elements can cause rehashing, which will invalidate iterators (but not pointers or references to elements). You should not even store iterators into an unordered_map.

Related

C++ Filteration using lazy iterator

template<typename Iterator>
struct Range {
using LazyIterator = Iterator; // required for accessing the used Iterator type from other locations
Iterator m_begin;
Iterator m_end;
auto begin() { return m_begin; }
auto end() { return m_end; }
};
template<typename Iterator>
Range(Iterator, Iterator) -> Range<Iterator>;
template<typename Iterator, typename Callable>
struct FilteringIterator : Iterator {
Callable callable;
using OriginalIterator = Iterator;
using t = typename OriginalIterator::value_type;
FilteringIterator(const Iterator begin, Callable callable):Iterator(begin),callable(callable){}
Iterator &get_orig_iter() { return ((Iterator &)*this); }
auto operator*() { return callable(*get_orig_iter()); }
};
auto filter = [](auto action) {
return [=]( auto &container) {
using Container = std::decay_t<decltype(container)>;
using Iterator = typename Container::iterator;
using actiontype = decltype(action);
using filter_iterator = FilteringIterator<Iterator, actiontype>;
return Range{filter_iterator{container.begin(),action}, filter_iterator{container.end(),action}};
};
};
I need a lazy iterator that will traverse over a range and filter it lazily.
For example
auto v = std::vector<double>{};
auto odd_gen = views::odds();
for(int i=0; i<5; ++i)
v.push_back(odd_gen() * 2.5);
// v contains {2.5, 7.5, 12.5, 17.5, 22.5} here
new_line();
for(auto a : v | filter(greater_than(15))) // filter is applied lazily as the range is traversed
std::cout << a << std::endl;
// print { 17.5, 22.5} here
but it prints
{0,0,0,0,17.5,22.5}
I want it to only print 17.5, 22.5
how can I achieve that?
Your code never skips elements, it just transforms them. You need to make sure that when the operator*() is invoked, it starts by advancing the iterator while callable returns false, and only then return the value pointed to by the Iterator.
There are corner cases though you have to take care of. If the input ends with elements that don't match the filter, then you run into a problem. You also need to skip over all filtered out elements when operator++() is called. And also think about the case where the filter would not match any elements of the input; in that case you must ensure that begin() is equal to end().

Convert the end() iterator to a pointer

To get to the point: is the following safe ?
vector<int> v;
int const* last = &*v.end();
// last is never dereferenced
My concern is that the trick to get a plain old pointer from an iterator forces to dereference the end() iterator, which is not valid... even if it is just to take the pointer back!
Backgroud: I am trying to create a collection of entries indexed by arbitrary types (especially integers and pointer to objects).
template<class IT>
/// requires IT implements addition (e.g. int, random-access iterator)
class IndexingFamily {
public:
using IndexType = IT;
IndexingFamily(IndexType first, IndexType last);
int size() const;
IndexType operator[](int i) const;
private:
IndexType first;
IndexType last;
};
template<class IT> IndexingFamily<IT>::
IndexingFamily(IndexType first, IndexType last)
: first(first)
, last(last) {}
template<class IT> auto IndexingFamily<IT>::
size() const -> int {
return last-first;
}
template<class IT> auto IndexingFamily<IT>::
operator[](int i) const -> IndexType {
return first+i;
}
template<class IT, class ET>
struct IndexedEntry {
using IndexType = IT;
using EntryType = ET;
IndexType index;
EntryType entry;
};
template<class IT, class ET>
class CollectionOfEntries {
public:
using IndexType = IT;
using EntryType = ET;
/// useful methods
private:
IndexingFamilyType indexingFamily;
vector<EntryType> entries;
};
struct MyArbitraryType {};
int main() {
MyArbitraryType obj0, obj1, obj2;
vector<MyArbitraryType> v = {obj0,obj1,obj2};
using IndexType = MyArbitraryType const*;
IndexingFamily<IndexType> indexingFamily(&*v.begin(),&*v.end());
using EntryType = double;
using IndexedEntryType = IndexedEntry<IndexType,EntryType>;
IndexedEntry entry0 = {&obj0,42.};
IndexedEntry entry1 = {&obj1,43.};
vector<IndexedEntryType> entries = {entry0,entry1};
CollectionOfEntries coll = {indexingFamily,entries};
return 0;
}
Dereferencing an end() iterator gives undefined behaviour, with any standard container.
For a vector you can get a pointer corresponding to the end() iterator using
pointer_to_end = v.empty() ? 0 : (&(*v.begin()) + v.size());
or
pointer_to_end = v.data() + v.size(); // v.data() gives null is size is zero
The check of v.empty() is needed since, if v is empty, v.begin() == v.end(). For C++11 or later, use of nullptr instead of 0 in the above is often considered preferable.
The iterator returned by member function end() "points" after the last element of a vector. You may not dereference it. Otherwise the program will have undefined behavior.
You can get the corresponding pointer the following way
vector<int> v;
int const *last = v.data() + v.size();
If you want to use the iterator returned by the member function end() you can write
vector<int> v;
int const *last = v.data() + std::distance( v.begin(), v.end() );
Take into account that member function data() returns a raw pointer of the memory extent occupied by vector's data.

Finding elements in std::set

Given that I have a std::set, how do I find out if one element of the set is before the other. For example, something like this -
bool before(const std::set &s, const int first, const int second) const {
auto it_first = s.find(first);
auto it_second = s.find(second);
return it_first <= it_second;
}
The above code does not work since <= is not defined for the bidirectional iterators, but how would one go about doing something like this?
A set orders its elements by operator< (by default). The comparator itself can be retrieved via key_comp or value_comp. So if both elements are in the set, the order is defined by the elements themselves - you don't need the iterators:
return s.key_comp()(first, second);
If one or neither are in the set, then it depends on what you want to do in those cases:
if (s.count(first)) {
if (s.count(second)) {
return s.key_comp()(first, second);
}
else {
/* no second */
}
}
else {
/* no first, possibly second */
}
If you would look more generic solution than only for std::set this method would work for any container with forward iterator:
template <class T>
bool before( const T &cont, typename T::const_iterator first, typename T::const_iterator second )
{
for( auto it = cont.begin(); true; ++it ) {
if( it == first ) return true;
if( it == second ) return false;
}
}
assuming first and second are valid iterators. Now you can have more optimal specialization for std::set and std::map:
return cont.key_comp()( *first, *second );
and for container with random access iterator:
return first < second;

Is there a flat unsorted map/set implementation?

There is the boost.container flat_map and others, and the Loki AssocVector and many others like these which keep the elements sorted.
Is there a modern (c++11 move-enabled, etc.) implementation of an unsorted vector adapted as a map/set?
The idea is to use it for very small maps/sets (less than 20 elements) and with simple keys (for which hashing wouldn't always make sense)
Something like this?
template<class Key, class Value, template<class...>class Storage=std::vector>
struct flat_map {
struct kv {
Key k;
Value v;
template<class K, class V>
kv( K&& kin, V&& vin ):k(std::forward<K>(kin)), v(std::forward<V>(vin)){}
};
using storage_t = Storage<kv>;
storage_t storage;
// TODO: adl upgrade
using iterator=decltype(std::begin(std::declval<storage_t&>()));
using const_iterator=decltype(std::begin(std::declval<const storage_t&>()));
// boilerplate:
iterator begin() {
using std::begin;
return begin(storage);
}
const_iterator begin() const {
using std::begin;
return begin(storage);
}
const_iterator cbegin() const {
using std::begin;
return begin(storage);
}
iterator end() {
using std::end;
return end(storage);
}
const_iterator end() const {
using std::end;
return end(storage);
}
const_iterator cend() const {
using std::end;
return end(storage);
}
size_t size() const {
return storage.size();
}
bool empty() const {
return storage.empty();
}
// these only have to be valid if called:
void reserve(size_t n) {
storage.reserve(n);
}
size_t capacity() const {
return storage.capacity();
}
// map-like interface:
// TODO: SFINAE check for type of key
template<class K>
Value& operator[](K&& k){
auto it = find(k);
if (it != end()) return it->v;
storage.emplace_back( std::forward<K>(k), Value{} );
return storage.back().v;
}
private: // C++14, but you can just inject the lambda at point of use in 11:
template<class K>
auto key_match( K& k ) {
return [&k](kv const& kv){
return kv.k == k;
};
}
public:
template<class K>
iterator find(K&& k) {
return std::find_if( begin(), end(), key_match(k) );
}
template<class K>
const_iterator find(K&& k) const {
return const_cast<flat_map*>(this)->find(k);
}
// iterator-less query functions:
template<class K>
Value* get(K&& k) {
auto it = find(std::forward<K>(k));
if (it==end()) return nullptr;
return std::addressof(it->v);
}
template<class K>
Value const* get(K&& k) const {
return const_cast<flat_map*>(this)->get(std::forward<K>(k));
}
// key-based erase: (SFINAE should be is_comparible, but that doesn't exist)
template<class K, class=std::enable_if_t<std::is_converible<K, Key>{}>>
bool erase(K&& k) {
auto it = std::remove(
storage.begin(), storage.end(), key_match(std::forward<K>(k))
);
if (it == storage.end()) return false;
storage.erase( it, storage.end() );
return true;
}
// classic erase, for iterating:
iterator erase(const_iterator it) {
return storage.erase(it);
}
template<class K2, class V2,
class=std::enable_if_t<
std::is_convertible< K2, Key >{}&&
std::is_convertible< V2, Value >{}
>
>
void set( K2&& kin, V2&& vin ) {
auto it = find(kin);
if (it != end()){
it->second = std::forward<V2>(vin);
return;
} else {
storage.emplace_back( std::forward<K2>(kin), std::forward<V2>(vin) );
}
}
};
I left the container type as a template argument, so you can use a SBO vector-like structure if you choose.
In theory, I should expose a template parameter for replacing equals on the keys. I did, however, make the key-search functions transparent.
If the sets are sure to be small then you can just use a std::vector (or std::deque) and do lookup using linear searches. An O(n) linear search over a small vector can be faster than an O(log(n)) search over a more complicated structure such as a red-black tree.
So you could just put elements in a vector without sorting them. You would still need to do some shuffling if you remove elements, but that will always be true for a flat vector-like structure whether it's sorted or not, unless you only ever remove the back element. Why is it important that it's flat anyway?
There's std::unordered_set and std::unordered_map but as far as I know they are not implemented using vectors.
A possible option is to write your own hash vector and hash the key using std::hash<Key> and then index the resulting number modulo the length of the vector, but then you'll have to figure out a way to handle collisions and all the resulting problems manually. Not sure I recommended that.
An alternative would be to pass a custom allocator to std::unordered_set and std::unordered_map which perform the allocation on a vector (for example by owning an internal vector), as suggested by #BeyelerStudios.
Evgeny Panasyuk is correct, I believe what you want is an Open Address Hash Map.
This fits exactly your requirement, only 1 flat buffer, no allocation of nodes, no pointers to follow, and unsorted.
Otherwise you also have flat_map/AssocVectorbut they are sorted, unlike your requirement.
For OAHM, I have an implementation of a STL-like generic one here:
https://sourceforge.net/projects/cgenericopenaddresshashmap/
Also you might want to take a look the benchmark page of flat_map:
boost::flat_map and its performance compared to map and unordered_map
The OAHM is performing very close to the flat_map in all tests, except iteration.
Please look at the sfl library that I have recently updated to GitHub: https://github.com/slavenf/sfl-library
It is C++11 header-only library that offers flat ordered and unordered containers that store elements contiguously in memory. All containers meet requirements of Container, AllocatorAwareContainer and ContiguousContainer. Library is licensed under zlib license.

unique_copy elements value from map to vector

I have a map<K, V> and I want to use unique_copy to put the values into a vector<V>.
I tried this but it doesn't work:
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
using namespace placeholders;
int main() {
map<std::string, int> mp;
mp["1"] = 1;
mp["2"] = 2;
mp["3"] = 3;
mp["4"] = 3;
mp["5"] = 3;
mp["6"] = 4;
mp["7"] = 2;
vector<int> vec;
unique_copy( mp.begin(), mp.end(),
back_inserter(vec),
bind(&map<std::string, int>::value_type::second, _1) );
for( auto& i : vec )
cout<< i <<" ";
}
Expected output:
1 2 3 4 2
All google searches return ways to use transform but I need unique_copy. Is there any way to make this work?
There's no way to do this directly, because the value type of the map iterator and the vector iterator are not compatible. You really need a transform of some sort, or an iterator adaptor.
You could use boost::transform_iterator for this:
auto getValue = [](const std::map<std::string, int>::value_type &pair) { return pair.second; };
unique_copy(
boost::make_transform_iterator(mp.begin(), getValue),
boost::make_transform_iterator(mp.end(), getValue),
back_inserter(vec)
);
If you cannot use Boost, you'll have to write such an iterator adaptor yourself:
template <class T_PairIterator>
struct SecondIterator
{
typedef T_PairIterator PairIterator;
typedef typename std::iterator_traits<PairIterator>::iterator_category iterator_category;
typedef typename std::iterator_traits<PairIterator>::value_type::second_type value_type;
typedef typename std::iterator_traits<PairIterator>::difference_type difference_type;
typedef value_type *pointer;
typedef value_type &reference;
PairIterator it;
SecondIterator() {}
explicit SecondIterator(PairIterator it) : it(it) {}
pointer operator-> () const { return &it->second; }
reference operator* () const { return it->second; }
SecondIterator& operator++ () { ++it; return *this; }
SecondIterator operator++ (int) { SecondIterator ret(*this); ++it; return ret; }
};
template <class T>
bool operator== (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return lhs.it == rhs.it; }
template <class T>
bool operator!= (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return !(lhs == rhs); }
template <class T>
SecondIterator<T> makeSecondIterator(const T &it)
{ return SecondIterator<T>(it); }
You could then use it like this:
unique_copy(
makeSecondIterator(mp.begin()),
makeSecondIterator(mp.end()),
back_inserter(vec)
);
Of course, the adaptor could be made a bit more generic (perhaps usable for first as well), and/or more encapsulated (it needn't be public); it would also need proper handling for const-iterators. But the above should be enough to give you the idea.
std::copy followed by vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() ); will end up in the same place as unique_copy with a transform would. It may use extra memory in the middle (before removing redundant entries) but is pretty clean.
A manual copy is another option:
if(!src.empty()){
auto* prev = &src.begin()->second;
dest.push_back(*prev);
for(auto it = std::next(src.begin()); it != sec.end(); ++it){
if (it->second == *prev) continue;
prev=&it->second;
dest.push_back(*prev);
}
}
with the note thay prev is technically redundant (use dest.back() instead of *prev except when push_backing -- there use ->second).
As Vijay says in his comment, you could use a std::set instead of a vector (if you don't need the individual features of a vector, of course, like contiguous storage, custom ordering or random access). In this case the std::set::insert will already take care of removing duplicates and you can use std::transform in the way you tried:
std::set<int> set;
std::transform( mp.begin(), mp.end(), std::inserter(set),
bind(&std::map<std::string, int>::value_type::second, _1) );
As to your modified question
std::set won't insert the value if it is already in the set but I
don't want consecutive duplicates.
Well, in this case just do a normal copy (i.e. std::transform) into the vector and do a std::unique afterwards, which will just remove all consecutive duplicates:
std::transform( mp.begin(), mp.end(), std::inserter(vec),
bind(&std::map<std::string, int>::value_type::second, _1) );
vec.erase( std::unique(vec.begin(), vec.end()), vec.end() );