You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libpEpDatatypes/src/wrapper.hh

191 lines
4.3 KiB

// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPDATATYPES_WRAPPER_HH
#define LIBPEPDATATYPES_WRAPPER_HH
#include <initializer_list>
#include <iterator>
namespace pEp
{
template<class T>
class Wrapper
{
public:
typedef T c_type;
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) } {}
// no implicit copying... (yet?)
Wrapper(const Wrapper<T>&) = delete;
void operator=(const Wrapper<T>&) = delete;
// must be implemented separately for each T
Wrapper(Wrapper<T>&& victim);
Wrapper<T>& operator=(Wrapper<T>&& victim);
~Wrapper();
Wrapper<T> copy() const;
bool operator==(const Wrapper<T>& b) const
{
return value==b.value;
}
bool operator!=(const Wrapper<T>& b) const
{
return value!=b.value;
}
private:
// must be defined for each wrapped type:
template<class... Args>
T _new(Args...);
T value;
};
// many wrapped datatypes are pointers, we can generalize a lot for them:
template<class T>
class Wrapper<T*>
{
public:
typedef T* c_type;
Wrapper() : value{nullptr} {}
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) } {}
// move is easy, efficient and generic:
Wrapper(Wrapper<T*>&& victim) noexcept
: value{ victim.value}
{
victim.value = nullptr;
}
Wrapper<T*>& operator=(Wrapper<T*>&& victim) noexcept
{
_free(value);
value = victim.value;
victim.value = nullptr;
return *this;
}
Wrapper(const Wrapper<T*>& orig)
: value{ orig.copy_out() }
{}
Wrapper<T*>& operator=(const Wrapper<T*>& orig)
{
if(&orig == this) return *this;
_free(value);
value = orig.copy_out();
return *this;
}
~Wrapper()
{
_free(value);
}
bool operator==(const Wrapper<T*>& b) const
{
return value==b.value;
}
bool operator!=(const Wrapper<T*>& b) const
{
return value!=b.value;
}
const T* operator->() const { return value; }
const T* get() const { return value; }
// dangerous!
T* operator->() { return value; }
T* get() { return value;}
T* move_out() { T* r = value; value=nullptr; return r;}
// only implemented for the datatypes where necessay.
// other implementations can follow if necessary.
T* copy_out() const;
protected:
Wrapper(T* _value) : value{_value} {}
// must be defined for each wrapped type:
template<class... Args>
T* _new(Args...);
void _free(T*);
T* value;
};
// Wraps single-linked lists and provides an interface compatible
// to std::forward_list
template<class T, class Element>
class ListWrapper;
template<class T, class Element>
class ListWrapper<T*, Element> : public Wrapper<T*>
{
public:
typedef Wrapper<T*> Base;
typedef ListWrapper<T*, Element> LW;
static Element T::* const Value; // to access the current value
// does not own the *value
class iterator : public std::iterator< std::forward_iterator_tag, Element, ptrdiff_t>
{
public:
iterator() = default;
iterator operator++() { return (value ? value = value->next : value); }
Element operator*() { return value->*LW::Value; }
Element operator->() { return value->*LW::Value; }
bool operator==(const iterator& other) const { return value == other.value; }
bool operator!=(const iterator& other) const { return value != other.value; }
private:
iterator(T* _t) : value{_t} {}
T* value = nullptr;
friend class ListWrapper<T*, Element>;
};
using Base::value;
ListWrapper() : Base() {}
ListWrapper(const std::initializer_list<pEp::Wrapper<Element>>& i);
ListWrapper(const std::initializer_list<Element>& i);
iterator begin() { return iterator{value}; }
iterator end() const { return iterator{}; }
int size() const;
bool empty() const;
void erase(const iterator& it);
void clear();
void push_back(Element&&);
void push_back(Wrapper<Element>&&);
};
} // end of namespace pEp
#endif // LIBPEPDATATYPES_WRAPPER_HH