std::pair and copy-assigning it in a map implementation - c++

Let me start by giving you a basic associative-array implementation.
#include <utility>
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>
namespace chops {
template <typename Key, typename Value,
typename Compare = std::less<Key>>
struct map {
using value_type = std::pair<const Key, Value>;
using key_type = Key;
using mapped_type = Value;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using key_compare = Compare;
using reference = value_type&;
using const_reference = value_type const&;
using iterator = typename std::vector<value_type>::iterator;
using const_iterator = typename std::vector<value_type>::const_iterator;
iterator begin() {
return data.begin();
}
iterator end() {
return data.end();
}
const_iterator begin() const {
return data.begin();
}
const_iterator end() const {
return data.end();
}
const_iterator cbegin() const {
return data.cbegin();
}
const_iterator cend() const {
return data.cend();
}
size_type size() {
return data.size();
}
bool empty() {
return data.empty();
}
void clear() {
data.clear();
}
mapped_type& operator[](Key const& k) {
key_comp kc{k};
iterator it = std::find_if(begin(), end(), kc);
if(it == end()) {
auto n = std::make_pair(k, mapped_type{});
data.push_back(n);
return data.back().second;
} else
return (*it).second;
}
template< class... Args >
std::pair<iterator,bool> emplace(Args&&... args) {
value_type v{std::forward<Args>(args)...};
key_comp kc{v.first};
iterator it = std::find_if(begin(), end(), kc);
if(it == end()) {
data.push_back(v);
return std::make_pair(data.end()--, true);
} else
return std::make_pair(it, false);
}
void erase(iterator pos){
data.erase(pos);
}
private:
struct key_comp {
Key k;
bool operator()(value_type const& p1) {
return p1.first == k;
}
};
std::vector<value_type> data;
};
}
int main() {
chops::map<int, std::string> m1;
m1[1] = "Burak";
m1.emplace(2, "Kaan");
m1.emplace(3, "Copur");
for (auto& kv : m1)
std::cout << kv.first << " has value " << kv.second << std::endl;
m1.erase(m1.begin());
for (auto& kv : m1)
std::cout << kv.first << " has value " << kv.second << std::endl;
}
First, the code uses vector to store key-value pairs. This makes implementation easy but operations are not O(log(n)) like balanced-tree implementations or O(1) like hashing-based implementations. In fact, this is a container of containers in a sense and the outer container may be parametrized in an implementation. Anyways, my problem is about that erase function, which I just delegate to erase function of underlying vector. Compiler tells me that copy constructor is removed from the pair type, since it has a user-defined move. Erase tries to copy the parts after the erase place I guess, and tries to use copy-constructor there.
The thing is, I devised a minimal example as follows:
#include <vector>
#include <string>
#include <utility>
int main() {
auto p1 = std::make_pair(1, "Burak");
auto p2 = std::make_pair(2, "Kaan");
std::vector<std::pair<int, std::string>> v1;
v1.push_back(p1);
v1.push_back(p2);
v1.erase(v1.begin());
}
where I can easily erase from vectors. So, what might be not working in my erase implementation?

Related

map proxy-iterator conflicts C++20 iterator concepts

I'm trying to write a wrapper class that interprets a std::vector<T> as a mapping of integers to Ts. As I want it to behave like a map, its iterators should dereference to (key, value) pairs. Since there are no such pairs in memory, the reference type of my corresponding iterator class is a bit unconventional:
using value_type = std::pair<Key, Value>;
using reference = std::pair<Key, Value&>;
For the corresponding const_iterator, this becomes
using value_type = std::pair<Key, const Value>;
using reference = std::pair<Key, const Value&>;
Now, however, my const_iterator no longer satisfies std::indirectly_readable (and, thus, std::forward_iterator and, thus, std::random_access_iterator) because
no type named 'type' in 'struct std::common_reference<std::pair<long unsigned int, const int&>&&, std::pair<long unsigned int, const int>&>'
(see https://godbolt.org/z/s89z56rY7) or the full code here:
#include <iostream>
#include <type_traits>
#include <vector>
#include <iterator>
using namespace std;
template<class Value, class VType, class RType>
struct _vector_map_iterator {
Value* _data = nullptr;
size_t index = 0;
using value_type = VType;
using reference = RType;
using difference_type = ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
reference operator*() const { return {index, *_data}; }
_vector_map_iterator& operator++() { ++index; return *this; }
_vector_map_iterator operator++(int) {_vector_map_iterator res = *this; ++(*this); return res; }
bool operator==(const _vector_map_iterator& other) const { return _data == other.data; }
};
template<class T>
using vmap_iterator = _vector_map_iterator<T, pair<size_t, T>, pair<size_t, T&>>;
template<class T>
using vmap_const_iterator = _vector_map_iterator<const T, pair<size_t, const T>, pair<size_t, const T&>>;
using I = vmap_const_iterator<int>;
//static_assert(std::common_reference_with<typename I::reference&&, typename I::value_type&>);
static_assert(forward_iterator<I>);
template<class Value>
struct vector_map {
vector<Value> _raw_data;
using iterator = vmap_iterator<Value>;
using const_iterator = vmap_const_iterator<Value>;
iterator begin() { return {_raw_data.data(), 0}; }
const_iterator begin() const { return {_raw_data.data(), 0}; }
vector_map(const initializer_list<Value>& lst): _raw_data(lst) {};
};
int main(){
const vector_map<int> int_map = {1,2,3};
const auto it = int_map.begin();
cout << (*it).first << ": " << (*it).second << '\n';
}
My question would be: is there a sensible (I specifically do not want to store key-value-pairs in the vector!) design for such an iterator class that also adheres to std::random_access_iterator?
EDIT: more details + full example

Error: can't dereference out of range vector iterator

How can I ensure iterator doesn't go out of range vector? and in the case where the filter would not match any elements of the input; in that case, how can i ensure ensure that begin() is equal to end()
Code
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; }
};
struct FilteringIterator : Iterator {
Callable callable;
using OriginalIterator = Iterator;
Iterator end;
Iterator current=(Iterator &)*this;;
FilteringIterator(const Iterator begin, Iterator end, Callable callable):Iterator(begin),end(end),callable(callable){}
Iterator &get_orig_iter() { return ((Iterator &)*this); }
auto operator++(){ return ((Iterator &)*this)++;}
bool operator==(const Iterator& rhs) const { return ((Iterator &)*this) == rhs; }
bool operator!=(const Iterator& rhs) const { return !(operator==(rhs)); }
auto operator*() {
while ((Iterator &)*this!=end && !callable(*get_orig_iter()))
++(Iterator &)*this;
return *(Iterator &)*this;
}
};
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>;
auto t=filter_iterator{container.end(),container.end(),action};
return Range{filter_iterator{container.begin(),container.end(),action}, filter_iterator{container.end(),container.end(),action}};
};
};
Main
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
for(auto a : v | filter(less_then(15))) // filter is applied lazily as the range is traversed
std::cout << a <<"D" << std::endl;
// prints 17.5 and 22.5 to the console
Output
2.5
7.5
12.5
Error
Move while loop to operator!=and return false if begin() is equal to end() to exist for loop

How do I get an iterable range from an N-dimensional container without copying?

Suppose I have a nested structure, say some class that contains some other classes:
struct Obj
{
std::vector<T> mVector; // T is large
};
std::vector<Obj> myVector;
I want to use some existing function, let's call it std::find_if, to find occurrences of T that match some criterion, etc. Many Standard Library functions (std::find_if included) require iterable ranges as inputs, so simply passing myVector iterators into these functions will cause the rows, not the elements, to be traversed.
Performance is also a concern so I don't want to have to reconstruct an entire vector of pointers or, worse, copy the objects themselves just in order to run these functions across the elements.
Having used boost::adaptors for various useful tasks such as filtering or indirecting containers without reconstructing them first, I figure I basically want to be able to do something like this:
auto myRange = boost::adaptors::nested(myVector, functor);
Where functor is some lambda that yanks nested ranges out of each row in my matrix, something like this:
auto functor = [](auto& it) { return boost::iterator_range(it.begin(), it.end(); }
Of course, boost::adaptors::nested doesn't exist. So how can I flatten this 2D array without copying Obj and without creating another flattened container first? The answer should be reasonably efficient while minimising the amount of code and boilerplate.
The answer is indeed to write an adaptor. It will need to keep track of the iterator in the outer container, and an iterator within the inner container.
Here is an example implementation, that only supports forward_iterator semantics, and const access — I'll leave a more complete implementation to you!
#include <cstddef>
#include <iterator>
template <typename V>
struct flat_view {
V &v;
typedef typename V::value_type inner_type;
typedef typename inner_type::value_type value_type;
typedef typename inner_type::reference reference;
typedef typename inner_type::const_reference const_reference;
struct const_iterator {
typedef std::forward_iterator_tag iterator_category;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::value_type value_type;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::pointer pointer;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::reference reference;
typedef ptrdiff_t difference_type;
typename inner_type::const_iterator i,i_end;
typename V::const_iterator o,o_end;
bool at_end;
const_iterator(): at_end(true) {}
const_iterator(typename V::const_iterator vb,typename V::const_iterator ve):
o(vb), o_end(ve), at_end(vb==ve)
{
if (!at_end) {
i=vb->begin();
i_end=vb->end();
}
}
const_iterator &operator++() {
if (at_end) return *this;
if (i!=i_end) ++i;
while (!at_end && i==i_end) {
if (++o==o_end)
at_end=true;
else {
i=o->begin();
i_end=o->end();
}
}
return *this;
}
const_iterator &operator++(int) {
iterator c(*this);
++*this;
return c;
}
bool operator==(const const_iterator &x) const {
return (at_end && x.at_end) || (o==x.o && i==x.i);
}
bool operator!=(const const_iterator &x) const { return !(*this==x); }
reference operator*() const { return *i; }
pointer operator->() const { return &*i; }
};
typedef const_iterator iterator;
explicit flat_view(V &v_): v(v_) {};
iterator begin() const { return iterator(v.begin(),v.end()); }
iterator end() const { return iterator(); }
const_iterator cbegin() const { return const_iterator(v.begin(),v.end()); }
const_iterator cend() const { return const_iterator(); }
};
template <typename V>
flat_view<V> make_flat_view(V &v) { return flat_view<V>(v); }
Quick demo:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::vector<double>> v={
{1,2,3,4},
{},
{10,9,8,7},
{5,6}
};
auto f=make_flat_view(v);
std::copy(f.begin(),f.end(),std::ostream_iterator<double>(std::cout," "));
std::cout << "\n";
}
produces:
1 2 3 4 10 9 8 7 5 6

C++ How to expose a map iterator to only the values of a map

I have some templates which can either have a map or a vector as underlying container. I would like the template to be able to expose const iterators to the elements. Most information I have read on how to expose iterators (such as this accu article) uses a form of
typedef std::vector<int>::iterator iterator;
typedef std::vector<int>::const_iterator const_iterator;
iterator begin() { return values.begin(); }
iterator end() { return values.end(); }
That doesn't really work for the template that uses the map though, because to access elements, the template can't use it->SomeMemberFunc() anymore, but rather needs to use it->second.SomeMemberFunc(). So I am looking to expose an iterator to the map elements which doesn't give access to the keys but only the values of the map.
How would I accomplish this?
A workaround1
#include <map>
#include <iterator>
template <typename Iter>
struct map_iterator : public std::iterator<std::bidirectional_iterator_tag,
typename Iter::value_type::second_type>
{
map_iterator() {}
map_iterator(Iter j) : i(j) {}
map_iterator& operator++() { ++i; return *this; }
map_iterator& operator--() { --i; return *this; }
bool operator==(map_iterator j) const { return i == j.i; }
bool operator!=(map_iterator j) const { return !(*this == j); }
typename map_iterator::reference operator*() { return i->second; }
typename map_iterator::pointer operator->() { return &i->second; }
map_iterator operator--(int) { return std::prev(--(*this)); }
map_iterator operator++(int) { return std::next((++*this)); }
protected:
Iter i;
};
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) {
return map_iterator<Iter>(j);
}
And then
int main() {
std::map<int,std::string> m {{1, "Hi"},{2, "Bye"}};
for (auto i=make_map_iterator(m.begin()); i!=make_map_iterator(m.end());i++)
cout << *i << endl;
}
Live code.

Custom input iterator

I have a custom read-only data structure that I need to transverse. I would like to create a custom iterator that need to skip certain values.
A simple but equivalent example would be the following. I have a vector of numbers and I want to loop through all skipping the negative values. Normally I would do something like:
vector<int> v;
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
if (*it > 0) {
dosomething(*it);
}
}
But I would like to do something like:
vector<int> v;
for (vector<int>::my_iterator it = v.my_begin(); it!=v.my_end(); ++it) {
dosomething(*it);
}
What is the right way to achieve this?
This is easily achieved with a boost::filter_iterator, if your data structure already stores a container under the hood. Here's a simple example:
#include <vector>
#include <iostream>
#include <boost/iterator/filter_iterator.hpp>
class X{
typedef std::vector<int> container;
struct Pred{
bool operator()(int i){
return i % 2 == 0;
}
};
public:
typedef boost::filter_iterator<Pred, container::iterator> iterator;
void add(int val){ nums.push_back(val); }
iterator begin(){ return iterator(nums.begin(), nums.end()); }
iterator end(){ return iterator(nums.end(), nums.end()); }
private:
container nums;
};
int main(){
X x;
for(int i=0; i < 10; ++i)
x.add(i);
for(X::iterator it = x.begin(), ite = x.end(); it != ite; ++it)
std::cout << *it << ' ';
}
Live example at Ideone. Output:
0 2 4 6 8
This isn't a very nice solution, but I'll post it anyway. Any attempt to dereference this iterator wrapper will cause it to check the current value and advance the iterator past any negative values. It will be called recur
template<typename InputIterator>
struct nonnegative_iterator : InputIterator {
template<typename Arg>
nonnegative_iterator(Arg i) : InputIterator(i) {
}
typename InputIterator :: reference operator* () {
typename InputIterator :: reference x = InputIterator :: operator*();
if( x < 0) {
++ (*this); // equivalent to this -> operator++ ()
return **this;
} else
return x;
}
};
which can be used like this:
for ( nonnegative_iterator< vector<int>::iterator > it = v.begin(); it!=v.end(); ++it) {
This has some problems, for example I haven't implemented a const method to allow to dereference to value_type. So use at your own risk!
Assuming you don't have control over the interface of vector<int>, e.g. because it is actually std::vector<int>, the first thing you want to do is to change the way you get your custom iterators. That is, instead of writing
for (vector<int>::my_iterator it = v.my_begin(); it != v.my_ned(); ++it)
you would use
for (my_iterator it(my_begin(v)), end(my_end(v)); it != end; ++it)
You can achieve the modified interface for a custom container but this is a bigger fish to fry. Creating your input iterator now essentially amounts to creating a suitable wrapper for the underlying iterator. This could look something like this:
template <typename InIt, Pred>
struct my_iterator {
typedef typename std::iterator_traits<InIt>::value_type value_type;
typedef typename std::iterator_traits<InIt>::difference_type difference_type;
typedef typename std::iterator_traits<InIt>::reference reference;
typedef typename std::iterator_traits<InIt>::pointer pointer;
my_iterator(InIt it, InIt end, Pred pred): it_(it), end_(end), pred_(pred) {}
bool operator== (my_iterator const& other) const { reutrn this->it_ == other.it_; }
bool operator!= (my_iterator const& other) const { return !(*this == other); }
reference operator*() { return *this->it_; }
pointer operator->() { return this->it_; }
my_iterator& operator++() {
this->it_ = std::find_if(this->it_, this->end_, this->pred_);
return *this;
}
my_iterator operator++(int)
{ my_iterator rc(*this); this->operator++(); return rc; }
private:
InIt it_, end_;
Pred pred_;
The my_begin() and my_end() functions would then create a suitable object of this type. One approach to avoid having to write this is to have a look a Boost's iterator adaptors: there should be something suitable over there.