diff --git a/include/itertools.hpp b/include/itertools.hpp index 0ffeba65..f7d2b430 100644 --- a/include/itertools.hpp +++ b/include/itertools.hpp @@ -3,9 +3,57 @@ #ifndef RGBDS_ITERTOOLS_HPP #define RGBDS_ITERTOOLS_HPP +#include +#include +#include +#include #include +#include #include +template +class InsertionOrderedMap { + std::deque list; + std::unordered_map map; // Indexes into `list` + +public: + size_t size() const { return list.size(); } + + bool empty() const { return list.empty(); } + + bool contains(std::string const &name) const { return map.find(name) != map.end(); } + + T &operator[](size_t i) { return list[i]; } + + typename decltype(list)::iterator begin() { return list.begin(); } + typename decltype(list)::iterator end() { return list.end(); } + typename decltype(list)::const_iterator begin() const { return list.begin(); } + typename decltype(list)::const_iterator end() const { return list.end(); } + + T &add(std::string const &name) { + map[name] = list.size(); + return list.emplace_back(); + } + + T &add(std::string const &name, T &&value) { + map[name] = list.size(); + list.emplace_back(std::move(value)); + return list.back(); + } + + T &addAnonymous() { + // Add the new item to the list, but do not update the map + return list.emplace_back(); + } + + std::optional findIndex(std::string const &name) const { + if (auto search = map.find(name); search != map.end()) { + return search->second; + } + return std::nullopt; + } +}; + template class EnumSeq { T _start; diff --git a/src/asm/charmap.cpp b/src/asm/charmap.cpp index f2ab2778..cd999cc1 100644 --- a/src/asm/charmap.cpp +++ b/src/asm/charmap.cpp @@ -2,7 +2,6 @@ #include "asm/charmap.hpp" -#include #include #include #include @@ -12,12 +11,12 @@ #include #include #include -#include #include #include #include "extern/utf8decoder.hpp" #include "helpers.hpp" +#include "itertools.hpp" // InsertionOrderedMap #include "util.hpp" #include "asm/warning.hpp" @@ -59,8 +58,7 @@ bool forEachChar(Charmap const &charmap, F callback) { return true; } -static std::deque charmapList; -static std::unordered_map charmapMap; // Indexes into `charmapList` +static InsertionOrderedMap charmaps; static Charmap *currentCharmap; static std::stack charmapStack; @@ -69,7 +67,7 @@ bool charmap_ForEach( void (*mapFunc)(std::string const &), void (*charFunc)(std::string const &, std::vector) ) { - for (Charmap const &charmap : charmapList) { + for (Charmap const &charmap : charmaps) { std::map mappings; forEachChar(charmap, [&mappings](size_t nodeIdx, std::string const &mapping) { mappings[nodeIdx] = mapping; @@ -81,45 +79,41 @@ bool charmap_ForEach( charFunc(mapping, charmap.nodes[nodeIdx].value); } } - return !charmapList.empty(); + return !charmaps.empty(); } void charmap_New(std::string const &name, std::string const *baseName) { - size_t baseIdx = SIZE_MAX; + std::optional baseIdx = std::nullopt; if (baseName != nullptr) { - if (auto search = charmapMap.find(*baseName); search == charmapMap.end()) { + baseIdx = charmaps.findIndex(*baseName); + if (!baseIdx) { error("Undefined base charmap `%s`", baseName->c_str()); - } else { - baseIdx = search->second; } } - if (charmapMap.find(name) != charmapMap.end()) { + if (charmaps.contains(name)) { error("Charmap `%s` is already defined", name.c_str()); return; } // Init the new charmap's fields - charmapMap[name] = charmapList.size(); - Charmap &charmap = charmapList.emplace_back(); - - if (baseIdx != SIZE_MAX) { - charmap.nodes = charmapList[baseIdx].nodes; // Copies `charmapList[baseIdx].nodes` + Charmap &charmap = charmaps.add(name); + charmap.name = name; + if (baseIdx) { + charmap.nodes = charmaps[*baseIdx].nodes; // Copies `charmaps[*baseIdx].nodes` } else { charmap.nodes.emplace_back(); // Zero-init the root node } - charmap.name = name; - currentCharmap = &charmap; } void charmap_Set(std::string const &name) { - if (auto search = charmapMap.find(name); search == charmapMap.end()) { - error("Undefined charmap `%s`", name.c_str()); + if (auto index = charmaps.findIndex(name); index) { + currentCharmap = &charmaps[*index]; } else { - currentCharmap = &charmapList[search->second]; + error("Undefined charmap `%s`", name.c_str()); } } diff --git a/src/asm/section.cpp b/src/asm/section.cpp index bf5d2f9e..4b663134 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -14,11 +14,11 @@ #include #include #include -#include #include #include #include "helpers.hpp" +#include "itertools.hpp" // InsertionOrderedMap #include "linkdefs.hpp" #include "asm/fstack.hpp" @@ -46,8 +46,7 @@ struct SectionStackEntry { }; static Section *currentSection = nullptr; -static std::deque
sectionList; -static std::unordered_map sectionMap; // Indexes into `sectionList` +static InsertionOrderedMap
sections; static uint32_t curOffset; // Offset into the current section (see `sect_GetSymbolOffset`) @@ -87,17 +86,17 @@ static bool requireCodeSection() { } size_t sect_CountSections() { - return sectionList.size(); + return sections.size(); } void sect_ForEach(void (*callback)(Section &)) { - for (Section § : sectionList) { + for (Section § : sections) { callback(sect); } } void sect_CheckSizes() { - for (Section const § : sectionList) { + for (Section const § : sections) { if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) { error( "Section \"%s\" grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32 @@ -111,8 +110,8 @@ void sect_CheckSizes() { } Section *sect_FindSectionByName(std::string const &name) { - auto search = sectionMap.find(name); - return search != sectionMap.end() ? §ionList[search->second] : nullptr; + auto index = sections.findIndex(name); + return index ? §ions[*index] : nullptr; } #define sectError(...) \ @@ -324,8 +323,7 @@ static Section *createSection( SectionModifier mod ) { // Add the new section to the list - Section § = sectionList.emplace_back(); - sectionMap.emplace(name, sectionMap.size()); + Section § = sections.add(name); sect.name = name; sect.type = type; @@ -349,9 +347,8 @@ static Section *createSection( } static Section *createSectionFragmentLiteral(Section const &parent) { - // Add the new section to the list, but do not update the map - Section § = sectionList.emplace_back(); - assume(sectionMap.find(parent.name) != sectionMap.end()); + assume(sections.contains(parent.name)); + Section § = sections.addAnonymous(); sect.name = parent.name; sect.type = parent.type; @@ -478,9 +475,9 @@ static void changeSection() { uint32_t Section::getID() const { // Section fragments share the same name but have different IDs, so search by identity if (auto search = - std::find_if(RANGE(sectionList), [this](Section const &s) { return &s == this; }); - search != sectionList.end()) { - return static_cast(std::distance(sectionList.begin(), search)); + std::find_if(RANGE(sections), [this](Section const &s) { return &s == this; }); + search != sections.end()) { + return static_cast(std::distance(sections.begin(), search)); } return UINT32_MAX; // LCOV_EXCL_LINE } diff --git a/src/link/section.cpp b/src/link/section.cpp index 04368bfe..1bc848dd 100644 --- a/src/link/section.cpp +++ b/src/link/section.cpp @@ -13,16 +13,16 @@ #include #include "helpers.hpp" +#include "itertools.hpp" // InsertionOrderedMap #include "linkdefs.hpp" #include "link/main.hpp" #include "link/warning.hpp" -static std::vector> sectionList; -static std::unordered_map sectionMap; // Indexes into `sectionList` +static InsertionOrderedMap> sections; void sect_ForEach(void (*callback)(Section &)) { - for (std::unique_ptr
&ptr : sectionList) { + for (std::unique_ptr
&ptr : sections) { callback(*ptr); } } @@ -198,7 +198,7 @@ static void mergeSections(Section &target, std::unique_ptr
&&other) { } void sect_AddSection(std::unique_ptr
&§ion) { - // Check if the section already exists + // Check if the section already exists; if not, add it if (Section *target = sect_GetSection(section->name); target) { mergeSections(*target, std::move(section)); } else if (section->modifier == SECTION_UNION && sectTypeHasData(section->type)) { @@ -208,15 +208,13 @@ void sect_AddSection(std::unique_ptr
&§ion) { sectionTypeInfo[section->type].name.c_str() ); } else { - // If not, add it - sectionMap.emplace(section->name, sectionList.size()); - sectionList.push_back(std::move(section)); + sections.add(section->name, std::move(section)); } } Section *sect_GetSection(std::string const &name) { - auto search = sectionMap.find(name); - return search != sectionMap.end() ? sectionList[search->second].get() : nullptr; + auto index = sections.findIndex(name); + return index ? sections[*index].get() : nullptr; } static void doSanityChecks(Section §ion) {