[Toponaming] create ElementMap class (#9175)

* Copypaste ElementMap
* Add MappedNameRef
* Fix missing include
* Copypaste `findTagInElementName`
* fix error introduced _somewhere_
* refactor toponaming constants
* Move `findTagInElementName` in `MappedName`
* reintroduce workaround to compile ElementMap
* Added missing functions copied from complexgeodata
* fix last compile errors, reorder and format files
* remove recursive refs to ComplexGeoData
* Add more comments
* fixed comments and added tests
* added FIXME, make functions private, misc fixes
* Move static functions from complexGeoData to PostfixStringReferences. Rename to ElementNamingUtils
* Fix broken includes due to previous change
* Revert constants from string to const char*
* added childmap tests and made hasher public
* Make functions private
* Added remaining tests
* removed bool return from `erase` functions
* fix missing appexport

Co-authored-by: John Dupuy <jdupuy98@gmail.com>
This commit is contained in:
Pesc0
2023-06-15 16:05:24 +02:00
committed by GitHub
parent 32d8029780
commit 4a8d3853ba
26 changed files with 2450 additions and 218 deletions

View File

@@ -26,19 +26,26 @@
# include <unordered_set>
#endif
//#include <boost/functional/hash.hpp>
#include "MappedName.h"
using namespace Data;
#include "Base/Console.h"
//#include <boost/functional/hash.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
void MappedName::compact()
FC_LOG_LEVEL_INIT("MappedName", true, 2);
namespace Data {
void MappedName::compact() const
{
auto self = const_cast<MappedName*>(this); //FIXME this is a workaround for a single call in ElementMap::addName()
if (this->raw) {
this->data = QByteArray(this->data.constData(), this->data.size());
this->raw = false;
self->data = QByteArray(self->data.constData(), self->data.size());
self->raw = false;
}
#if 0
@@ -51,3 +58,158 @@ void MappedName::compact()
#endif
}
int MappedName::findTagInElementName(long* tag, int* len, const char* postfix,
char* type, bool negative, bool recursive) const
{
bool hex = true;
int pos = this->rfind(POSTFIX_TAG);
// Example name, tagPosfix == ;:H
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// ^
// |
// pos
if(pos < 0) {
pos = this->rfind(POSTFIX_DECIMAL_TAG);
if (pos < 0)
return -1;
hex = false;
}
int offset = pos + (int)POSTFIX_TAG_SIZE;
long _tag = 0;
int _len = 0;
char sep = 0;
char sep2 = 0;
char tp = 0;
char eof = 0;
int size;
const char *s = this->toConstString(offset, size);
// check if the number followed by the tagPosfix is negative
bool isNegative = (s[0] == '-');
if (isNegative) {
++s;
--size;
}
boost::iostreams::stream<boost::iostreams::array_source> iss(s, size);
if (!hex) {
// no hex is an older version of the encoding scheme
iss >> _tag >> sep;
} else {
// The purpose of tag postfix is to encode one model operation. The
// 'tag' field is used to record the own object ID of that model shape,
// and the 'len' field indicates the length of the operation codes
// before the tag postfix. These fields are in hex. The trailing 'F' is
// the shape type of this element, 'F' for face, 'E' edge, and 'V' vertex.
//
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// | | ^^ ^^
// | | | |
// ---len = 0x10--- tag len
iss >> std::hex;
// _tag field can be skipped, if it is 0
if (s[0] == ',' || s[0] == ':')
iss >> sep;
else
iss >> _tag >> sep;
}
if (isNegative)
_tag = -_tag;
if (sep == ':') {
// ':' is followed by _len field.
//
// For decTagPostfix() (i.e. older encoding scheme), this is the length
// of the string before the entire postfix (A postfix may contain
// multiple segments usually separated by ELEMENT_MAP_PREFIX.
//
// For newer POSTFIX_TAG, this counts the number of characters that
// proceeds this tag postfix segment that forms the op code (see
// example above).
//
// The reason of this change is so that the postfix can stay the same
// regardless of the prefix, which can increase memory efficiency.
//
iss >> _len >> sep2 >> tp >> eof;
// The next separator to look for is either ':' for older tag postfix, or ','
if (!hex && sep2 == ':')
sep2 = ',';
}
else if (hex && sep == ',') {
// ',' is followed by a single character that indicates the element type.
iss >> tp >> eof;
sep = ':';
sep2 = ',';
}
if (_len < 0 || sep != ':' || sep2 != ',' || tp == 0 || eof != 0)
return -1;
if (hex) {
if (pos-_len < 0)
return -1;
if (_len && recursive && (tag || len)) {
// in case of recursive tag postfix (used by hierarchy element
// map), look for any embedded tag postifx
int next = MappedName::fromRawData(*this, pos-_len, _len).rfind(POSTFIX_TAG);
if (next >= 0) {
next += pos - _len;
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// ^ ^
// | |
// next pos
//
// There maybe other operation codes after this embedded tag
// postfix, search for the sperator.
//
int end;
if (pos == next)
end = -1;
else
end = MappedName::fromRawData(*this, next+1, pos-next-1).find(ELEMENT_MAP_PREFIX);
if (end >= 0) {
end += next+1;
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// ^
// |
// end
_len = pos - end;
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// | |
// -- len --
} else
_len = 0;
}
}
// Now convert the 'len' field back to the length of the remaining name
//
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
// | |
// ----------- len -----------
_len = pos - _len;
}
if(type)
*type = tp;
if(tag) {
if (_tag == 0 && recursive)
return MappedName(*this, 0, _len).findTagInElementName(tag, len, postfix, type, negative);
if(_tag>0 || negative)
*tag = _tag;
else
*tag = -_tag;
}
if(len)
*len = _len;
if(postfix)
this->toString(*postfix, pos);
return pos;
}
}