Replace entity map implementation with std::unordered_map.
On a single load benchmark this provides about 25% speedup.pull/434/head
parent
406c55e8b9
commit
bd84bc1ae9
38
src/file.cpp
38
src/file.cpp
|
@ -210,9 +210,9 @@ const SolveSpaceUI::SaveTable SolveSpaceUI::SAVED[] = {
|
|||
};
|
||||
|
||||
struct SAVEDptr {
|
||||
IdList<EntityMap,EntityId> &M() { return *((IdList<EntityMap,EntityId> *)this); }
|
||||
std::string &S() { return *((std::string *)this); }
|
||||
Platform::Path &P() { return *((Platform::Path *)this); }
|
||||
EntityMap &M() { return *((EntityMap *)this); }
|
||||
std::string &S() { return *((std::string *)this); }
|
||||
Platform::Path &P() { return *((Platform::Path *)this); }
|
||||
bool &b() { return *((bool *)this); }
|
||||
RgbaColor &c() { return *((RgbaColor *)this); }
|
||||
int &d() { return *((int *)this); }
|
||||
|
@ -254,12 +254,16 @@ void SolveSpaceUI::SaveUsingTable(const Platform::Path &filename, int type) {
|
|||
}
|
||||
|
||||
case 'M': {
|
||||
int j;
|
||||
fprintf(fh, "{\n");
|
||||
for(j = 0; j < p->M().n; j++) {
|
||||
EntityMap *em = &(p->M().elem[j]);
|
||||
// Sort the mapping, since EntityMap is not deterministic.
|
||||
std::vector<std::pair<EntityKey, EntityId>> sorted(p->M().begin(), p->M().end());
|
||||
std::sort(sorted.begin(), sorted.end(),
|
||||
[](std::pair<EntityKey, EntityId> &a, std::pair<EntityKey, EntityId> &b) {
|
||||
return a.second.v < b.second.v;
|
||||
});
|
||||
for(auto it : sorted) {
|
||||
fprintf(fh, " %d %08x %d\n",
|
||||
em->h.v, em->input.v, em->copyNumber);
|
||||
it.second.v, it.first.input.v, it.first.copyNumber);
|
||||
}
|
||||
fprintf(fh, "}");
|
||||
break;
|
||||
|
@ -424,20 +428,17 @@ void SolveSpaceUI::LoadUsingTable(const Platform::Path &filename, char *key, cha
|
|||
break;
|
||||
|
||||
case 'M': {
|
||||
// Don't clear this list! When the group gets added, it
|
||||
// makes a shallow copy, so that would result in us
|
||||
// freeing memory that we want to keep around. Just
|
||||
// zero it out so that new memory is allocated.
|
||||
p->M() = {};
|
||||
p->M().clear();
|
||||
for(;;) {
|
||||
EntityMap em;
|
||||
EntityKey ek;
|
||||
EntityId ei;
|
||||
char line2[1024];
|
||||
if (fgets(line2, (int)sizeof(line2), fh) == NULL)
|
||||
break;
|
||||
if(sscanf(line2, "%d %x %d", &(em.h.v), &(em.input.v),
|
||||
&(em.copyNumber)) == 3)
|
||||
if(sscanf(line2, "%d %x %d", &(ei.v), &(ek.input.v),
|
||||
&(ek.copyNumber)) == 3)
|
||||
{
|
||||
p->M().Add(&em);
|
||||
p->M().insert({ ek, ei });
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -719,9 +720,8 @@ bool SolveSpaceUI::LoadEntitiesFromFile(const Platform::Path &filename, EntityLi
|
|||
char *key = line, *val = e+1;
|
||||
LoadUsingTable(filename, key, val);
|
||||
} else if(strcmp(line, "AddGroup")==0) {
|
||||
// Don't leak memory; these get allocated whether we want them
|
||||
// or not.
|
||||
sv.g.remap.Clear();
|
||||
// These get allocated whether we want them or not.
|
||||
sv.g.remap.clear();
|
||||
} else if(strcmp(line, "AddParam")==0) {
|
||||
|
||||
} else if(strcmp(line, "AddEntity")==0) {
|
||||
|
|
|
@ -31,7 +31,7 @@ void Group::Clear() {
|
|||
impShell.Clear();
|
||||
impEntity.Clear();
|
||||
// remap is the only one that doesn't get recreated when we regen
|
||||
remap.Clear();
|
||||
remap.clear();
|
||||
}
|
||||
|
||||
void Group::AddParam(IdList<Param,hParam> *param, hParam hp, double v) {
|
||||
|
@ -641,30 +641,12 @@ void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
hEntity Group::Remap(hEntity in, int copyNumber) {
|
||||
// A hash table is used to accelerate the search
|
||||
int hash = ((unsigned)(in.v*61 + copyNumber)) % REMAP_PRIME;
|
||||
int i = remapCache[hash];
|
||||
if(i >= 0 && i < remap.n) {
|
||||
EntityMap *em = &(remap.elem[i]);
|
||||
if(em->input.v == in.v && em->copyNumber == copyNumber) {
|
||||
return h.entity(em->h.v);
|
||||
}
|
||||
auto it = remap.find({ in, copyNumber });
|
||||
if(it == remap.end()) {
|
||||
std::tie(it, std::ignore) =
|
||||
remap.insert({ { in, copyNumber }, { (uint32_t)remap.size() } });
|
||||
}
|
||||
// but if we don't find it in the hash table, then linear search
|
||||
for(i = 0; i < remap.n; i++) {
|
||||
EntityMap *em = &(remap.elem[i]);
|
||||
if(em->input.v == in.v && em->copyNumber == copyNumber) {
|
||||
// We already have a mapping for this entity.
|
||||
remapCache[hash] = i;
|
||||
return h.entity(em->h.v);
|
||||
}
|
||||
}
|
||||
// And if we still don't find it, then create a new entry.
|
||||
EntityMap em;
|
||||
em.input = in;
|
||||
em.copyNumber = copyNumber;
|
||||
remap.AddAndAssignId(&em);
|
||||
return h.entity(em.h.v);
|
||||
return h.entity(it->second.v);
|
||||
}
|
||||
|
||||
void Group::MakeExtrusionLines(IdList<Entity,hEntity> *el, hEntity in) {
|
||||
|
|
28
src/sketch.h
28
src/sketch.h
|
@ -94,21 +94,27 @@ public:
|
|||
uint32_t v;
|
||||
};
|
||||
|
||||
class EntityId {
|
||||
public:
|
||||
struct EntityId {
|
||||
uint32_t v; // entity ID, starting from 0
|
||||
};
|
||||
class EntityMap {
|
||||
public:
|
||||
int tag;
|
||||
|
||||
EntityId h;
|
||||
struct EntityKey {
|
||||
hEntity input;
|
||||
int copyNumber;
|
||||
// (input, copyNumber) gets mapped to ((Request)xxx).entity(h.v)
|
||||
|
||||
void Clear() {}
|
||||
};
|
||||
struct EntityKeyHash {
|
||||
size_t operator()(const EntityKey &k) const {
|
||||
size_t h1 = std::hash<uint32_t>{}(k.input.v),
|
||||
h2 = std::hash<uint32_t>{}(k.copyNumber);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
struct EntityKeyEqual {
|
||||
bool operator()(const EntityKey &a, const EntityKey &b) const {
|
||||
return std::tie(a.input.v, a.copyNumber) == std::tie(b.input.v, b.copyNumber);
|
||||
}
|
||||
};
|
||||
typedef std::unordered_map<EntityKey, EntityId, EntityKeyHash, EntityKeyEqual> EntityMap;
|
||||
|
||||
// A set of requests. Every request must have an associated group.
|
||||
class Group {
|
||||
|
@ -214,9 +220,7 @@ public:
|
|||
|
||||
bool forceToMesh;
|
||||
|
||||
IdList<EntityMap,EntityId> remap;
|
||||
enum { REMAP_PRIME = 19477 };
|
||||
int remapCache[REMAP_PRIME];
|
||||
EntityMap remap;
|
||||
|
||||
Platform::Path linkFile;
|
||||
SMesh impMesh;
|
||||
|
|
|
@ -66,8 +66,7 @@ void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
|
|||
dest.displayMesh = {};
|
||||
dest.displayOutlines = {};
|
||||
|
||||
dest.remap = {};
|
||||
src->remap.DeepCopyInto(&(dest.remap));
|
||||
dest.remap = src->remap;
|
||||
|
||||
dest.impMesh = {};
|
||||
dest.impShell = {};
|
||||
|
@ -161,7 +160,7 @@ void SolveSpaceUI::UndoClearState(UndoState *ut) {
|
|||
for(i = 0; i < ut->group.n; i++) {
|
||||
Group *g = &(ut->group.elem[i]);
|
||||
|
||||
g->remap.Clear();
|
||||
g->remap.clear();
|
||||
}
|
||||
ut->group.Clear();
|
||||
ut->request.Clear();
|
||||
|
|
Loading…
Reference in New Issue