Simplify some C++ abstractions (#1518)

* Remove namespaces
* Prefer `bool operator==`, not `friend auto operator==`
* Prefer not to use `using`
* Use a `constexpr` function instead of a template for `flipTable`
This commit is contained in:
Sylvie
2024-09-26 00:07:27 -04:00
committed by GitHub
parent 8037b9e10a
commit 9783671399
11 changed files with 80 additions and 124 deletions

View File

@@ -107,20 +107,18 @@ struct Palette {
uint8_t size() const; uint8_t size() const;
}; };
namespace detail { // Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
template<typename T, T... i> static constexpr auto flipTable = ([]() constexpr {
static constexpr auto flipTable(std::integer_sequence<T, i...>) { std::array<uint16_t, 256> table{};
return std::array{[](uint8_t byte) { for (uint16_t i = 0; i < table.size(); i++) {
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc. // To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
uint16_t byte = i;
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4; byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2; byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1; byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
return byte; table[i] = byte;
}(i)...}; }
} return table;
} // namespace detail })();
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
static constexpr auto flipTable = detail::flipTable(std::make_integer_sequence<uint16_t, 256>());
#endif // RGBDS_GFX_MAIN_HPP #endif // RGBDS_GFX_MAIN_HPP

View File

@@ -6,19 +6,15 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitvec.hpp"
struct Palette; struct Palette;
class ProtoPalette; class ProtoPalette;
namespace packing {
/* /*
* Returns which palette each proto-palette maps to, and how many palettes are necessary * Returns which palette each proto-palette maps to, and how many palettes are necessary
*/ */
std::tuple<DefaultInitVec<size_t>, size_t> std::tuple<DefaultInitVec<size_t>, size_t>
overloadAndRemove(std::vector<ProtoPalette> const &protoPalettes); overloadAndRemove(std::vector<ProtoPalette> const &protoPalettes);
} // namespace packing
#endif // RGBDS_GFX_PAL_PACKING_HPP #endif // RGBDS_GFX_PAL_PACKING_HPP

View File

@@ -12,20 +12,16 @@
struct Palette; struct Palette;
namespace sorting { void sortIndexed(
void indexed(
std::vector<Palette> &palettes, std::vector<Palette> &palettes,
int palSize, int palSize,
png_color const *palRGB, png_color const *palRGB,
int palAlphaSize, int palAlphaSize,
png_byte *palAlpha png_byte *palAlpha
); );
void grayscale( void sortGrayscale(
std::vector<Palette> &palettes, std::array<std::optional<Rgba>, 0x8001> const &colors std::vector<Palette> &palettes, std::array<std::optional<Rgba>, 0x8001> const &colors
); );
void rgb(std::vector<Palette> &palettes); void sortRgb(std::vector<Palette> &palettes);
} // namespace sorting
#endif // RGBDS_GFX_PAL_SORTING_HPP #endif // RGBDS_GFX_PAL_SORTING_HPP

View File

@@ -40,8 +40,8 @@ struct Rgba {
auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; }; auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; };
return shl(red, 24) | shl(green, 16) | shl(blue, 8) | shl(alpha, 0); return shl(red, 24) | shl(green, 16) | shl(blue, 8) | shl(alpha, 0);
} }
friend bool operator==(Rgba const &lhs, Rgba const &rhs) { return lhs.toCSS() == rhs.toCSS(); } bool operator==(Rgba const &rhs) const { return toCSS() == rhs.toCSS(); }
friend bool operator!=(Rgba const &lhs, Rgba const &rhs) { return lhs.toCSS() != rhs.toCSS(); } bool operator!=(Rgba const &rhs) const { return toCSS() != rhs.toCSS(); }
/* /*
* CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead * CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead

View File

@@ -7,51 +7,45 @@
#include <utility> #include <utility>
template<typename T> template<typename T>
class EnumSeqIterator { class EnumSeq {
T _start;
T _stop;
class Iterator {
T _value; T _value;
public: public:
explicit EnumSeqIterator(T value) : _value(value) {} explicit Iterator(T value) : _value(value) {}
EnumSeqIterator &operator++() { Iterator &operator++() {
_value = (T)(_value + 1); _value = (T)(_value + 1);
return *this; return *this;
} }
auto operator*() const { return _value; } auto operator*() const { return _value; }
friend auto operator==(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) { bool operator==(Iterator const &rhs) const { return _value == rhs._value; }
return lhs._value == rhs._value; bool operator!=(Iterator const &rhs) const { return _value != rhs._value; }
} };
friend auto operator!=(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) {
return lhs._value != rhs._value;
}
};
template<typename T>
class EnumSeq {
T _start;
T _stop;
public: public:
explicit EnumSeq(T stop) : _start((T)0), _stop(stop) {} explicit EnumSeq(T stop) : _start((T)0), _stop(stop) {}
explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {} explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {}
EnumSeqIterator<T> begin() { return EnumSeqIterator(_start); } Iterator begin() { return Iterator(_start); }
EnumSeqIterator<T> end() { return EnumSeqIterator(_stop); } Iterator end() { return Iterator(_stop); }
}; };
// This is not a fully generic implementation; its current use cases only require for-loop behavior. // This is not a fully generic implementation; its current use cases only require for-loop behavior.
// We also assume that all iterators have the same length. // We also assume that all iterators have the same length.
template<typename... Iters> template<typename... Ts>
class Zip { class ZipIterator {
std::tuple<Iters...> _iters; std::tuple<Ts...> _iters;
public: public:
explicit Zip(std::tuple<Iters...> &&iters) : _iters(iters) {} explicit ZipIterator(std::tuple<Ts...> &&iters) : _iters(iters) {}
Zip &operator++() { ZipIterator &operator++() {
std::apply([](auto &&...it) { (++it, ...); }, _iters); std::apply([](auto &&...it) { (++it, ...); }, _iters);
return *this; return *this;
} }
@@ -62,26 +56,24 @@ public:
); );
} }
friend auto operator==(Zip const &lhs, Zip const &rhs) { bool operator==(ZipIterator const &rhs) const {
return std::get<0>(lhs._iters) == std::get<0>(rhs._iters); return std::get<0>(_iters) == std::get<0>(rhs._iters);
} }
friend auto operator!=(Zip const &lhs, Zip const &rhs) { bool operator!=(ZipIterator const &rhs) const {
return std::get<0>(lhs._iters) != std::get<0>(rhs._iters); return std::get<0>(_iters) != std::get<0>(rhs._iters);
} }
}; };
namespace detail { template<typename... Ts>
template<typename... Containers>
class ZipContainer { class ZipContainer {
std::tuple<Containers...> _containers; std::tuple<Ts...> _containers;
public: public:
explicit ZipContainer(Containers &&...containers) explicit ZipContainer(Ts &&...containers) : _containers(std::forward<Ts>(containers)...) {}
: _containers(std::forward<Containers>(containers)...) {}
auto begin() { auto begin() {
return Zip(std::apply( return ZipIterator(std::apply(
[](auto &&...containers) { [](auto &&...containers) {
using std::begin; using std::begin;
return std::make_tuple(begin(containers)...); return std::make_tuple(begin(containers)...);
@@ -91,7 +83,7 @@ public:
} }
auto end() { auto end() {
return Zip(std::apply( return ZipIterator(std::apply(
[](auto &&...containers) { [](auto &&...containers) {
using std::end; using std::end;
return std::make_tuple(end(containers)...); return std::make_tuple(end(containers)...);
@@ -105,12 +97,11 @@ public:
template<typename T> template<typename T>
using Holder = std:: using Holder = std::
conditional_t<std::is_lvalue_reference_v<T>, T, std::remove_cv_t<std::remove_reference_t<T>>>; conditional_t<std::is_lvalue_reference_v<T>, T, std::remove_cv_t<std::remove_reference_t<T>>>;
} // namespace detail
// Does the same number of iterations as the first container's iterator! // Does the same number of iterations as the first container's iterator!
template<typename... Containers> template<typename... Ts>
static constexpr auto zip(Containers &&...cs) { static constexpr auto zip(Ts &&...cs) {
return detail::ZipContainer<detail::Holder<Containers>...>(std::forward<Containers>(cs)...); return ZipContainer<Holder<Ts>...>(std::forward<Ts>(cs)...);
} }
#endif // RGBDS_ITERTOOLS_HPP #endif // RGBDS_ITERTOOLS_HPP

View File

@@ -15,10 +15,6 @@
#include "gfx/main.hpp" #include "gfx/main.hpp"
#include "gfx/proto_palette.hpp" #include "gfx/proto_palette.hpp"
using std::swap;
namespace packing {
// The solvers here are picked from the paper at https://arxiv.org/abs/1605.00558: // The solvers here are picked from the paper at https://arxiv.org/abs/1605.00558:
// "Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items" // "Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items"
// Their formulation of the problem consists in packing "tiles" into "pages"; here is a // Their formulation of the problem consists in packing "tiles" into "pages"; here is a
@@ -114,8 +110,8 @@ private:
} }
friend void swap(Iter &lhs, Iter &rhs) { friend void swap(Iter &lhs, Iter &rhs) {
swap(lhs._array, rhs._array); std::swap(lhs._array, rhs._array);
swap(lhs._iter, rhs._iter); std::swap(lhs._iter, rhs._iter);
} }
}; };
public: public:
@@ -537,5 +533,3 @@ std::tuple<DefaultInitVec<size_t>, size_t>
} }
return {mappings, assignments.size()}; return {mappings, assignments.size()};
} }
} // namespace packing

View File

@@ -8,9 +8,7 @@
#include "gfx/main.hpp" #include "gfx/main.hpp"
namespace sorting { void sortIndexed(
void indexed(
std::vector<Palette> &palettes, std::vector<Palette> &palettes,
int palSize, int palSize,
png_color const *palRGB, png_color const *palRGB,
@@ -47,7 +45,7 @@ void indexed(
} }
} }
void grayscale( void sortGrayscale(
std::vector<Palette> &palettes, std::array<std::optional<Rgba>, 0x8001> const &colors std::vector<Palette> &palettes, std::array<std::optional<Rgba>, 0x8001> const &colors
) { ) {
options.verbosePrint(Options::VERB_LOG_ACT, "Sorting grayscale-only palette...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Sorting grayscale-only palette...\n");
@@ -73,7 +71,7 @@ static unsigned int legacyLuminance(uint16_t color) {
return 2126 * red + 7152 * green + 722 * blue; return 2126 * red + 7152 * green + 722 * blue;
} }
void rgb(std::vector<Palette> &palettes) { void sortRgb(std::vector<Palette> &palettes) {
options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes by \"\"\"luminance\"\"\"...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes by \"\"\"luminance\"\"\"...\n");
for (Palette &pal : palettes) { for (Palette &pal : palettes) {
@@ -82,5 +80,3 @@ void rgb(std::vector<Palette> &palettes) {
}); });
} }
} }
} // namespace sorting

View File

@@ -15,7 +15,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitvec.hpp"
#include "file.hpp" #include "file.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "itertools.hpp" #include "itertools.hpp"
@@ -446,7 +446,7 @@ public:
}; };
private: private:
struct iterator { struct Iterator {
TilesVisitor const &parent; TilesVisitor const &parent;
uint32_t const limit; uint32_t const limit;
uint32_t x, y; uint32_t x, y;
@@ -458,7 +458,7 @@ public:
return {parent._png, x + options.inputSlice.left, y + options.inputSlice.top}; return {parent._png, x + options.inputSlice.left, y + options.inputSlice.top};
} }
iterator &operator++() { Iterator &operator++() {
auto [major, minor] = parent._columnMajor ? std::tie(y, x) : std::tie(x, y); auto [major, minor] = parent._columnMajor ? std::tie(y, x) : std::tie(x, y);
major += 8; major += 8;
if (major == limit) { if (major == limit) {
@@ -468,19 +468,14 @@ public:
return *this; return *this;
} }
friend bool operator==(iterator const &lhs, iterator const &rhs) { bool operator==(Iterator const &rhs) const { return coords() == rhs.coords(); }
return lhs.coords() == rhs.coords(); // Compare the returned coord pairs bool operator!=(Iterator const &rhs) const { return coords() != rhs.coords(); }
}
friend bool operator!=(iterator const &lhs, iterator const &rhs) {
return lhs.coords() != rhs.coords(); // Compare the returned coord pairs
}
}; };
public: public:
iterator begin() const { return {*this, _limit, 0, 0}; } Iterator begin() const { return {*this, _limit, 0, 0}; }
iterator end() const { Iterator end() const {
iterator it{*this, _limit, _width - 8, _height - 8}; // Last valid one... Iterator it{*this, _limit, _width - 8, _height - 8}; // Last valid one...
return ++it; // ...now one-past-last! return ++it; // ...now one-past-last!
} }
}; };
@@ -567,7 +562,7 @@ static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
generatePalettes(std::vector<ProtoPalette> const &protoPalettes, Png const &png) { generatePalettes(std::vector<ProtoPalette> const &protoPalettes, Png const &png) {
// Run a "pagination" problem solver // Run a "pagination" problem solver
// TODO: allow picking one of several solvers? // TODO: allow picking one of several solvers?
auto [mappings, nbPalettes] = packing::overloadAndRemove(protoPalettes); auto [mappings, nbPalettes] = overloadAndRemove(protoPalettes);
assume(mappings.size() == protoPalettes.size()); assume(mappings.size() == protoPalettes.size());
if (options.verbosity >= Options::VERB_INTERM) { if (options.verbosity >= Options::VERB_INTERM) {
@@ -601,11 +596,11 @@ static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
// "Sort" colors in the generated palettes, see the man page for the flowchart // "Sort" colors in the generated palettes, see the man page for the flowchart
auto [embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha] = png.getEmbeddedPal(); auto [embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha] = png.getEmbeddedPal();
if (embPalRGB != nullptr) { if (embPalRGB != nullptr) {
sorting::indexed(palettes, embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha); sortIndexed(palettes, embPalSize, embPalRGB, embPalAlphaSize, embPalAlpha);
} else if (png.isSuitableForGrayscale()) { } else if (png.isSuitableForGrayscale()) {
sorting::grayscale(palettes, png.getColors().raw()); sortGrayscale(palettes, png.getColors().raw());
} else { } else {
sorting::rgb(palettes); sortRgb(palettes);
} }
return {mappings, palettes}; return {mappings, palettes};
} }
@@ -826,9 +821,7 @@ public:
return MatchType::NOPE; return MatchType::NOPE;
} }
friend bool operator==(TileData const &lhs, TileData const &rhs) { bool operator==(TileData const &rhs) const { return tryMatching(rhs) != MatchType::NOPE; }
return lhs.tryMatching(rhs) != MatchType::NOPE;
}
}; };
template<> template<>
@@ -836,9 +829,7 @@ struct std::hash<TileData> {
std::size_t operator()(TileData const &tile) const { return tile.hash(); } std::size_t operator()(TileData const &tile) const { return tile.hash(); }
}; };
namespace unoptimized { static void outputUnoptimizedTileData(
static void outputTileData(
Png const &png, Png const &png,
DefaultInitVec<AttrmapEntry> const &attrmap, DefaultInitVec<AttrmapEntry> const &attrmap,
std::vector<Palette> const &palettes, std::vector<Palette> const &palettes,
@@ -877,7 +868,7 @@ static void outputTileData(
assume(remainingTiles == 0); assume(remainingTiles == 0);
} }
static void outputMaps( static void outputUnoptimizedMaps(
DefaultInitVec<AttrmapEntry> const &attrmap, DefaultInitVec<size_t> const &mappings DefaultInitVec<AttrmapEntry> const &attrmap, DefaultInitVec<size_t> const &mappings
) { ) {
std::optional<File> tilemapOutput, attrmapOutput, palmapOutput; std::optional<File> tilemapOutput, attrmapOutput, palmapOutput;
@@ -916,10 +907,6 @@ static void outputMaps(
} }
} }
} // namespace unoptimized
namespace optimized {
struct UniqueTiles { struct UniqueTiles {
std::unordered_set<TileData> tileset; std::unordered_set<TileData> tileset;
std::vector<TileData const *> tiles; std::vector<TileData const *> tiles;
@@ -1089,8 +1076,6 @@ static void outputPalmap(
} }
} }
} // namespace optimized
void processPalettes() { void processPalettes() {
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr)); options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
@@ -1251,7 +1236,7 @@ continue_visiting_tiles:;
if (!options.output.empty()) { if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating unoptimized tile data...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating unoptimized tile data...\n");
unoptimized::outputTileData(png, attrmap, palettes, mappings); outputUnoptimizedTileData(png, attrmap, palettes, mappings);
} }
if (!options.tilemap.empty() || !options.attrmap.empty() || !options.palmap.empty()) { if (!options.tilemap.empty() || !options.attrmap.empty() || !options.palmap.empty()) {
@@ -1259,12 +1244,12 @@ continue_visiting_tiles:;
Options::VERB_LOG_ACT, Options::VERB_LOG_ACT,
"Generating unoptimized tilemap and/or attrmap and/or palmap...\n" "Generating unoptimized tilemap and/or attrmap and/or palmap...\n"
); );
unoptimized::outputMaps(attrmap, mappings); outputUnoptimizedMaps(attrmap, mappings);
} }
} else { } else {
// All of these require the deduplication process to be performed to be output // All of these require the deduplication process to be performed to be output
options.verbosePrint(Options::VERB_LOG_ACT, "Deduplicating tiles...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Deduplicating tiles...\n");
optimized::UniqueTiles tiles = optimized::dedupTiles(png, attrmap, palettes, mappings); UniqueTiles tiles = dedupTiles(png, attrmap, palettes, mappings);
if (tiles.size() > options.maxNbTiles[0] + options.maxNbTiles[1]) { if (tiles.size() > options.maxNbTiles[0] + options.maxNbTiles[1]) {
fatal( fatal(
@@ -1277,22 +1262,22 @@ continue_visiting_tiles:;
if (!options.output.empty()) { if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tile data...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tile data...\n");
optimized::outputTileData(tiles); outputTileData(tiles);
} }
if (!options.tilemap.empty()) { if (!options.tilemap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tilemap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tilemap...\n");
optimized::outputTilemap(attrmap); outputTilemap(attrmap);
} }
if (!options.attrmap.empty()) { if (!options.attrmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized attrmap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized attrmap...\n");
optimized::outputAttrmap(attrmap, mappings); outputAttrmap(attrmap, mappings);
} }
if (!options.palmap.empty()) { if (!options.palmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized palmap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized palmap...\n");
optimized::outputPalmap(attrmap, mappings); outputPalmap(attrmap, mappings);
} }
} }
} }

View File

@@ -12,7 +12,7 @@
#include <string.h> #include <string.h>
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitvec.hpp"
#include "file.hpp" #include "file.hpp"
#include "helpers.hpp" // assume #include "helpers.hpp" // assume

View File

@@ -29,7 +29,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitvec.hpp" // Reused from RGBDS
#include "gfx/rgba.hpp" // Reused from RGBGFX #include "gfx/rgba.hpp" // Reused from RGBGFX