quickshell/src/core/stacklist.hpp

173 lines
4.8 KiB
C++

#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <vector>
#include <qlist.h>
#include <qtypes.h>
template <class T, size_t N>
class StackList {
public:
T& operator[](size_t i) {
if (i < N) {
return this->array[i];
} else {
return this->vec[i - N];
}
}
const T& operator[](size_t i) const {
return const_cast<StackList<T, N>*>(this)->operator[](i); // NOLINT
}
void push(const T& value) {
if (this->size < N) {
this->array[this->size] = value;
} else {
this->vec.push_back(value);
}
++this->size;
}
[[nodiscard]] size_t length() const { return this->size; }
[[nodiscard]] bool isEmpty() const { return this->size == 0; }
[[nodiscard]] bool operator==(const StackList<T, N>& other) const {
if (other.size != this->size) return false;
for (size_t i = 0; i != this->size; ++i) {
if (this->operator[](i) != other[i]) return false;
}
return true;
}
[[nodiscard]] QList<T> toList() const {
QList<T> list;
list.reserve(this->size);
for (const auto& entry: *this) {
list.push_back(entry);
}
return list;
}
template <typename Self, typename ListPtr, typename IT>
struct BaseIterator {
using iterator_category = std::bidirectional_iterator_tag;
using difference_type = int64_t;
using value_type = IT;
using pointer = IT*;
using reference = IT&;
BaseIterator() = default;
explicit BaseIterator(ListPtr list, size_t i): list(list), i(i) {}
reference operator*() const { return this->list->operator[](this->i); }
pointer operator->() const { return &**this; }
Self& operator++() {
++this->i;
return *static_cast<Self*>(this);
}
Self& operator--() {
--this->i;
return *static_cast<Self*>(this);
}
Self operator++(int) {
auto v = *this;
this->operator++();
return v;
}
Self operator--(int) {
auto v = *this;
this->operator--();
return v;
}
difference_type operator-(const Self& other) {
return static_cast<int64_t>(this->i) - static_cast<int64_t>(other.i);
}
Self& operator+(difference_type offset) {
return Self(this->list, static_cast<int64_t>(this->i) + offset);
}
[[nodiscard]] bool operator==(const Self& other) const {
return this->list == other.list && this->i == other.i;
}
[[nodiscard]] bool operator!=(const Self& other) const { return !(*this == other); }
private:
ListPtr list = nullptr;
size_t i = 0;
};
struct Iterator: public BaseIterator<Iterator, StackList<T, N>*, T> {
Iterator() = default;
Iterator(StackList<T, N>* list, size_t i)
: BaseIterator<Iterator, StackList<T, N>*, T>(list, i) {}
};
struct ConstIterator: public BaseIterator<ConstIterator, const StackList<T, N>*, const T> {
ConstIterator() = default;
ConstIterator(const StackList<T, N>* list, size_t i)
: BaseIterator<ConstIterator, const StackList<T, N>*, const T>(list, i) {}
};
[[nodiscard]] Iterator begin() { return Iterator(this, 0); }
[[nodiscard]] Iterator end() { return Iterator(this, this->size); }
[[nodiscard]] ConstIterator begin() const { return ConstIterator(this, 0); }
[[nodiscard]] ConstIterator end() const { return ConstIterator(this, this->size); }
[[nodiscard]] bool isContiguous() const { return this->vec.empty(); }
[[nodiscard]] const T* pArray() const { return this->array.data(); }
[[nodiscard]] size_t dataLength() const { return this->size * sizeof(T); }
const T* populateAlloc(void* alloc) const {
auto arraylen = std::min(this->size, N) * sizeof(T);
memcpy(alloc, this->array.data(), arraylen);
if (!this->vec.empty()) {
memcpy(
static_cast<char*>(alloc) + arraylen, // NOLINT
this->vec.data(),
this->vec.size() * sizeof(T)
);
}
return static_cast<T*>(alloc);
}
private:
std::array<T, N> array {};
std::vector<T> vec;
size_t size = 0;
};
// might be incorrectly aligned depending on type
// #define STACKLIST_ALLOCA_VIEW(list) ((list).isContiguous() ? (list).pArray() : (list).populateAlloc(alloca((list).dataLength())))
// NOLINTBEGIN
#define STACKLIST_VLA_VIEW(type, list, var) \
const type* var; \
type var##Data[(list).length()]; \
if ((list).isContiguous()) { \
(var) = (list).pArray(); \
} else { \
(list).populateAlloc(var##Data); \
(var) = var##Data; \
}
// NOLINTEND