I have a class which holds small numbers inside bigger integer variable. It works fine and fast and looks like this:
template
class Container<IntegerT>
static int bitsPerElement;
IntegerT data; // [0000] [0000] [0000] [0000] up to 128bits(or maybe more)
int size;
iterator as value_type return "reference" to container element:
Container::iterator
DataRef operator*()
DataRef
Container* parent;
int position;
But i got a problem of unavailability of std::sort, because it have no clue how to actually swap elements of this container (direct swapping of DataRefs is obviously pointless).
Is there any magic way to make std::sort work with it (actually to force it use custom swap function)?
Or is there decent alternative to std::sort which can handle this situation? (storing DataRefs in array is not considered as a solution)
Which is the fastest way to sort this data structure?
#ifndef INTSTORAGE_H
#define INTSTORAGE_H
#include <algorithm>
template<class T> class IntStorage;
template<class T>
class DataRef
{
public:
DataRef(IntStorage<T>* parent, int position) : m_parent(parent), m_position(position) {}
DataRef(DataRef&& o) = default;
DataRef(const DataRef& o) = default;
int value() const {return m_parent->value(m_position);}
void setValue(int value) {m_parent->setValue(m_position, value);}
DataRef& operator=(const DataRef& c)
{ setValue(c.value()); return *this; }
DataRef& operator=(const DataRef&& c)
{ setValue(c.value()); return *this; }
bool operator<(const DataRef& o) const
{ return value() < o.value(); }
IntStorage<T>* m_parent;
int m_position;
};
template<class T>
class IntStorage
{
template<typename> friend class IntStorage;
template<typename> friend class DataRef;
public:
void append(int value)
{
data |= (static_cast<T>(value) << (s_bitsPerItem * size));
++size;
}
void setValue(int index, T value)
{
data = ((~(s_mask << (s_bitsPerItem * index))) & data)
| (static_cast<T>(value) << (s_bitsPerItem * index));
}
T value(int i) const { return (data & s_mask << (i * s_bitsPerItem)) >> (i * s_bitsPerItem); }
class iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = int;
using value_type = DataRef<T>;
using pointer = DataRef<T>*;
using reference = DataRef<T>&;
iterator(IntStorage<T>* parent, int pos = 0) : ref(parent, pos) {}
inline bool operator==(const iterator& o) const { return ref.m_parent == o.ref.m_parent && ref.m_position == o.ref.m_position;}
inline bool operator!=(const iterator& o) const { return !operator==(o);}
inline const DataRef<T>& operator*() const { return ref;}
inline DataRef<T>& operator*() { return ref; }
inline iterator& operator++() { ++ref.m_position; return *this; }
inline iterator& operator--() { --ref.m_position; return *this; }
inline int operator-(const iterator& o) const { return ref.m_position - o.ref.m_position; }
inline iterator operator+(int diff) const { return iterator(ref.m_parent, ref.m_position + diff); }
inline iterator operator-(int diff) const { return iterator(ref.m_parent, ref.m_position - diff); }
inline bool operator<(const iterator& o) const { return ref.m_position < o.ref.m_position; }
DataRef<T> ref;
};
friend class iterator;
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size);}
iterator cbegin() {return iterator(this, 0);}
iterator cend() {return iterator(this, size);}
static constexpr T s_mask = 0b111111;
static constexpr int s_bitsPerItem = 6;
int size = 0;
T data = 0;
};
#endif // INTSTORAGE_H
Related
What is the right way to implement an iterator that iterates over a Recordset provided below in C++ style?
class Recordset
{
public:
Recordset(const Recordset&) = delete;
Recordset& operator = (const Recordset&) = delete;
Recordset(Recordset&& other) noexcept = default;
Recordset& operator = (Recordset&&) = default;
//Moves to the next record. Returns false if the end is reached.
bool Next();
//Gets the current record as an instance of type T.
template <class T>
void Get(T& val);
};
my idea is that I probably do something like this:
template <class T>
class Iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
Iterator() = default;
Iterator(Recordset s) : m_i(std::move(s))
{
try_next();
}
Iterator(const Iterator&) = delete;
Iterator& operator = (const Iterator&) = delete;
Iterator(Iterator&& other) = default;
Iterator& operator = (Iterator&& other) = default;
T* operator-> () { return cur(); }
T* operator* () { return cur(); }
bool operator== (const Iterator& other) const noexcept
{
//They both are end().
return !m_v && !other.m_v;
}
bool operator!= (const Iterator& other) const noexcept
{
return !operator==(other);
}
Iterator& operator++ ()
{
this->try_next();
return *this;
}
Iterator operator++ (int)
{
Iterator tmp = *this; //would not compile.
this->try_next();
return tmp;
}
private:
bool try_next()
{
if (m_i.Next())
{
T val;
m_i.Get(val);
m_v = val;
return true;
}
return false;
}
T* cur()
{
T& val = *m_v;
return &val;
}
Recordset m_i;
std::optional<T> m_v;
};
template <class T>
std::ranges::subrange<Iterator<T>> make_range(Recordset& s)
{
return std::ranges::subrange(Iterator<T>(s), Iterator<T>{});
}
and use it as follows:
struct Record { int x; std::string y; };
int main()
{
Recordset s;
for (Record& r : make_range(s))
{
std::cout << r.x << r.y << std::endl;
}
return 0;
}
The frist question is how do I implement Iterator operator++ (int) if both Recordset and Iterator are move-only? (temp and this can't point to different records, because there is only one current record in the recordset). Does C++20 require it?
The second question is it a good idea to implement end() in this way? (end() is a simply an iterator containing an empty optional)
Single pass move-only input iterators (A c++20 std::input_iterator) are only required to be weakly incremental, where (void) ++i has the same effect as (void) i++. You can simply have void operator++(int) { ++*this; }. Older requirements for iterators (Cpp17InputIterator) requires iterators to be copyable, and require operator++ to return that copy.
And for your second question, you might want to use a sentinel type, something like:
template<typename T>
bool operator==(const Iterator<T>& it, std::default_sentinel_t) {
return !it.m_v;
}
// != can be rewritten from ==, so no need to write one
template <class T>
auto make_range(Recordset& s)
{
return std::ranges::subrange(Iterator<T>(s), std::default_sentinel);
}
And if you need to work with a algorithm that can't use separate sentinel types, use ranges::common_view. Your current solution also works, except you need to have this == &other || (!m_v && !other.m_v);.
i have to implement a forward iterator on a stack based on arrays. I can't use std::vectors or anything, i just need that. My development of this program stopped when i begun with forward iterator, and in particular with the operators.
I have a method that takes a generic sequence, and from that, given an offset, creates a stack:
template <typename IterT>
stack(IterT begin, IterT end) : _stack(0), _size(0), _capacity(0) {
try {
for(; begin!=end; ++begin) {
push(static_cast<T>(*begin));
}
}
catch(...) {
clear(); //my method to destroy the stack
throw;
}
}
In my main i do the following:
int a[5] = {1, 2, 3, 4, 5};
stack<int> sint(a, a+5);
cout << sint << endl;
But when the code runs the stack is created but not printed. Can somebody help me? And also give me other helps(on code indentation, improvements, etc...) Thank you, I will post the iterator code forward.
class const_iterator {
const T* data;
unsigned int index;
public:
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data[index] == other.data[index];
}
bool operator!=(const const_iterator &other) const {
return data[index] != other.data[index] ;
}
private:
friend class stack;
const_iterator(unsigned int ind) :
index(ind){}
}; // class const_iterator
const_iterator begin() const {
cout << "begin" << _stack[_size-1] << endl;
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
cout << "end" << _stack[0] << endl;
return const_iterator(_stack[0]);
}
Last but not least i redefined the << operator to fit the iterator:
template <typename T>
std::ostream &operator<<(std::ostream &os, const stack<T> &st) {
typename stack<T>::const_iterator i, ie;
for(i = st.begin(), ie = st.end(); i!=ie; ++i){
os << *i << std::endl;
}
return os;
}
The code for the stack is the following (I omitted something for readability).
stack()
: _capacity(0), _size(0), _stack(0){}
void push (const T &value){
if (_size == _capacity){ //raddoppio la dimensione
if(_capacity == 0)
++_capacity;
_capacity *= 2;
T* tmp = new T[_capacity];
copy_n(_stack, _size, tmp);
swap(_stack, tmp);
delete[] tmp;
}
_stack[_size] = value;
++_size;
}
void pop(){
T _tmp;
if(!is_empty()){
_tmp = _stack[_size-1];
--_size;
}
}
If you want to create an iterator that looks like a pointer, you don't need index, because data plays its role. Comparison operator should compare datas, not values:
bool operator==(const const_iterator &other) const {
return data == other.data;
}
If you want to create a reverse iterator, it is slightly more complex. First, operator++ should decrement data. Second, dereference operator should return not *data, but *(data - 1). Third, data in the begin() iterator should point to stack[size], and data in the end() iterator should point to stack[0]. You don't need a destructor in any case.
I followed the previous advices and here's the edited result, still i can't figure out how to properly use the constructor in the private section
class const_iterator {
const T *data;
public:
/* ITERATOR TRAITS HERE */
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data == other.data;
}
bool operator!=(const const_iterator &other) const {
return data != other.data;
}
private:
friend class stack;
const_iterator(const T *d) {
data = d;
}
}; // classe const_iterator
const_iterator begin() const {
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
return const_iterator(_stack[0]);
}
I've created an abstract container class with the following basic functions
class AbstractInventory
{
private:
string name;
public:
AbstracInventory(string name);
virtual ~AbstractInventory();
virtual size_t size() const = 0;
virtual Stack* stackAt(size_t index) const = 0;
virtual Stack* &stackAt(size_t index) = 0;
Stack* operator[](int index) const { return(stackAt(index)); }
Stack* &operator[](int index) { return(stackAt(index)); }
};
As an example this can be one of the derived classes
class BasicInventory : public AbstractInventory
{
private:
vector<Stack*> content;
public:
BasicInventory(string name, int size, bool sorting = false, ItemFilter* f=nullptr);
size_t size() const override { return(content.size()); }
Stack* stackAt(size_t index) const override { return(content[index]); }
Stack*& stackAt(size_t index) override { return(content[index]); }
};
Now my question is if its possible to make the abstract interface and it's childs iterable like a vector or list to use it for example in an foreach loop
You may create your own iterator, something like:
struct Stack {};
class AbstractInventory;
class AbstractInventoryIterator
{
public:
using difference_type = std::ptrdiff_t;
using value_type = Stack*;
using pointer = Stack**;
using reference = Stack*&;
using iterator_category = std::random_access_iterator_tag;
AbstractInventoryIterator(AbstractInventory* inv, std::size_t index) : inv(inv), index(index) {}
AbstractInventoryIterator(const AbstractInventoryIterator&) = default;
AbstractInventoryIterator& operator =(const AbstractInventoryIterator&) = default;
bool operator == (const AbstractInventoryIterator& rhs) const { return std::tie(inv, index) == std::tie(rhs.inv, rhs.index); }
bool operator != (const AbstractInventoryIterator& rhs) const { return !(*this == rhs); }
reference operator*() const;
pointer operator->() const { return &operator*(); }
AbstractInventoryIterator& operator ++() { ++index; return *this; }
AbstractInventoryIterator& operator --() { --index; return *this; }
AbstractInventoryIterator operator ++(int) { auto next(*this); ++*this; return next; }
AbstractInventoryIterator operator --(int) { auto prev(*this); --*this; return prev; }
AbstractInventoryIterator& operator += (difference_type n) { index += n; return *this; }
AbstractInventoryIterator& operator -= (difference_type n) { index -= n; return *this; }
AbstractInventoryIterator operator + (difference_type n) const { auto res(*this); res += n; return res; }
AbstractInventoryIterator operator - (difference_type n) const { auto res(*this); res -= n; return res; }
friend AbstractInventoryIterator operator + (difference_type n, AbstractInventoryIterator it) { return it + n; }
difference_type operator - (const AbstractInventoryIterator& it) const { return index - it.index; }
reference operator [](difference_type n) const;
bool operator < (const AbstractInventoryIterator& rhs) const { return rhs - *this > 0; }
bool operator > (const AbstractInventoryIterator& rhs) const { return rhs < *this; }
bool operator <= (const AbstractInventoryIterator& rhs) const { return !(rhs < *this); }
bool operator >= (const AbstractInventoryIterator& rhs) const { return !(*this < rhs); }
private:
AbstractInventory* inv = nullptr;
int index = 0;
};
class AbstractInventory
{
private:
std::string name;
public:
AbstractInventory(std::string name) : name(name) {}
virtual ~AbstractInventory() = default;
virtual std::size_t size() const = 0;
virtual Stack* stackAt(std::size_t index) const = 0;
virtual Stack* &stackAt(std::size_t index) = 0;
Stack* operator[](int index) const { return(stackAt(index)); }
Stack* &operator[](int index) { return(stackAt(index)); }
AbstractInventoryIterator begin() { return {this, 0}; }
AbstractInventoryIterator end() { return {this, size()};}
};
auto AbstractInventoryIterator::operator*() const
-> AbstractInventoryIterator::reference
{ return inv->stackAt(index); }
auto AbstractInventoryIterator::operator [](difference_type n) const
-> AbstractInventoryIterator::reference
{ return inv->stackAt(index + n); }
And equivalent for const_iterator.
I wrote this Vector class and one nested Iterator class and one const_Iterator class, now I have to secure my Vector so my Iterator doesn't point beyond .end() with for instance my operator ++ method and to throw an exception if i try.
so in my iterator class I cannot access .end() because its a vector method. so I was thinking, instead of pointing on values in my Iterator class I point on the whole vector but i cannot access .end() with a Vector* .
Am I on the right way to the solution and if I am how can I pass my Vector so I can use it in the way I intend to?
class Vector{
public:
using value_type= double;
using size_type= size_t;
using difference_type= ptrdiff_t;
using reference = double&;
using const_reference= const double&;
using pointer = double*;
using const_pointer= const double*;
using iterator = double*;
using const_iterator= const double*;
private:
size_t sz;
size_t max_sz;
double* values=nullptr;
class const_Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
const_Iterator(double* p){
ptr=p;
cnt=0;
}
const_Iterator& operator++ () {
ptr++;
cnt = 0;
return *this;
}
bool operator==(const const_Iterator& rop)const {
return this->ptr == rop.ptr;
}
bool operator!=(const const_Iterator& rop)const {
return this->ptr != rop.ptr;
}
const double operator* () const {
return *ptr;
}
friend Vector::difference_type operator-(const Vector::const_Iterator& lop,const Vector::const_Iterator& rop) {
return lop.ptr-rop.ptr;
}
};
class Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
Iterator(double* p){
ptr=p;
cnt=0;
}
Iterator& operator++() {
ptr++;
cnt = 0;
return *this;
}
Iterator operator++(int){
Iterator a(ptr);
ptr++;
return a;
}
bool operator==( Iterator& rop) {
return this->ptr != rop.ptr;
}
bool operator!=(const Iterator& rop) {
return this->ptr != rop.ptr;
}
double& operator*() {
return *ptr;
}
operator const_Iterator() const{
return const_Iterator(ptr);
};
};
const_Iterator end() const{return const_Iterator(values+sz);}
const_Iterator begin() const{return const_Iterator(values);}
Iterator begin() { return values; }
Iterator end() { return values + sz; }
size_t min_sz = 5;
Vector();
Vector(size_t);
Vector(const Vector&);
Vector (initializer_list<double> );
void push_back(double);
void reserve(size_t);
void pop_back();
bool empty();
void clear();
Vector& operator=(const Vector&);
const double& operator[] (size_t) const;
double& operator[] (size_t) ;
void fit_to_shrink();
size_t size()const {return sz;}
ostream& print(ostream&) const;
};
Your iterator may look like:
class Iterator{
public:
// ... using type
private:
Vector* parent;
std::size_t index;
public:
Iterator(Vector& v, std::size_t index) : ptr(&v), index(index) {}
Iterator& operator++() {
if (index == parent->size()) {
throw std::runtime_error("++ on end iterator");
}
++index;
return *this;
}
Iterator operator++(int){
Iterator old(*this);
++(*this);
return old;
}
bool operator==(const Iterator& rhs) const {
if (parent != rhs.parent) {
throw std::runtime_error("You compare iterator of different containers");
}
return index == rhs.index;
}
bool operator!=(const Iterator& rop) const { return !(*this == rhs); }
double& operator*() { return parent->at(index); } // `at` throws on invalid index
// ...
};
And your vector:
Iterator Vector::begin() { return Iterator(this, 0);}
Iterator Vector::end() { return Iterator(this, size());}
I'm trying to make the iterator work properly, and for the inequality i != a.end().
I get the error
no know conversion from argument 2 from 'const a3::vector<int>::iterator' to 'const a3::vector<int>&
for the friend function. I need the function to check if the iterator is not equal to vector.end() and am unsure how I would do it.
Class
#include <iostream>
using std::cout;
using std::endl;
namespace a3
{
template <typename T>
class vector
{
public:
class iterator {
public:
int index_;
vector* a_;
iterator() : index_(-1), a_(0) {}
iterator(int index, vector* a) : index_(index), a_(a) {}
iterator& operator=(const iterator& itr)
{
a_ = itr.a_;
index_ = itr.index_;
return *this;
}
iterator& next() {
index_++;
return *this;
}
iterator& operator++() {
return next();
}
int& operator*() { return (*a_)[index_]; }
};
private:
T* mem_;
int sz_;
public:
vector(int sz) : sz_(sz), b_(0, this), e_(sz, this)
{
mem_ = new T[sz];
}
~vector() { delete[] mem_; }
const T& operator[](T i) const { return mem_[i]; }
T& operator[](T i) { return mem_[i]; }
const int& get_size() const { return sz_; }
const iterator& begin() { return b_; }
const iterator& end() { return e_; }
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
{
return !(itr1.index_ == vec1.end);
}
private:
iterator b_;
iterator e_;
};
}
Main Function
#include "a3_vector.cpp"
int main(int argc, char** argv)
{
using namespace a3;
vector<int> a(10); // allocate an int array of size 10
for (int i=0; i<10; ++i) a[i] = i*2;
// a now looks as follows
//0,2,4,6,8,10,12,14,16,18
// prints the content of the array
vector<int>::iterator i;
for (i = a.begin(); i != a.end(); i.next()) {
cout << *i << endl;
}
}
This is fundamentally wrong:
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
Iterator comparisons should compare iterators. What you want are comparison operators that look like this:
friend bool operator!=(const iterator& itr1, const iterator& itr2);
friend bool operator==(const iterator& itr1, const iterator& itr2);
After all, that's what this expression is trying to do:
i != a.end()
You're trying to compare two iterators. The error is just trying to convert a.end() to a const vector<T>&, since that's the match that it found for !=. Simply fix != to take an iterator as the second argument and you'll be fine.