mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Use an iterator template for enum sequence loops (#1228)
This commit is contained in:
@@ -110,7 +110,8 @@ static constexpr auto flipTable(std::integer_sequence<T, i...>) {
|
|||||||
return byte;
|
return byte;
|
||||||
}(i)...};
|
}(i)...};
|
||||||
}
|
}
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
|
// 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>());
|
static constexpr auto flipTable = detail::flipTable(std::make_integer_sequence<uint16_t, 256>());
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ namespace packing {
|
|||||||
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
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ void grayscale(std::vector<Palette> &palettes,
|
|||||||
std::array<std::optional<Rgba>, 0x8001> const &colors);
|
std::array<std::optional<Rgba>, 0x8001> const &colors);
|
||||||
void rgb(std::vector<Palette> &palettes);
|
void rgb(std::vector<Palette> &palettes);
|
||||||
|
|
||||||
}
|
} // namespace sorting
|
||||||
|
|
||||||
#endif // RGBDS_GFX_PAL_SORTING_HPP
|
#endif // RGBDS_GFX_PAL_SORTING_HPP
|
||||||
|
|||||||
@@ -13,6 +13,42 @@ static inline void report() {
|
|||||||
puts(__PRETTY_FUNCTION__);
|
puts(__PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<typename T>
|
||||||
|
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<T> begin() { return EnumSeqIterator(_start); }
|
||||||
|
EnumSeqIterator<T> end() { return EnumSeqIterator(_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... Iters>
|
||||||
@@ -73,7 +109,7 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using Holder = std::conditional_t<std::is_lvalue_reference_v<T>, T,
|
using Holder = std::conditional_t<std::is_lvalue_reference_v<T>, T,
|
||||||
std::remove_cv_t<std::remove_reference_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... Containers>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "itertools.hpp"
|
||||||
|
|
||||||
unsigned int nbErrors = 0;
|
unsigned int nbErrors = 0;
|
||||||
|
|
||||||
@@ -214,7 +215,7 @@ void processWarningFlag(char *flag)
|
|||||||
static bool setError = false;
|
static bool setError = false;
|
||||||
|
|
||||||
// First, try to match against a "meta" warning
|
// 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?
|
// TODO: improve the matching performance?
|
||||||
if (!strcmp(flag, warningFlags[id])) {
|
if (!strcmp(flag, warningFlags[id])) {
|
||||||
// We got a match!
|
// We got a match!
|
||||||
@@ -309,8 +310,7 @@ void processWarningFlag(char *flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to match the flag against a "normal" flag
|
// Try to match the flag against a "normal" flag
|
||||||
for (enum WarningID id = (enum WarningID)0; id < NB_PLAIN_WARNINGS;
|
for (enum WarningID id : EnumSeq(NB_PLAIN_WARNINGS)) {
|
||||||
id = (enum WarningID)(id + 1)) {
|
|
||||||
if (!strcmp(rootFlag, warningFlags[id])) {
|
if (!strcmp(rootFlag, warningFlags[id])) {
|
||||||
// We got a match!
|
// We got a match!
|
||||||
warningStates[id] = state;
|
warningStates[id] = state;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "itertools.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct MemoryLocation {
|
struct MemoryLocation {
|
||||||
@@ -36,7 +37,7 @@ uint64_t nbSectionsToAssign;
|
|||||||
// Init the free space-modelling structs
|
// Init the free space-modelling structs
|
||||||
static void initFreeSpace(void)
|
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));
|
memory[type] = (struct FreeSpace *)malloc(sizeof(*memory[type]) * nbbanks(type));
|
||||||
if (!memory[type])
|
if (!memory[type])
|
||||||
err("Failed to init free space for region %d", type);
|
err("Failed to init free space for region %d", type);
|
||||||
@@ -428,7 +429,7 @@ max_out:
|
|||||||
|
|
||||||
void assign_Cleanup(void)
|
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++) {
|
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
|
||||||
struct FreeSpace *ptr =
|
struct FreeSpace *ptr =
|
||||||
memory[type][bank].next;
|
memory[type][bank].next;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "extern/getopt.hpp"
|
#include "extern/getopt.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "itertools.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
@@ -249,7 +250,7 @@ static void parseScrambleSpec(char const *spec)
|
|||||||
size_t regionNameLen = strcspn(spec, "=, \t");
|
size_t regionNameLen = strcspn(spec, "=, \t");
|
||||||
// Length of region name string slice for printing, truncated if too long
|
// Length of region name string slice for printing, truncated if too long
|
||||||
int regionNamePrintLen = regionNameLen > INT_MAX ? INT_MAX : (int)regionNameLen;
|
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 this trips, `spec` must be pointing at a ',' or '=' (or NUL) due to the assert
|
||||||
if (regionNameLen == 0) {
|
if (regionNameLen == 0) {
|
||||||
@@ -272,13 +273,15 @@ static void parseScrambleSpec(char const *spec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, determine which region type this is
|
// 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!
|
// If the strings match (case-insensitively), we got it!
|
||||||
// `strncasecmp` must be used here since `regionName` points
|
// `strncasecmp` must be used here since `regionName` points
|
||||||
// to the entire remaining argument.
|
// to the entire remaining argument.
|
||||||
if (!strncasecmp(scrambleSpecs[region].name, regionName, regionNameLen))
|
if (!strncasecmp(scrambleSpecs[r].name, regionName, regionNameLen)) {
|
||||||
|
region = r;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (region == SCRAMBLE_UNK)
|
if (region == SCRAMBLE_UNK)
|
||||||
argErr('S', "Unknown region \"%.*s\"", regionNamePrintLen, regionName);
|
argErr('S', "Unknown region \"%.*s\"", regionNamePrintLen, regionName);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "extern/utf8decoder.hpp"
|
#include "extern/utf8decoder.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "itertools.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp" // For `MIN_NB_ELMS` and `AT`
|
#include "platform.hpp" // For `MIN_NB_ELMS` and `AT`
|
||||||
|
|
||||||
@@ -604,7 +605,7 @@ static void cleanupSections(struct SortedSection *section)
|
|||||||
|
|
||||||
static void cleanup(void)
|
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++) {
|
for (uint32_t i = 0; i < sections[type].nbBanks; i++) {
|
||||||
struct SortedSections *bank = §ions[type].banks[i];
|
struct SortedSections *bank = §ions[type].banks[i];
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "link/section.hpp"
|
#include "link/section.hpp"
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "itertools.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
|
||||||
@@ -292,7 +293,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
token.type = TOKEN_INVALID;
|
token.type = TOKEN_INVALID;
|
||||||
|
|
||||||
// Try to match a command
|
// 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)) {
|
if (!strcmp(commands[i], str)) {
|
||||||
token.type = TOKEN_COMMAND;
|
token.type = TOKEN_COMMAND;
|
||||||
token.attr.command = i;
|
token.attr.command = i;
|
||||||
@@ -302,7 +303,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
|
|
||||||
if (token.type == TOKEN_INVALID) {
|
if (token.type == TOKEN_INVALID) {
|
||||||
// Try to match a bank specifier
|
// 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)) {
|
if (!strcmp(sectionTypeInfo[type].name, str)) {
|
||||||
token.type = TOKEN_BANK;
|
token.type = TOKEN_BANK;
|
||||||
token.attr.secttype = type;
|
token.attr.secttype = type;
|
||||||
@@ -384,7 +385,7 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
lineNo = 1;
|
lineNo = 1;
|
||||||
|
|
||||||
// Init PC for all banks
|
// 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));
|
curaddr[i] = (uint16_t *)malloc(sizeof(*curaddr[i]) * nbbanks(i));
|
||||||
for (uint32_t b = 0; b < nbbanks(i); b++)
|
for (uint32_t b = 0; b < nbbanks(i); b++)
|
||||||
curaddr[i][b] = sectionTypeInfo[i].startAddr;
|
curaddr[i][b] = sectionTypeInfo[i].startAddr;
|
||||||
@@ -544,6 +545,6 @@ lineend:
|
|||||||
|
|
||||||
void script_Cleanup(void)
|
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]);
|
free(curaddr[type]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user