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 {
|
struct SAVEDptr {
|
||||||
IdList<EntityMap,EntityId> &M() { return *((IdList<EntityMap,EntityId> *)this); }
|
EntityMap &M() { return *((EntityMap *)this); }
|
||||||
std::string &S() { return *((std::string *)this); }
|
std::string &S() { return *((std::string *)this); }
|
||||||
Platform::Path &P() { return *((Platform::Path *)this); }
|
Platform::Path &P() { return *((Platform::Path *)this); }
|
||||||
bool &b() { return *((bool *)this); }
|
bool &b() { return *((bool *)this); }
|
||||||
RgbaColor &c() { return *((RgbaColor *)this); }
|
RgbaColor &c() { return *((RgbaColor *)this); }
|
||||||
int &d() { return *((int *)this); }
|
int &d() { return *((int *)this); }
|
||||||
|
@ -254,12 +254,16 @@ void SolveSpaceUI::SaveUsingTable(const Platform::Path &filename, int type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'M': {
|
case 'M': {
|
||||||
int j;
|
|
||||||
fprintf(fh, "{\n");
|
fprintf(fh, "{\n");
|
||||||
for(j = 0; j < p->M().n; j++) {
|
// Sort the mapping, since EntityMap is not deterministic.
|
||||||
EntityMap *em = &(p->M().elem[j]);
|
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",
|
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, "}");
|
fprintf(fh, "}");
|
||||||
break;
|
break;
|
||||||
|
@ -424,20 +428,17 @@ void SolveSpaceUI::LoadUsingTable(const Platform::Path &filename, char *key, cha
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M': {
|
case 'M': {
|
||||||
// Don't clear this list! When the group gets added, it
|
p->M().clear();
|
||||||
// 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() = {};
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
EntityMap em;
|
EntityKey ek;
|
||||||
|
EntityId ei;
|
||||||
char line2[1024];
|
char line2[1024];
|
||||||
if (fgets(line2, (int)sizeof(line2), fh) == NULL)
|
if (fgets(line2, (int)sizeof(line2), fh) == NULL)
|
||||||
break;
|
break;
|
||||||
if(sscanf(line2, "%d %x %d", &(em.h.v), &(em.input.v),
|
if(sscanf(line2, "%d %x %d", &(ei.v), &(ek.input.v),
|
||||||
&(em.copyNumber)) == 3)
|
&(ek.copyNumber)) == 3)
|
||||||
{
|
{
|
||||||
p->M().Add(&em);
|
p->M().insert({ ek, ei });
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -719,9 +720,8 @@ bool SolveSpaceUI::LoadEntitiesFromFile(const Platform::Path &filename, EntityLi
|
||||||
char *key = line, *val = e+1;
|
char *key = line, *val = e+1;
|
||||||
LoadUsingTable(filename, key, val);
|
LoadUsingTable(filename, key, val);
|
||||||
} else if(strcmp(line, "AddGroup")==0) {
|
} else if(strcmp(line, "AddGroup")==0) {
|
||||||
// Don't leak memory; these get allocated whether we want them
|
// These get allocated whether we want them or not.
|
||||||
// or not.
|
sv.g.remap.clear();
|
||||||
sv.g.remap.Clear();
|
|
||||||
} else if(strcmp(line, "AddParam")==0) {
|
} else if(strcmp(line, "AddParam")==0) {
|
||||||
|
|
||||||
} else if(strcmp(line, "AddEntity")==0) {
|
} else if(strcmp(line, "AddEntity")==0) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ void Group::Clear() {
|
||||||
impShell.Clear();
|
impShell.Clear();
|
||||||
impEntity.Clear();
|
impEntity.Clear();
|
||||||
// remap is the only one that doesn't get recreated when we regen
|
// 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) {
|
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) {
|
hEntity Group::Remap(hEntity in, int copyNumber) {
|
||||||
// A hash table is used to accelerate the search
|
auto it = remap.find({ in, copyNumber });
|
||||||
int hash = ((unsigned)(in.v*61 + copyNumber)) % REMAP_PRIME;
|
if(it == remap.end()) {
|
||||||
int i = remapCache[hash];
|
std::tie(it, std::ignore) =
|
||||||
if(i >= 0 && i < remap.n) {
|
remap.insert({ { in, copyNumber }, { (uint32_t)remap.size() } });
|
||||||
EntityMap *em = &(remap.elem[i]);
|
|
||||||
if(em->input.v == in.v && em->copyNumber == copyNumber) {
|
|
||||||
return h.entity(em->h.v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// but if we don't find it in the hash table, then linear search
|
return h.entity(it->second.v);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::MakeExtrusionLines(IdList<Entity,hEntity> *el, hEntity in) {
|
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;
|
uint32_t v;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntityId {
|
struct EntityId {
|
||||||
public:
|
|
||||||
uint32_t v; // entity ID, starting from 0
|
uint32_t v; // entity ID, starting from 0
|
||||||
};
|
};
|
||||||
class EntityMap {
|
struct EntityKey {
|
||||||
public:
|
|
||||||
int tag;
|
|
||||||
|
|
||||||
EntityId h;
|
|
||||||
hEntity input;
|
hEntity input;
|
||||||
int copyNumber;
|
int copyNumber;
|
||||||
// (input, copyNumber) gets mapped to ((Request)xxx).entity(h.v)
|
// (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.
|
// A set of requests. Every request must have an associated group.
|
||||||
class Group {
|
class Group {
|
||||||
|
@ -214,9 +220,7 @@ public:
|
||||||
|
|
||||||
bool forceToMesh;
|
bool forceToMesh;
|
||||||
|
|
||||||
IdList<EntityMap,EntityId> remap;
|
EntityMap remap;
|
||||||
enum { REMAP_PRIME = 19477 };
|
|
||||||
int remapCache[REMAP_PRIME];
|
|
||||||
|
|
||||||
Platform::Path linkFile;
|
Platform::Path linkFile;
|
||||||
SMesh impMesh;
|
SMesh impMesh;
|
||||||
|
|
|
@ -66,8 +66,7 @@ void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
|
||||||
dest.displayMesh = {};
|
dest.displayMesh = {};
|
||||||
dest.displayOutlines = {};
|
dest.displayOutlines = {};
|
||||||
|
|
||||||
dest.remap = {};
|
dest.remap = src->remap;
|
||||||
src->remap.DeepCopyInto(&(dest.remap));
|
|
||||||
|
|
||||||
dest.impMesh = {};
|
dest.impMesh = {};
|
||||||
dest.impShell = {};
|
dest.impShell = {};
|
||||||
|
@ -161,7 +160,7 @@ void SolveSpaceUI::UndoClearState(UndoState *ut) {
|
||||||
for(i = 0; i < ut->group.n; i++) {
|
for(i = 0; i < ut->group.n; i++) {
|
||||||
Group *g = &(ut->group.elem[i]);
|
Group *g = &(ut->group.elem[i]);
|
||||||
|
|
||||||
g->remap.Clear();
|
g->remap.clear();
|
||||||
}
|
}
|
||||||
ut->group.Clear();
|
ut->group.Clear();
|
||||||
ut->request.Clear();
|
ut->request.Clear();
|
||||||
|
|
Loading…
Reference in New Issue