Refactor some iterator template code in RGBGFX pal_packing.cpp

This commit is contained in:
Rangi42
2025-09-21 10:54:27 -04:00
parent 3ece61b103
commit c8d22d8744

View File

@@ -68,23 +68,27 @@ public:
: _assigned{attrs}, _colorSets{&colorSets} {} : _assigned{attrs}, _colorSets{&colorSets} {}
private: private:
template<typename Inner, template<typename> typename Constness> // Template class for both const and non-const iterators over the non-empty `_assigned` slots
class Iter { template<typename I, template<typename> typename Constness>
class AssignedSetsIter {
public: public:
friend class AssignedSets; friend class AssignedSets;
// For `iterator_traits` // For `iterator_traits`
using difference_type = typename std::iterator_traits<Inner>::difference_type;
using value_type = ColorSetAttrs; using value_type = ColorSetAttrs;
using pointer = Constness<value_type> *; using difference_type = ptrdiff_t;
using reference = Constness<value_type> &; using reference = Constness<value_type> &;
using pointer = Constness<value_type> *;
using iterator_category = std::forward_iterator_tag; using iterator_category = std::forward_iterator_tag;
private: private:
Constness<decltype(_assigned)> *_array = nullptr; Constness<decltype(_assigned)> *_array = nullptr;
Inner _iter{}; I _iter{};
Iter(decltype(_array) array, decltype(_iter) &&iter) : _array(array), _iter(iter) {} AssignedSetsIter(decltype(_array) array, decltype(_iter) &&iter)
Iter &skipEmpty() { : _array(array), _iter(iter) {}
AssignedSetsIter &skipEmpty() {
while (_iter != _array->end() && !_iter->has_value()) { while (_iter != _array->end() && !_iter->has_value()) {
++_iter; ++_iter;
} }
@@ -92,17 +96,17 @@ private:
} }
public: public:
Iter() = default; AssignedSetsIter() = default;
bool operator==(Iter const &rhs) const { return _iter == rhs._iter; } bool operator==(AssignedSetsIter const &rhs) const { return _iter == rhs._iter; }
Iter &operator++() { AssignedSetsIter &operator++() {
++_iter; ++_iter;
skipEmpty(); skipEmpty();
return *this; return *this;
} }
Iter operator++(int) { AssignedSetsIter operator++(int) {
Iter it = *this; AssignedSetsIter it = *this;
++(*this); ++(*this);
return it; return it;
} }
@@ -115,18 +119,18 @@ private:
return &(**this); // Invokes the operator above, not quite a no-op! return &(**this); // Invokes the operator above, not quite a no-op!
} }
friend void swap(Iter &lhs, Iter &rhs) { friend void swap(AssignedSetsIter &lhs, AssignedSetsIter &rhs) {
std::swap(lhs._array, rhs._array); std::swap(lhs._array, rhs._array);
std::swap(lhs._iter, rhs._iter); std::swap(lhs._iter, rhs._iter);
} }
}; };
public: public:
using iterator = Iter<decltype(_assigned)::iterator, std::remove_const_t>; using iterator = AssignedSetsIter<decltype(_assigned)::iterator, std::remove_const_t>;
iterator begin() { return iterator{&_assigned, _assigned.begin()}.skipEmpty(); } iterator begin() { return iterator{&_assigned, _assigned.begin()}.skipEmpty(); }
iterator end() { return iterator{&_assigned, _assigned.end()}; } iterator end() { return iterator{&_assigned, _assigned.end()}; }
using const_iterator = Iter<decltype(_assigned)::const_iterator, std::add_const_t>; using const_iterator = AssignedSetsIter<decltype(_assigned)::const_iterator, std::add_const_t>;
const_iterator begin() const { const_iterator begin() const {
return const_iterator{&_assigned, _assigned.begin()}.skipEmpty(); return const_iterator{&_assigned, _assigned.begin()}.skipEmpty();
} }
@@ -151,20 +155,19 @@ public:
void clear() { _assigned.clear(); } void clear() { _assigned.clear(); }
bool empty() const { bool empty() const {
return std::find_if( return std::none_of(RANGE(_assigned), [](std::optional<ColorSetAttrs> const &slot) {
RANGE(_assigned), return slot.has_value();
[](std::optional<ColorSetAttrs> const &slot) { return slot.has_value(); } });
)
== _assigned.end();
} }
size_t nbColorSets() const { return std::distance(RANGE(*this)); } size_t nbColorSets() const { return std::distance(RANGE(*this)); }
private: private:
template<typename Iter> template<typename I>
static void addUniqueColors( static void addUniqueColors(
std::unordered_set<uint16_t> &colors, std::unordered_set<uint16_t> &colors,
Iter iter, I iter,
Iter const &end, I const &end,
std::vector<ColorSet> const &colorSets std::vector<ColorSet> const &colorSets
) { ) {
for (; iter != end; ++iter) { for (; iter != end; ++iter) {
@@ -236,19 +239,18 @@ public:
} }
// Computes the "relative size" of a set of color sets on this palette // Computes the "relative size" of a set of color sets on this palette
template<typename Iter> template<typename I>
size_t combinedVolume(Iter &&begin, Iter const &end, std::vector<ColorSet> const &colorSets) size_t combinedVolume(I &&begin, I const &end, std::vector<ColorSet> const &colorSets) const {
const {
std::unordered_set<uint16_t> &colors = uniqueColors(); std::unordered_set<uint16_t> &colors = uniqueColors();
addUniqueColors(colors, std::forward<Iter>(begin), end, colorSets); addUniqueColors(colors, std::forward<I>(begin), end, colorSets);
return colors.size(); return colors.size();
} }
// Computes the "relative size" of a set of colors on this palette // Computes the "relative size" of a set of colors on this palette
template<typename Iter> template<typename I>
size_t combinedVolume(Iter &&begin, Iter &&end) const { size_t combinedVolume(I &&begin, I &&end) const {
std::unordered_set<uint16_t> &colors = uniqueColors(); std::unordered_set<uint16_t> &colors = uniqueColors();
colors.insert(std::forward<Iter>(begin), std::forward<Iter>(end)); colors.insert(std::forward<I>(begin), std::forward<I>(end));
return colors.size(); return colors.size();
} }
}; };
@@ -321,23 +323,23 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
// We do this by adding the first available color set, and then looking for palettes with // We do this by adding the first available color set, and then looking for palettes with
// common colors. (As an optimization, we know we can skip palettes already scanned.) // common colors. (As an optimization, we know we can skip palettes already scanned.)
std::vector<bool> processed(from.nbColorSets(), false); std::vector<bool> processed(from.nbColorSets(), false);
for (std::vector<bool>::iterator iter; for (std::vector<bool>::iterator wasProcessed;
(iter = std::find(RANGE(processed), false)) != processed.end();) { (wasProcessed = std::find(RANGE(processed), false)) != processed.end();) {
auto attrs = from.begin(); auto attrs = from.begin();
std::advance(attrs, iter - processed.begin()); std::advance(attrs, wasProcessed - processed.begin());
std::unordered_set<uint16_t> colors(RANGE(colorSets[attrs->colorSetIndex])); std::unordered_set<uint16_t> colors(RANGE(colorSets[attrs->colorSetIndex]));
std::vector<size_t> members = {static_cast<size_t>(iter - processed.begin())}; std::vector<size_t> members = {static_cast<size_t>(wasProcessed - processed.begin())};
*iter = true; // Mark the first color set as processed *wasProcessed = true; // Mark the first color set as processed
// Build up the "component"... // Build up the "component"...
for (; ++iter != processed.end(); ++attrs) { for (; ++wasProcessed != processed.end(); ++attrs) {
// If at least one color matches, add it // If at least one color matches, add it
if (ColorSet const &colorSet = colorSets[attrs->colorSetIndex]; if (ColorSet const &colorSet = colorSets[attrs->colorSetIndex];
std::find_first_of(RANGE(colors), RANGE(colorSet)) != colors.end()) { std::find_first_of(RANGE(colors), RANGE(colorSet)) != colors.end()) {
colors.insert(RANGE(colorSet)); colors.insert(RANGE(colorSet));
members.push_back(iter - processed.begin()); members.push_back(wasProcessed - processed.begin());
*iter = true; // Mark that color set as processed *wasProcessed = true; // Mark that color set as processed
} }
} }
@@ -362,10 +364,10 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
// Decant on individual color sets // Decant on individual color sets
decantOn([&colorSets](AssignedSets &to, AssignedSets &from) { decantOn([&colorSets](AssignedSets &to, AssignedSets &from) {
for (auto iter = from.begin(); iter != from.end(); ++iter) { for (auto it = from.begin(); it != from.end(); ++it) {
if (to.canFit(colorSets[iter->colorSetIndex])) { if (to.canFit(colorSets[it->colorSetIndex])) {
to.assign(std::move(*iter)); to.assign(std::move(*it));
from.remove(iter); from.remove(it);
} }
} }
}); });
@@ -530,10 +532,10 @@ std::pair<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet> c
// Place back any color sets now in the queue via first-fit // Place back any color sets now in the queue via first-fit
for (ColorSetAttrs const &attrs : overloadQueue) { for (ColorSetAttrs const &attrs : overloadQueue) {
ColorSet const &colorSet = colorSets[attrs.colorSetIndex]; ColorSet const &colorSet = colorSets[attrs.colorSetIndex];
auto iter = std::find_if(RANGE(assignments), [&colorSet](AssignedSets const &pal) { auto palette = std::find_if(RANGE(assignments), [&colorSet](AssignedSets const &pal) {
return pal.canFit(colorSet); return pal.canFit(colorSet);
}); });
if (iter == assignments.end()) { // No such page, create a new one if (palette == assignments.end()) { // No such page, create a new one
verbosePrint( verbosePrint(
VERB_DEBUG, VERB_DEBUG,
"Adding new palette (%zu) for overflowing color set %zu\n", "Adding new palette (%zu) for overflowing color set %zu\n",
@@ -546,9 +548,9 @@ std::pair<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet> c
VERB_DEBUG, VERB_DEBUG,
"Assigning overflowing color set %zu to palette %zu\n", "Assigning overflowing color set %zu to palette %zu\n",
attrs.colorSetIndex, attrs.colorSetIndex,
iter - assignments.begin() palette - assignments.begin()
); );
iter->assign(std::move(attrs)); palette->assign(std::move(attrs));
} }
} }