diff --git a/src/gfx/pal_packing.cpp b/src/gfx/pal_packing.cpp index 9fecbd38..b3376f45 100644 --- a/src/gfx/pal_packing.cpp +++ b/src/gfx/pal_packing.cpp @@ -136,6 +136,8 @@ public: } const_iterator end() const { return const_iterator{&_assigned, _assigned.end()}; } + iterator slotAt(size_t index) { return iterator{&_assigned, _assigned.begin() + index}; } + void assign(ColorSetAttrs const &&attrs) { auto freeSlot = std::find_if_not(RANGE(_assigned), [](std::optional const &slot) { @@ -160,7 +162,9 @@ public: }); } - size_t nbColorSets() const { return std::distance(RANGE(*this)); } + size_t nbSlots() const { return _assigned.size(); } + + bool isFree(size_t slotIndex) const { return !_assigned[slotIndex].has_value(); } private: template @@ -318,24 +322,30 @@ static void decant(std::vector &assignments, std::vector decantOn([&colorSets](AssignedSets &to, AssignedSets &from) { // We need to iterate on all the "components", which are groups of color sets sharing at // least one color with another color set in the group. - // 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.) - std::vector processed(from.nbColorSets(), false); - for (std::vector::iterator wasProcessed; - (wasProcessed = std::find(RANGE(processed), false)) != processed.end();) { - auto attrs = from.begin(); - std::advance(attrs, wasProcessed - processed.begin()); + // We do this by adding the first free color set, and then looking for palettes with + // common colors. (As an optimization, we know we can skip palettes already processed.) + std::vector processed(from.nbSlots(), false); + for (size_t startIdx = 0; startIdx < processed.size(); ++startIdx) { + if (processed[startIdx] || from.isFree(startIdx)) { + continue; + } + size_t startColorSetIdx = from.slotAt(startIdx)->colorSetIndex; // Build up the "component"; start by marking the first color set as processed - std::unordered_set colors(RANGE(colorSets[attrs->colorSetIndex])); - std::vector members = {static_cast(wasProcessed - processed.begin())}; - for (*wasProcessed = true; ++wasProcessed != processed.end(); ++attrs) { + std::unordered_set colors(RANGE(colorSets[startColorSetIdx])); + std::vector members = {startIdx}; + processed[startIdx] = true; + for (size_t nextIdx = startIdx + 1; nextIdx < processed.size(); ++nextIdx) { + if (processed[nextIdx] || from.isFree(nextIdx)) { + continue; + } + size_t nextColorSetIdx = from.slotAt(nextIdx)->colorSetIndex; // If at least one color matches, add it - if (ColorSet const &colorSet = colorSets[attrs->colorSetIndex]; + if (ColorSet const &colorSet = colorSets[nextColorSetIdx]; std::find_first_of(RANGE(colors), RANGE(colorSet)) != colors.end()) { colors.insert(RANGE(colorSet)); - members.push_back(wasProcessed - processed.begin()); - *wasProcessed = true; // Mark the added color set as processed + members.push_back(nextIdx); + processed[nextIdx] = true; // Mark the added color set as processed } } @@ -344,11 +354,8 @@ static void decant(std::vector &assignments, std::vector } // Iterate through the component's color sets, and transfer them - auto member = from.begin(); - size_t curIndex = 0; for (size_t index : members) { - std::advance(member, index - curIndex); - curIndex = index; + auto member = from.slotAt(index); to.assign(std::move(*member)); from.remove(member); // Removing does not shift elements, so it's cheap }