mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Factor out InsertionOrderedMap to group an indexed list with a string-keyed map
This commit is contained in:
@@ -3,9 +3,57 @@
|
|||||||
#ifndef RGBDS_ITERTOOLS_HPP
|
#ifndef RGBDS_ITERTOOLS_HPP
|
||||||
#define RGBDS_ITERTOOLS_HPP
|
#define RGBDS_ITERTOOLS_HPP
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <optional>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class InsertionOrderedMap {
|
||||||
|
std::deque<T> list;
|
||||||
|
std::unordered_map<std::string, size_t> 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<size_t> findIndex(std::string const &name) const {
|
||||||
|
if (auto search = map.find(name); search != map.end()) {
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class EnumSeq {
|
class EnumSeq {
|
||||||
T _start;
|
T _start;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "asm/charmap.hpp"
|
#include "asm/charmap.hpp"
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@@ -12,12 +11,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "extern/utf8decoder.hpp"
|
#include "extern/utf8decoder.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "itertools.hpp" // InsertionOrderedMap
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
@@ -59,8 +58,7 @@ bool forEachChar(Charmap const &charmap, F callback) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::deque<Charmap> charmapList;
|
static InsertionOrderedMap<Charmap> charmaps;
|
||||||
static std::unordered_map<std::string, size_t> charmapMap; // Indexes into `charmapList`
|
|
||||||
|
|
||||||
static Charmap *currentCharmap;
|
static Charmap *currentCharmap;
|
||||||
static std::stack<Charmap *> charmapStack;
|
static std::stack<Charmap *> charmapStack;
|
||||||
@@ -69,7 +67,7 @@ bool charmap_ForEach(
|
|||||||
void (*mapFunc)(std::string const &),
|
void (*mapFunc)(std::string const &),
|
||||||
void (*charFunc)(std::string const &, std::vector<int32_t>)
|
void (*charFunc)(std::string const &, std::vector<int32_t>)
|
||||||
) {
|
) {
|
||||||
for (Charmap const &charmap : charmapList) {
|
for (Charmap const &charmap : charmaps) {
|
||||||
std::map<size_t, std::string> mappings;
|
std::map<size_t, std::string> mappings;
|
||||||
forEachChar(charmap, [&mappings](size_t nodeIdx, std::string const &mapping) {
|
forEachChar(charmap, [&mappings](size_t nodeIdx, std::string const &mapping) {
|
||||||
mappings[nodeIdx] = mapping;
|
mappings[nodeIdx] = mapping;
|
||||||
@@ -81,45 +79,41 @@ bool charmap_ForEach(
|
|||||||
charFunc(mapping, charmap.nodes[nodeIdx].value);
|
charFunc(mapping, charmap.nodes[nodeIdx].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !charmapList.empty();
|
return !charmaps.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void charmap_New(std::string const &name, std::string const *baseName) {
|
void charmap_New(std::string const &name, std::string const *baseName) {
|
||||||
size_t baseIdx = SIZE_MAX;
|
std::optional<size_t> baseIdx = std::nullopt;
|
||||||
|
|
||||||
if (baseName != nullptr) {
|
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());
|
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());
|
error("Charmap `%s` is already defined", name.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the new charmap's fields
|
// Init the new charmap's fields
|
||||||
charmapMap[name] = charmapList.size();
|
Charmap &charmap = charmaps.add(name);
|
||||||
Charmap &charmap = charmapList.emplace_back();
|
charmap.name = name;
|
||||||
|
if (baseIdx) {
|
||||||
if (baseIdx != SIZE_MAX) {
|
charmap.nodes = charmaps[*baseIdx].nodes; // Copies `charmaps[*baseIdx].nodes`
|
||||||
charmap.nodes = charmapList[baseIdx].nodes; // Copies `charmapList[baseIdx].nodes`
|
|
||||||
} else {
|
} else {
|
||||||
charmap.nodes.emplace_back(); // Zero-init the root node
|
charmap.nodes.emplace_back(); // Zero-init the root node
|
||||||
}
|
}
|
||||||
|
|
||||||
charmap.name = name;
|
|
||||||
|
|
||||||
currentCharmap = &charmap;
|
currentCharmap = &charmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void charmap_Set(std::string const &name) {
|
void charmap_Set(std::string const &name) {
|
||||||
if (auto search = charmapMap.find(name); search == charmapMap.end()) {
|
if (auto index = charmaps.findIndex(name); index) {
|
||||||
error("Undefined charmap `%s`", name.c_str());
|
currentCharmap = &charmaps[*index];
|
||||||
} else {
|
} else {
|
||||||
currentCharmap = &charmapList[search->second];
|
error("Undefined charmap `%s`", name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "itertools.hpp" // InsertionOrderedMap
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
@@ -46,8 +46,7 @@ struct SectionStackEntry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Section *currentSection = nullptr;
|
static Section *currentSection = nullptr;
|
||||||
static std::deque<Section> sectionList;
|
static InsertionOrderedMap<Section> sections;
|
||||||
static std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList`
|
|
||||||
|
|
||||||
static uint32_t curOffset; // Offset into the current section (see `sect_GetSymbolOffset`)
|
static uint32_t curOffset; // Offset into the current section (see `sect_GetSymbolOffset`)
|
||||||
|
|
||||||
@@ -87,17 +86,17 @@ static bool requireCodeSection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t sect_CountSections() {
|
size_t sect_CountSections() {
|
||||||
return sectionList.size();
|
return sections.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sect_ForEach(void (*callback)(Section &)) {
|
void sect_ForEach(void (*callback)(Section &)) {
|
||||||
for (Section § : sectionList) {
|
for (Section § : sections) {
|
||||||
callback(sect);
|
callback(sect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sect_CheckSizes() {
|
void sect_CheckSizes() {
|
||||||
for (Section const § : sectionList) {
|
for (Section const § : sections) {
|
||||||
if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) {
|
if (uint32_t maxSize = sectionTypeInfo[sect.type].size; sect.size > maxSize) {
|
||||||
error(
|
error(
|
||||||
"Section \"%s\" grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32
|
"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) {
|
Section *sect_FindSectionByName(std::string const &name) {
|
||||||
auto search = sectionMap.find(name);
|
auto index = sections.findIndex(name);
|
||||||
return search != sectionMap.end() ? §ionList[search->second] : nullptr;
|
return index ? §ions[*index] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define sectError(...) \
|
#define sectError(...) \
|
||||||
@@ -324,8 +323,7 @@ static Section *createSection(
|
|||||||
SectionModifier mod
|
SectionModifier mod
|
||||||
) {
|
) {
|
||||||
// Add the new section to the list
|
// Add the new section to the list
|
||||||
Section § = sectionList.emplace_back();
|
Section § = sections.add(name);
|
||||||
sectionMap.emplace(name, sectionMap.size());
|
|
||||||
|
|
||||||
sect.name = name;
|
sect.name = name;
|
||||||
sect.type = type;
|
sect.type = type;
|
||||||
@@ -349,9 +347,8 @@ static Section *createSection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Section *createSectionFragmentLiteral(Section const &parent) {
|
static Section *createSectionFragmentLiteral(Section const &parent) {
|
||||||
// Add the new section to the list, but do not update the map
|
assume(sections.contains(parent.name));
|
||||||
Section § = sectionList.emplace_back();
|
Section § = sections.addAnonymous();
|
||||||
assume(sectionMap.find(parent.name) != sectionMap.end());
|
|
||||||
|
|
||||||
sect.name = parent.name;
|
sect.name = parent.name;
|
||||||
sect.type = parent.type;
|
sect.type = parent.type;
|
||||||
@@ -478,9 +475,9 @@ static void changeSection() {
|
|||||||
uint32_t Section::getID() const {
|
uint32_t Section::getID() const {
|
||||||
// Section fragments share the same name but have different IDs, so search by identity
|
// Section fragments share the same name but have different IDs, so search by identity
|
||||||
if (auto search =
|
if (auto search =
|
||||||
std::find_if(RANGE(sectionList), [this](Section const &s) { return &s == this; });
|
std::find_if(RANGE(sections), [this](Section const &s) { return &s == this; });
|
||||||
search != sectionList.end()) {
|
search != sections.end()) {
|
||||||
return static_cast<uint32_t>(std::distance(sectionList.begin(), search));
|
return static_cast<uint32_t>(std::distance(sections.begin(), search));
|
||||||
}
|
}
|
||||||
return UINT32_MAX; // LCOV_EXCL_LINE
|
return UINT32_MAX; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,16 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "itertools.hpp" // InsertionOrderedMap
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
#include "link/main.hpp"
|
#include "link/main.hpp"
|
||||||
#include "link/warning.hpp"
|
#include "link/warning.hpp"
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<Section>> sectionList;
|
static InsertionOrderedMap<std::unique_ptr<Section>> sections;
|
||||||
static std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList`
|
|
||||||
|
|
||||||
void sect_ForEach(void (*callback)(Section &)) {
|
void sect_ForEach(void (*callback)(Section &)) {
|
||||||
for (std::unique_ptr<Section> &ptr : sectionList) {
|
for (std::unique_ptr<Section> &ptr : sections) {
|
||||||
callback(*ptr);
|
callback(*ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ static void mergeSections(Section &target, std::unique_ptr<Section> &&other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sect_AddSection(std::unique_ptr<Section> &§ion) {
|
void sect_AddSection(std::unique_ptr<Section> &§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) {
|
if (Section *target = sect_GetSection(section->name); target) {
|
||||||
mergeSections(*target, std::move(section));
|
mergeSections(*target, std::move(section));
|
||||||
} else if (section->modifier == SECTION_UNION && sectTypeHasData(section->type)) {
|
} else if (section->modifier == SECTION_UNION && sectTypeHasData(section->type)) {
|
||||||
@@ -208,15 +208,13 @@ void sect_AddSection(std::unique_ptr<Section> &§ion) {
|
|||||||
sectionTypeInfo[section->type].name.c_str()
|
sectionTypeInfo[section->type].name.c_str()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// If not, add it
|
sections.add(section->name, std::move(section));
|
||||||
sectionMap.emplace(section->name, sectionList.size());
|
|
||||||
sectionList.push_back(std::move(section));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section *sect_GetSection(std::string const &name) {
|
Section *sect_GetSection(std::string const &name) {
|
||||||
auto search = sectionMap.find(name);
|
auto index = sections.findIndex(name);
|
||||||
return search != sectionMap.end() ? sectionList[search->second].get() : nullptr;
|
return index ? sections[*index].get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doSanityChecks(Section §ion) {
|
static void doSanityChecks(Section §ion) {
|
||||||
|
|||||||
Reference in New Issue
Block a user