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.
Related
Hey I am trying to implement Color space logic with c++.
As you may see every color space has its unique color components with its unique ranges and names, so I tried to implement a space component logic first.
template<typename T, T min, T max>
struct SpaceComponent {
static constexpr T MIN = min;
static constexpr T MAX = max;
T value;
SpaceComponent() = default;
SpaceComponent(T value) : value(static_cast<T>(value)) {
}
operator T() const {
return value > MAX ? MAX : value < MIN ? MIN : value;
}
operator SpaceComponent<T, MIN, MAX>() const {
return SpaceComponent<T, MIN, MAX>(static_cast<T>(value));
}
inline bool operator==(const SpaceComponent &other) const {
return value == other.value;
}
inline bool operator!=(const SpaceComponent &other) const {
return !(*this == other);
}
inline bool operator>(const SpaceComponent &other) const {
return value > other.value;
}
inline bool operator<(const SpaceComponent &other) const {
return !(*this > other) && *this != other;
}
inline bool operator>=(const SpaceComponent &other) const {
return !(*this < other);
}
inline bool operator<=(const SpaceComponent &other) const {
return !(*this > other);
}
inline SpaceComponent &operator=(const T &elem) {
if (value == elem) {
return *this;
}
value = static_cast<T>(elem);
return *this;
}
inline SpaceComponent &operator=(const SpaceComponent &other) {
if (*this == other) {
return *this;
}
*this = other.value;
return *this;
}
inline SpaceComponent &operator++() {
*this = static_cast<T>(++value);
return *this;
}
inline SpaceComponent &operator--() {
*this = static_cast<T>(--value);
return *this;
}
inline SpaceComponent operator+(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value + elem);
return result;
}
inline SpaceComponent operator-(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value - elem);
return result;
}
inline SpaceComponent operator*(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value * elem);
return result;
}
inline SpaceComponent operator/(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value / elem);
return result;
}
inline SpaceComponent operator+(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value + other.value);
return result;
}
inline SpaceComponent operator-(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value - other.value);
return result;
}
inline SpaceComponent operator*(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value * other.value);
return result;
}
inline SpaceComponent operator/(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value / other.value);
return result;
}
inline SpaceComponent operator+=(const T &elem) {
*this = *this + elem;
return *this;
}
inline SpaceComponent operator-=(const T &elem) {
*this = *this - elem;
return *this;
}
inline SpaceComponent operator*=(const T &elem) {
*this = *this * elem;
return *this;
}
inline SpaceComponent operator/=(const T &elem) {
*this = *this / elem;
return *this;
}
inline SpaceComponent &operator+=(const SpaceComponent &other) {
*this = *this + other;
return *this;
}
inline SpaceComponent &operator-=(const SpaceComponent &other) {
*this = *this - other;
return *this;
}
inline SpaceComponent &operator*=(const SpaceComponent &other) {
*this = *this * other;
return *this;
}
inline SpaceComponent &operator/=(const SpaceComponent &other) {
*this = *this / other;
return *this;
}
};
By this logic I can create a color component of any type I want and it will not exit it's ranges(see implementation). Note that I am keeping MIN and MAX statically as I do not want my space component to increase in size(imagine what will be the size of 4096x4096 image in my ram if I do so).
Then I tried to implement different spaces of colors
struct RGB {
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline RGB operator+(const RGB &other) {
RGB rgb;
rgb.r = r + other.r;
rgb.g = g + other.g;
rgb.b = b + other.b;
return rgb;
}
};
struct ARGB {
SpaceComponent<unsigned char, 0, 255> a;
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline ARGB operator+(const ARGB &other) {
ARGB argb;
argb.a = a + other.a;
argb.r = r + other.r;
argb.g = g + other.g;
argb.b = b + other.b;
return argb;
}
};
I stopped at this two as I realized that I need to write all operator overloading logic for all the spaces and that is huge work. I need somehow implement the operator overloading in one struct struct Space and derive all others from that. Note I cannot have any virtual methods as any pointer to vtable will increase the sizeof(Space) and it will raise problems that I already mentioned.I think I need something like template meta-programming to do this (using macros is my last choice) or using some technique like CRTP, as a draft I think my Space implementation can look like this.
using RGB = Space<SpaceComponent<unsigned char,0,255> r,SpaceComponent<unsigned char,0,255> g,SpaceComponent<unsigned char,0,255> b>;
I know that it's illegal to write like this, but can I have a struct which syntax will at least be nearly similar to this? Thx in advance.
I think it is possible if all components have the same type.
We can declare Space like this:
template <typename T, typename ...Components>
struct Space {...}
and use syntax like:
Space<unsigned char, Component<'r'>, Component<'g'>, Component<'b'>>;
where
template <char Id>
struct Component{...} // Component is just wrapper for ComponentImpl (for creation, to not duplicate types every time)
template <typename T> // your `SpaceComponent`
struct ComponentImpl{...}
Then inside Space we can use constexpr function to fill std::array<ComponentImpl>.
And inside operator+ just iterate through this array and sum all components.
Also we (probably) does not have to store T min, T max, we can use std::numeric_limits to get them.
UPDATE:
I wrote some prototype of this, take a look: https://godbolt.org/z/oEThae
I'm experimenting with the execution policies on a toy problem of evaluating a polynomial at a certain point, given its coefficients and the point of evaluation (x).
Here's my implementation:
class counter: public std::iterator<
std::random_access_iterator_tag, // iterator_category
size_t, // value_type
size_t, // difference_type
const size_t*, // pointer
size_t // reference
>{
size_t num = 0;
public:
explicit counter(size_t _num) : num(_num) {}
counter& operator++() {num += 1; return *this;}
counter operator++(int) {counter retval = *this; ++(*this); return retval;}
bool operator==(counter other) const {return num == other.num;}
bool operator!=(counter other) const {return !(*this == other);}
counter& operator+=(size_t i) { num += i; return *this; }
counter& operator-=(size_t i) { num -= i; return *this; }
counter operator +(counter &other) const { return counter(num + other.num);}
counter operator -(counter &other) const { return counter(num - other.num); }
counter operator +(size_t i) const { return counter(num + i); }
counter operator -(size_t i) const {return counter(num - i); }
reference operator*() const {return num;}
};
double better_algorithm_polinomials(const vector<double> & coeffs, double x) {
return transform_reduce(execution::par, cbegin(coeffs), end(coeffs), counter(0), 0.0, plus{}, [x](double coeff, size_t index) { return coeff * pow<double>(x, index); });
}
This works fine for the par policy, but for the par_unseq this fails due to race conditions.
I attempted to mitigate them using atomic_size_t, but there are some places (such as copy construction, or ++(int) operator), where I'm not atomic and probably have to use locks... I was wondering if there's a better way.
This doesn't work:
class counter: public std::iterator<
std::random_access_iterator_tag, // iterator_category
atomic_size_t, // value_type
atomic_size_t, // difference_type
const atomic_size_t*, // pointer
atomic_size_t // reference
>{
atomic_size_t num = 0;
public:
explicit counter(size_t _num) : num(_num) {}
counter(counter &other) { num = other.num.load();}
counter& operator++() {num += 1; return *this;}
const counter operator++(int) {num += 1; return counter(num-1);}
bool operator==(counter &other) const {return num == other.num;}
bool operator!=(counter &other) const {return !(*this == other);}
counter& operator+=(size_t i) { num += i; return *this; }
counter& operator-=(size_t i) { num -= i; return *this; }
counter operator +(counter &other) const { return counter(num + other.num);}
difference_type operator -(counter &other) const { return num - other.num; }
counter operator +(size_t i) const { return counter(num + i); }
difference_type operator -(size_t i) const {return num - i; }
size_t operator [](size_t i) const {return i;}
reference operator*() const {return num.load();}
};
I attempted to mitigate them using atomic_size_t
Note that you should statically assert that std::atomic<std::size_t> is actually lock-free in your platform.
but there are some places (such as copy construction, or ++(int) operator), where I'm not atomic and probably have to use locks...
You cannot acquire locks when using unsequenced execution policies! See [algorithms.parallel], e.g. this and this.
I have trying to use a class as a key in an std::map. I have read documentations and I know I have to type some sort of sorting rule because my std::map is a binary search tree. The problem arise because the class key have another classes in it. Can someone get me some advice how to build the operators?
MasterRenderer file
std::map<TexturedModel, std::vector<Entity>> entites;
void MasterRenderer::processEntity(Entity entity)
{
TexturedModel model = entity.getModel();
auto search = entites.find(model);
if (search != entites.end()) {
//found
entites[model].emplace_back(entity);
}
else {
//not found
entites[model].emplace_back(entity);
}
std::cout << entites[model].size() << std::endl;
}
TexturedModel.h
TexturedModel(RawModel model, ModelTextures
texture)
:m_model(model), m_texture(texture) {
};
friend bool operator<(const TexturedModel& m,
const
TexturedModel& m2) {
return m.m_model < m2.m_model || m.m_model ==
m2.m_model && m.m_texture < m2.m_texture;
}
private:
RawModel m_model;
ModelTextures m_texture;
};
Rawmodel.h
unsigned int VaoID;
unsigned int Vertecies;
RawModel(unsigned int vaoID, unsigned int
vertecies)
:VaoID(vaoID), Vertecies(vertecies) {};
friend bool operator <(const RawModel& rhs, const
RawModel& rhs2)
{
return rhs.get() < rhs2.get();
}
friend bool operator ==(const RawModel& rhs, const
RawModel& rhs2)
{
return rhs.get() == rhs2.get();
}
const RawModel* get() const {
return this;
}
ModelTextures.h
ModelTextures(unsigned int ID)
:textureID(ID) {};
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return rhs.get() < rhs2.get();
}
const ModelTextures* get() const{
return this;
}
private:
unsigned int textureID;
float shineDamper = 1.0f;
float reflectivity = 0.0f;
};
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return rhs.get() < rhs2.get();
}
const ModelTextures* get() const{
return this;
}
this orders by address of the object, not content. That violates the requirements of std::map.
friend auto as_tie(const ModelTexture& m) {
return std::tie(m.textureID, m.shineDamper, m.reflexivity);
}
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return as_tie(rhs) < as_tie(lhs);
}
repeat this pattern for TexturedModel and RawModel.
If you are stuck in c++11 you have to manually write the return type of as_tie or use decltype.
friend auto as_tie(const ModelTexture& m)
-> decltype(std::tie(m.textureID, m.shineDamper, m.reflexivity))
{
return std::tie(m.textureID, m.shineDamper, m.reflexivity);
}
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
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());}