#pragma once #include "glContainer.h" #include #include #include template class InstanceVertices : protected glContainer { using base = glContainer; public: class [[nodiscard]] InstanceProxy { public: InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { } InstanceProxy(InstanceProxy && other) noexcept : instances {std::exchange(other.instances, nullptr)}, index {other.index} { } NO_COPY(InstanceProxy); ~InstanceProxy() { if (instances) { instances->release(index); } } InstanceProxy & operator=(InstanceProxy && other) noexcept { if (instances) { instances->release(index); } instances = std::exchange(other.instances, nullptr); index = other.index; return *this; } template InstanceProxy & operator=(U && v) { instances->lookup(index) = std::forward(v); return *this; } // NOLINTNEXTLINE)hicpp-explicit-conversions [[nodiscard]] operator T &() { return instances->lookup(index); } // NOLINTNEXTLINE)hicpp-explicit-conversions [[nodiscard]] operator const T &() const { return instances->lookup(index); } [[nodiscard]] T * get() { return &instances->lookup(index); } [[nodiscard]] const T * get() const { return &instances->lookup(index); } [[nodiscard]] T * operator->() { return get(); } [[nodiscard]] const T * operator->() const { return get(); } [[nodiscard]] T & operator*() { return instances->lookup(index); } [[nodiscard]] const T & operator*() const { return instances->lookup(index); } private: InstanceVertices * instances; std::size_t index; }; template [[nodiscard]] InstanceProxy acquire(Params &&... params) { if (!unused.empty()) { auto idx = unused.back(); unused.pop_back(); index[idx] = base::size(); reverseIndex.emplace_back(idx); base::emplace_back(std::forward(params)...); return InstanceProxy {this, idx}; } index.emplace_back(base::size()); reverseIndex.push_back(base::size()); base::emplace_back(std::forward(params)...); return InstanceProxy {this, index.size() - 1}; } using base::bufferName; [[nodiscard]] auto size() const { base::unmap(); return base::size(); } template glContainer::iterator partition(Pred pred) { return partition(base::begin(), base::end(), pred); } protected: static constexpr auto npos = static_cast(-1); friend InstanceProxy; void release(const size_t pidx) { if (const size_t last = base::size() - 1; last != index[pidx]) { lookup(pidx) = std::move(base::back()); const auto movedKey = reverseIndex[last]; index[movedKey] = std::exchange(index[pidx], npos); reverseIndex[index[movedKey]] = movedKey; } base::pop_back(); reverseIndex.pop_back(); if (pidx == index.size() - 1) { index.pop_back(); } else { index[pidx] = npos; // Remember p.index is free index now unused.emplace_back(pidx); } } [[nodiscard]] T & lookup(size_t pindex) { return base::data()[index[pindex]]; } template glContainer::iterator partition(glContainer::iterator first, glContainer::iterator last, Pred pred) { while (first < last) { first = std::find_if_not(first, last, pred); last = --std::find_if(std::make_reverse_iterator(last), std::make_reverse_iterator(first), pred).base(); if (first < last) { std::iter_swap(first, last); const auto fidx = static_cast(first - base::begin()), lidx = static_cast(last - base::begin()); std::swap(index[reverseIndex[fidx]], index[reverseIndex[lidx]]); std::swap(reverseIndex[fidx], reverseIndex[lidx]); } } return first; } // Index into buffer given to nth proxy std::vector index; std::vector reverseIndex; // List of free spaces in index std::vector unused; };