From e824e34526b7daa12002b8a6a06a7ae30d463a8d Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sun, 12 Nov 2023 03:19:19 -0500 Subject: [PATCH] Use an iterator template for enum sequence loops (#1228) --- include/gfx/main.hpp | 3 ++- include/gfx/pal_packing.hpp | 2 +- include/gfx/pal_sorting.hpp | 2 +- include/itertools.hpp | 38 ++++++++++++++++++++++++++++++++++++- src/asm/warning.cpp | 6 +++--- src/link/assign.cpp | 5 +++-- src/link/main.cpp | 9 ++++++--- src/link/output.cpp | 3 ++- src/link/script.cpp | 9 +++++---- 9 files changed, 60 insertions(+), 17 deletions(-) diff --git a/include/gfx/main.hpp b/include/gfx/main.hpp index 500dd73c..55189fbf 100644 --- a/include/gfx/main.hpp +++ b/include/gfx/main.hpp @@ -110,7 +110,8 @@ static constexpr auto flipTable(std::integer_sequence) { return byte; }(i)...}; } -} +} // 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()); diff --git a/include/gfx/pal_packing.hpp b/include/gfx/pal_packing.hpp index 8f6f4184..6f4d602c 100644 --- a/include/gfx/pal_packing.hpp +++ b/include/gfx/pal_packing.hpp @@ -21,6 +21,6 @@ namespace packing { std::tuple, size_t> overloadAndRemove(std::vector const &protoPalettes); -} +} // namespace packing #endif // RGBDS_GFX_PAL_PACKING_HPP diff --git a/include/gfx/pal_sorting.hpp b/include/gfx/pal_sorting.hpp index aec236a1..ff4f2958 100644 --- a/include/gfx/pal_sorting.hpp +++ b/include/gfx/pal_sorting.hpp @@ -21,6 +21,6 @@ void grayscale(std::vector &palettes, std::array, 0x8001> const &colors); void rgb(std::vector &palettes); -} +} // namespace sorting #endif // RGBDS_GFX_PAL_SORTING_HPP diff --git a/include/itertools.hpp b/include/itertools.hpp index a1c40c63..1406442c 100644 --- a/include/itertools.hpp +++ b/include/itertools.hpp @@ -13,6 +13,42 @@ static inline void report() { puts(__PRETTY_FUNCTION__); } +template +class EnumSeqIterator { + T _value; + +public: + explicit EnumSeqIterator(T value) : _value(value) {} + + EnumSeqIterator &operator++() { + _value = (T)(_value + 1); + return *this; + } + + auto operator*() const { return _value; } + + friend auto operator==(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) { + return lhs._value == rhs._value; + } + + friend auto operator!=(EnumSeqIterator const &lhs, EnumSeqIterator const &rhs) { + return lhs._value != rhs._value; + } +}; + +template +class EnumSeq { + T _start; + T _stop; + +public: + explicit EnumSeq(T stop) : _start((T)0), _stop(stop) {} + explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {} + + EnumSeqIterator begin() { return EnumSeqIterator(_start); } + EnumSeqIterator end() { return EnumSeqIterator(_stop); } +}; + // 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. template @@ -73,7 +109,7 @@ public: template using Holder = std::conditional_t, T, std::remove_cv_t>>; -} +} // namespace detail // Does the same number of iterations as the first container's iterator! template diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 09a3f5e8..05aa1718 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -13,6 +13,7 @@ #include "asm/warning.hpp" #include "error.hpp" +#include "itertools.hpp" unsigned int nbErrors = 0; @@ -214,7 +215,7 @@ void processWarningFlag(char *flag) static bool setError = false; // First, try to match against a "meta" warning - for (enum WarningID id = META_WARNINGS_START; id < NB_WARNINGS; id = (enum WarningID)(id + 1)) { + for (enum WarningID id : EnumSeq(META_WARNINGS_START, NB_WARNINGS)) { // TODO: improve the matching performance? if (!strcmp(flag, warningFlags[id])) { // We got a match! @@ -309,8 +310,7 @@ void processWarningFlag(char *flag) } // Try to match the flag against a "normal" flag - for (enum WarningID id = (enum WarningID)0; id < NB_PLAIN_WARNINGS; - id = (enum WarningID)(id + 1)) { + for (enum WarningID id : EnumSeq(NB_PLAIN_WARNINGS)) { if (!strcmp(rootFlag, warningFlags[id])) { // We got a match! warningStates[id] = state; diff --git a/src/link/assign.cpp b/src/link/assign.cpp index 8148d9ae..621d2e06 100644 --- a/src/link/assign.cpp +++ b/src/link/assign.cpp @@ -15,6 +15,7 @@ #include "error.hpp" #include "helpers.hpp" +#include "itertools.hpp" #include "linkdefs.hpp" struct MemoryLocation { @@ -36,7 +37,7 @@ uint64_t nbSectionsToAssign; // Init the free space-modelling structs static void initFreeSpace(void) { - for (enum SectionType type = (enum SectionType)0; type < SECTTYPE_INVALID; type = (enum SectionType)(type + 1)) { + for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { memory[type] = (struct FreeSpace *)malloc(sizeof(*memory[type]) * nbbanks(type)); if (!memory[type]) err("Failed to init free space for region %d", type); @@ -428,7 +429,7 @@ max_out: void assign_Cleanup(void) { - for (enum SectionType type = (enum SectionType)0; type < SECTTYPE_INVALID; type = (enum SectionType)(type + 1)) { + for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { for (uint32_t bank = 0; bank < nbbanks(type); bank++) { struct FreeSpace *ptr = memory[type][bank].next; diff --git a/src/link/main.cpp b/src/link/main.cpp index 07be9f67..2a0abb90 100644 --- a/src/link/main.cpp +++ b/src/link/main.cpp @@ -23,6 +23,7 @@ #include "extern/getopt.hpp" #include "error.hpp" +#include "itertools.hpp" #include "linkdefs.hpp" #include "platform.hpp" #include "version.hpp" @@ -249,7 +250,7 @@ static void parseScrambleSpec(char const *spec) size_t regionNameLen = strcspn(spec, "=, \t"); // Length of region name string slice for printing, truncated if too long int regionNamePrintLen = regionNameLen > INT_MAX ? INT_MAX : (int)regionNameLen; - enum ScrambledRegion region = (enum ScrambledRegion)0; + enum ScrambledRegion region = SCRAMBLE_UNK; // If this trips, `spec` must be pointing at a ',' or '=' (or NUL) due to the assert if (regionNameLen == 0) { @@ -272,12 +273,14 @@ static void parseScrambleSpec(char const *spec) } // Now, determine which region type this is - for (; region < SCRAMBLE_UNK; region = (enum ScrambledRegion)(region + 1)) { + for (enum ScrambledRegion r : EnumSeq(SCRAMBLE_UNK)) { // If the strings match (case-insensitively), we got it! // `strncasecmp` must be used here since `regionName` points // to the entire remaining argument. - if (!strncasecmp(scrambleSpecs[region].name, regionName, regionNameLen)) + if (!strncasecmp(scrambleSpecs[r].name, regionName, regionNameLen)) { + region = r; break; + } } if (region == SCRAMBLE_UNK) diff --git a/src/link/output.cpp b/src/link/output.cpp index 35427785..ff30001e 100644 --- a/src/link/output.cpp +++ b/src/link/output.cpp @@ -15,6 +15,7 @@ #include "extern/utf8decoder.hpp" #include "error.hpp" +#include "itertools.hpp" #include "linkdefs.hpp" #include "platform.hpp" // For `MIN_NB_ELMS` and `AT` @@ -604,7 +605,7 @@ static void cleanupSections(struct SortedSection *section) static void cleanup(void) { - for (enum SectionType type = (enum SectionType)0; type < SECTTYPE_INVALID; type = (enum SectionType)(type + 1)) { + for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { for (uint32_t i = 0; i < sections[type].nbBanks; i++) { struct SortedSections *bank = §ions[type].banks[i]; diff --git a/src/link/script.cpp b/src/link/script.cpp index b53140de..77ab5e5d 100644 --- a/src/link/script.cpp +++ b/src/link/script.cpp @@ -12,6 +12,7 @@ #include "link/section.hpp" #include "error.hpp" +#include "itertools.hpp" #include "linkdefs.hpp" #include "platform.hpp" @@ -292,7 +293,7 @@ static struct LinkerScriptToken *nextToken(void) token.type = TOKEN_INVALID; // Try to match a command - for (enum LinkerScriptCommand i = (enum LinkerScriptCommand)0; i < COMMAND_INVALID; i = (enum LinkerScriptCommand)(i + 1)) { + for (enum LinkerScriptCommand i : EnumSeq(COMMAND_INVALID)) { if (!strcmp(commands[i], str)) { token.type = TOKEN_COMMAND; token.attr.command = i; @@ -302,7 +303,7 @@ static struct LinkerScriptToken *nextToken(void) if (token.type == TOKEN_INVALID) { // Try to match a bank specifier - for (enum SectionType type = (enum SectionType)0; type < SECTTYPE_INVALID; type = (enum SectionType)(type + 1)) { + for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { if (!strcmp(sectionTypeInfo[type].name, str)) { token.type = TOKEN_BANK; token.attr.secttype = type; @@ -384,7 +385,7 @@ struct SectionPlacement *script_NextSection(void) lineNo = 1; // Init PC for all banks - for (enum SectionType i = (enum SectionType)0; i < SECTTYPE_INVALID; i = (enum SectionType)(i + 1)) { + for (enum SectionType i : EnumSeq(SECTTYPE_INVALID)) { curaddr[i] = (uint16_t *)malloc(sizeof(*curaddr[i]) * nbbanks(i)); for (uint32_t b = 0; b < nbbanks(i); b++) curaddr[i][b] = sectionTypeInfo[i].startAddr; @@ -544,6 +545,6 @@ lineend: void script_Cleanup(void) { - for (enum SectionType type = (enum SectionType)0; type < SECTTYPE_INVALID; type = (enum SectionType)(type + 1)) + for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) free(curaddr[type]); }