Waybar/include/util/ptr_vec.hpp

582 lines
12 KiB
C++

#pragma once
#include <cassert>
#include <memory>
#include <type_traits>
#include <vector>
#include "algorithm.hpp"
namespace waybar::util {
/// An iterator wrapper that dereferences twice.
template<typename Iter>
struct double_iterator {
using wrapped = Iter;
using value_type = std::decay_t<decltype(*std::declval<typename wrapped::value_type>())>;
using difference_type = typename wrapped::difference_type;
using reference = value_type&;
using pointer = value_type*;
using iterator_category = std::random_access_iterator_tag;
using self_t = double_iterator<Iter>;
double_iterator(wrapped w) : _iter(std::move(w)) {}
double_iterator() : _iter() {}
reference operator*() const
{
return (**_iter);
}
pointer operator->() const
{
return &(**_iter);
}
self_t& operator++()
{
_iter.operator++();
return *this;
}
self_t operator++(int i)
{
return _iter.operator++(i);
}
self_t& operator--()
{
_iter.operator--();
return *this;
}
self_t operator--(int i)
{
return _iter.operator--(i);
}
auto operator==(const self_t& rhs) const noexcept
{
return _iter == rhs._iter;
}
auto operator!=(const self_t& rhs) const noexcept
{
return _iter != rhs._iter;
}
auto operator<(const self_t& rhs) const noexcept
{
return _iter < rhs._iter;
}
auto operator>(const self_t& rhs) const noexcept
{
return _iter > rhs._iter;
}
auto operator<=(const self_t& rhs) const noexcept
{
return _iter <= rhs._iter;
}
auto operator>=(const self_t& rhs) const noexcept
{
return _iter >= rhs._iter;
}
self_t operator+(difference_type d) const noexcept
{
return _iter + d;
}
self_t operator-(difference_type d) const noexcept
{
return _iter - d;
}
auto operator-(const self_t& rhs) const noexcept
{
return _iter - rhs._iter;
}
self_t& operator+=(difference_type d)
{
_iter += d;
return *this;
}
self_t& operator-=(difference_type d)
{
_iter -= d;
return *this;
}
operator wrapped&()
{
return _iter;
}
operator const wrapped&() const
{
return _iter;
}
wrapped& data()
{
return _iter;
}
const wrapped& data() const
{
return _iter;
}
private:
wrapped _iter;
};
template<typename Iter>
auto operator+(typename double_iterator<Iter>::difference_type diff, double_iterator<Iter> iter)
{
return iter + diff;
}
/// To avoid clients being moved, they are stored in unique_ptrs, which are
/// moved around in a vector. This class is purely for convenience, to still
/// have iterator semantics, and a few other utility functions
template<typename T>
struct ptr_vec {
using value_type = T;
std::vector<std::unique_ptr<value_type>> _order;
using iterator = double_iterator<typename decltype(_order)::iterator>;
using const_iterator = double_iterator<typename decltype(_order)::const_iterator>;
using reverse_iterator = double_iterator<typename decltype(_order)::reverse_iterator>;
using const_reverse_iterator =
double_iterator<typename decltype(_order)::const_reverse_iterator>;
value_type& push_back(const value_type& v)
{
auto ptr = std::make_unique<value_type>(v);
auto res = ptr.get();
_order.push_back(std::move(ptr));
return *res;
}
value_type& push_back(value_type&& v)
{
auto ptr = std::make_unique<value_type>(std::move(v));
auto res = ptr.get();
_order.push_back(std::move(ptr));
return *res;
}
value_type& push_back(std::unique_ptr<value_type> ptr)
{
auto res = ptr.get();
_order.push_back(std::move(ptr));
return *res;
}
template<typename... Args>
value_type& emplace_back(Args&&... args)
{
return push_back(std::make_unique<value_type>(std::forward<Args>(args)...));
}
std::unique_ptr<value_type> erase(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
if (iter != _order.end()) {
auto uptr = std::move(*iter);
_order.erase(iter);
return uptr;
}
return nullptr;
}
iterator rotate_to_back(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
return rotate_to_back(iter);
}
iterator rotate_to_back(iterator iter)
{
if (iter != _order.end()) {
{
return std::rotate(iter.data(), iter.data() + 1, _order.end());
}
}
return end();
}
iterator rotate_to_front(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& uptr) { return uptr.get() == &v; });
return rotate_to_front(iter);
}
iterator rotate_to_front(iterator iter)
{
if (iter != _order.end()) {
{
return std::rotate(_order.begin(), iter.data(), iter.data() + 1);
}
}
return end();
}
std::size_t size() const noexcept
{
return _order.size();
}
bool empty() const noexcept
{
return _order.empty();
}
std::size_t capacity() const noexcept
{
return _order.capacity();
}
std::size_t max_size() const noexcept
{
return _order.max_size();
}
void reserve(std::size_t new_cap)
{
_order.reserve(new_cap);
}
void shrink_to_fit()
{
_order.shrink_to_fit();
}
value_type& operator[](std::size_t n)
{
return *_order[n];
}
const value_type& operator[](std::size_t n) const
{
return *_order[n];
}
value_type& at(std::size_t n)
{
return *_order.at(n);
}
const value_type& at(std::size_t n) const
{
return *_order.at(n);
}
iterator begin()
{
return _order.begin();
}
iterator end()
{
return _order.end();
}
const_iterator begin() const
{
return _order.begin();
}
const_iterator end() const
{
return _order.end();
}
reverse_iterator rbegin()
{
return _order.rbegin();
}
reverse_iterator rend()
{
return _order.rend();
}
const_reverse_iterator rbegin() const
{
return _order.rbegin();
}
const_reverse_iterator rend() const
{
return _order.rend();
}
value_type& front()
{
return *_order.front();
}
value_type& back()
{
return *_order.back();
}
const value_type& front() const
{
return *_order.front();
}
const value_type& back() const
{
return *_order.back();
}
std::vector<std::unique_ptr<value_type>>& underlying() {
return _order;
}
};
template<typename T, typename T2>
std::unique_ptr<T> erase_this(ptr_vec<T>& vec, T2* el)
{
return vec.erase(*el);
}
template<typename T, typename T2>
std::unique_ptr<T> erase_this(ptr_vec<T>& vec, T2& el)
{
return vec.erase(el);
}
template<typename T>
struct non_null_ptr {
non_null_ptr() = delete;
constexpr non_null_ptr(T* ptr) : _ptr(ptr)
{
assert(ptr != nullptr);
}
non_null_ptr(std::nullptr_t) = delete;
constexpr non_null_ptr(const non_null_ptr&) = default;
constexpr non_null_ptr(non_null_ptr&&) = default;
constexpr non_null_ptr& operator=(const non_null_ptr&) = default;
constexpr non_null_ptr& operator=(non_null_ptr&&) = default;
constexpr T& operator*() const noexcept
{
return *_ptr;
}
constexpr T* operator->() const noexcept
{
return _ptr;
}
constexpr operator T*() noexcept
{
return _ptr;
}
constexpr operator T* const() const noexcept
{
return _ptr;
}
private:
T* _ptr;
};
template<typename T>
struct ref_vec {
using value_type = T;
std::vector<value_type*> _order;
using iterator = double_iterator<typename decltype(_order)::iterator>;
using const_iterator = double_iterator<typename decltype(_order)::const_iterator>;
using reverse_iterator = double_iterator<typename decltype(_order)::reverse_iterator>;
using const_reverse_iterator =
double_iterator<typename decltype(_order)::const_reverse_iterator>;
ref_vec() = default;
ref_vec(std::initializer_list<value_type*> lst) : _order {lst} { };
template<typename InputIter, typename = std::enable_if_t<std::is_same_v<decltype(*std::declval<InputIter>()), value_type&>>>
ref_vec(InputIter iter1, InputIter iter2) {
_order.reserve(std::distance(iter1, iter2));
std::transform(iter1, iter2, std::back_inserter(_order), [] (auto& v) {return &v; });
}
template<typename Range, typename = std::enable_if_t<std::is_same_v<decltype(*std::declval<Range>().begin()), value_type&>>>
ref_vec(Range&& rng) : ref_vec (std::begin(rng), std::end(rng)) { }
value_type& push_back(value_type& v)
{
_order.push_back(&v);
return v;
}
value_type& push_back(non_null_ptr<value_type> ptr)
{
_order.push_back(ptr);
return *ptr;
}
value_type& emplace_back(value_type& v)
{
return push_back(v);
}
std::unique_ptr<value_type> erase(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
if (iter != _order.end()) {
auto uptr = std::move(*iter);
_order.erase(iter);
return uptr;
}
return nullptr;
}
iterator rotate_to_back(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
return rotate_to_back(iter);
}
iterator rotate_to_back(iterator iter)
{
if (iter != _order.end()) {
{
return std::rotate(iter.data(), iter.data() + 1, _order.end());
}
}
return end();
}
iterator rotate_to_front(const value_type& v)
{
auto iter =
std::find_if(_order.begin(), _order.end(), [&v](auto&& ptr) { return ptr == &v; });
return rotate_to_front(iter);
}
iterator rotate_to_front(iterator iter)
{
if (iter != _order.end()) {
{
return std::rotate(_order.begin(), iter.data(), iter.data() + 1);
}
}
return end();
}
std::size_t size() const noexcept
{
return _order.size();
}
bool empty() const noexcept
{
return _order.empty();
}
std::size_t capacity() const noexcept
{
return _order.capacity();
}
std::size_t max_size() const noexcept
{
return _order.max_size();
}
void reserve(std::size_t new_cap)
{
_order.reserve(new_cap);
}
void shrink_to_fit()
{
_order.shrink_to_fit();
}
value_type& operator[](std::size_t n)
{
return *_order[n];
}
const value_type& operator[](std::size_t n) const
{
return *_order[n];
}
value_type& at(std::size_t n)
{
return *_order.at(n);
}
const value_type& at(std::size_t n) const
{
return *_order.at(n);
}
iterator begin()
{
return _order.begin();
}
iterator end()
{
return _order.end();
}
const_iterator begin() const
{
return _order.begin();
}
const_iterator end() const
{
return _order.end();
}
reverse_iterator rbegin()
{
return _order.rbegin();
}
reverse_iterator rend()
{
return _order.rend();
}
const_reverse_iterator rbegin() const
{
return _order.rbegin();
}
const_reverse_iterator rend() const
{
return _order.rend();
}
value_type& front()
{
return *_order.front();
}
value_type& back()
{
return *_order.back();
}
const value_type& front() const
{
return *_order.front();
}
const value_type& back() const
{
return *_order.back();
}
std::vector<value_type*>& underlying() {
return _order;
}
};
} // namespace waybar::util