refactor xml parser, uses faster string to double conversion

This commit is contained in:
Dennis Luxen 2014-04-29 15:33:13 +02:00
parent b7704f0c7f
commit a1ecab2f95
3 changed files with 318 additions and 229 deletions

View File

@ -42,124 +42,150 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/ref.hpp> #include <boost/ref.hpp>
XMLParser::XMLParser(const char * filename, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser(ec, se) { XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se)
: BaseParser(ec, se)
{
inputReader = inputReaderFactory(filename); inputReader = inputReaderFactory(filename);
} }
bool XMLParser::ReadHeader() { bool XMLParser::ReadHeader() { return (xmlTextReaderRead(inputReader) == 1); }
return (xmlTextReaderRead( inputReader ) == 1); bool XMLParser::Parse()
} {
bool XMLParser::Parse() { while (xmlTextReaderRead(inputReader) == 1)
while ( xmlTextReaderRead( inputReader ) == 1 ) { {
const int type = xmlTextReaderNodeType(inputReader); const int type = xmlTextReaderNodeType(inputReader);
// 1 is Element // 1 is Element
if ( type != 1 ) { if (type != 1)
{
continue; continue;
} }
xmlChar *currentName = xmlTextReaderName(inputReader); xmlChar *currentName = xmlTextReaderName(inputReader);
if ( currentName == NULL ) { if (currentName == NULL)
{
continue; continue;
} }
if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) { if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
ImportNode n = _ReadXMLNode(); {
ImportNode n = ReadXMLNode();
ParseNodeInLua(n, lua_state); ParseNodeInLua(n, lua_state);
extractor_callbacks->nodeFunction(n); extractor_callbacks->nodeFunction(n);
// if(!extractor_callbacks->nodeFunction(n))
// std::cerr << "[XMLParser] dense node not parsed" << std::endl;
} }
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) { if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
ExtractionWay way = _ReadXMLWay( ); {
ExtractionWay way = ReadXMLWay();
ParseWayInLua(way, lua_state); ParseWayInLua(way, lua_state);
extractor_callbacks->wayFunction(way); extractor_callbacks->wayFunction(way);
// if(!extractor_callbacks->wayFunction(way))
// std::cerr << "[PBFParser] way not parsed" << std::endl;
} }
if( use_turn_restrictions ) { if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) { {
InputRestrictionContainer r = _ReadXMLRestriction(); InputRestrictionContainer r = ReadXMLRestriction();
if(r.fromWay != UINT_MAX) { if ((UINT_MAX != r.fromWay) && !extractor_callbacks->restrictionFunction(r))
if(!extractor_callbacks->restrictionFunction(r)) { {
std::cerr << "[XMLParser] restriction not parsed" << std::endl; std::cerr << "[XMLParser] restriction not parsed" << std::endl;
} }
} }
}
}
xmlFree(currentName); xmlFree(currentName);
} }
return true; return true;
} }
InputRestrictionContainer XMLParser::_ReadXMLRestriction() { InputRestrictionContainer XMLParser::ReadXMLRestriction()
{
InputRestrictionContainer restriction; InputRestrictionContainer restriction;
std::string except_tag_string; std::string except_tag_string;
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { if (xmlTextReaderIsEmptyElement(inputReader) != 1)
const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) { {
const int depth = xmlTextReaderDepth(inputReader);
while (xmlTextReaderRead(inputReader) == 1)
{
const int childType = xmlTextReaderNodeType(inputReader); const int childType = xmlTextReaderNodeType(inputReader);
if ( childType != 1 && childType != 15 ) { if (childType != 1 && childType != 15)
{
continue; continue;
} }
const int childDepth = xmlTextReaderDepth(inputReader); const int childDepth = xmlTextReaderDepth(inputReader);
xmlChar *childName = xmlTextReaderName(inputReader); xmlChar *childName = xmlTextReaderName(inputReader);
if ( childName == NULL ) { if (childName == NULL)
{
continue; continue;
} }
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) { if (depth == childDepth && childType == 15 &&
xmlStrEqual(childName, (const xmlChar *)"relation") == 1)
{
xmlFree(childName); xmlFree(childName);
break; break;
} }
if ( childType != 1 ) { if (childType != 1)
{
xmlFree(childName); xmlFree(childName);
continue; continue;
} }
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
{
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k"); xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v"); xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
if ( k != NULL && value != NULL ) { if (k != NULL && value != NULL)
if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){ {
if(0 == std::string((const char *) value).find("only_")) { if (xmlStrEqual(k, (const xmlChar *)"restriction") &&
(0 == std::string((const char *)value).find("only_")))
{
restriction.restriction.flags.isOnly = true; restriction.restriction.flags.isOnly = true;
} }
} if (xmlStrEqual(k, (const xmlChar *)"except"))
if ( xmlStrEqual(k, (const xmlChar *) "except") ) { {
except_tag_string = (const char *)value; except_tag_string = (const char *)value;
} }
} }
if ( k != NULL ) { if (k != NULL)
{
xmlFree(k); xmlFree(k);
} }
if ( value != NULL ) { if (value != NULL)
{
xmlFree(value); xmlFree(value);
} }
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) { }
else if (xmlStrEqual(childName, (const xmlChar *)"member") == 1)
{
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref"); xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
if ( ref != NULL ) { if (ref != NULL)
{
xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role"); xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type"); xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) { if (xmlStrEqual(role, (const xmlChar *)"to") &&
xmlStrEqual(type, (const xmlChar *)"way"))
{
restriction.toWay = stringToUint((const char *)ref); restriction.toWay = stringToUint((const char *)ref);
} }
if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) { if (xmlStrEqual(role, (const xmlChar *)"from") &&
xmlStrEqual(type, (const xmlChar *)"way"))
{
restriction.fromWay = stringToUint((const char *)ref); restriction.fromWay = stringToUint((const char *)ref);
} }
if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) { if (xmlStrEqual(role, (const xmlChar *)"via") &&
xmlStrEqual(type, (const xmlChar *)"node"))
{
restriction.restriction.viaNode = stringToUint((const char *)ref); restriction.restriction.viaNode = stringToUint((const char *)ref);
} }
if(NULL != type) { if (NULL != type)
{
xmlFree(type); xmlFree(type);
} }
if(NULL != role) { if (NULL != role)
{
xmlFree(role); xmlFree(role);
} }
if(NULL != ref) { if (NULL != ref)
{
xmlFree(ref); xmlFree(ref);
} }
} }
@ -168,55 +194,71 @@ InputRestrictionContainer XMLParser::_ReadXMLRestriction() {
} }
} }
if( ShouldIgnoreRestriction(except_tag_string) ) { if (ShouldIgnoreRestriction(except_tag_string))
{
restriction.fromWay = UINT_MAX; // workaround to ignore the restriction restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
} }
return restriction; return restriction;
} }
ExtractionWay XMLParser::_ReadXMLWay() { ExtractionWay XMLParser::ReadXMLWay()
{
ExtractionWay way; ExtractionWay way;
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { if (xmlTextReaderIsEmptyElement(inputReader) != 1)
{
const int depth = xmlTextReaderDepth(inputReader); const int depth = xmlTextReaderDepth(inputReader);
while ( xmlTextReaderRead( inputReader ) == 1 ) { while (xmlTextReaderRead(inputReader) == 1)
{
const int childType = xmlTextReaderNodeType(inputReader); const int childType = xmlTextReaderNodeType(inputReader);
if ( childType != 1 && childType != 15 ) { if (childType != 1 && childType != 15)
{
continue; continue;
} }
const int childDepth = xmlTextReaderDepth(inputReader); const int childDepth = xmlTextReaderDepth(inputReader);
xmlChar *childName = xmlTextReaderName(inputReader); xmlChar *childName = xmlTextReaderName(inputReader);
if ( childName == NULL ) { if (childName == NULL)
{
continue; continue;
} }
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) { if (depth == childDepth && childType == 15 &&
xmlStrEqual(childName, (const xmlChar *)"way") == 1)
{
xmlChar *id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id"); xmlChar *id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
way.id = stringToUint((char *)id); way.id = stringToUint((char *)id);
xmlFree(id); xmlFree(id);
xmlFree(childName); xmlFree(childName);
break; break;
} }
if ( childType != 1 ) { if (childType != 1)
{
xmlFree(childName); xmlFree(childName);
continue; continue;
} }
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
{
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k"); xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v"); xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
// cout << "->k=" << k << ", v=" << value << endl;
if ( k != NULL && value != NULL ) { if (k != NULL && value != NULL)
{
way.keyVals.Add(std::string((char *)k), std::string((char *)value)); way.keyVals.Add(std::string((char *)k), std::string((char *)value));
} }
if ( k != NULL ) { if (k != NULL)
{
xmlFree(k); xmlFree(k);
} }
if ( value != NULL ) { if (value != NULL)
{
xmlFree(value); xmlFree(value);
} }
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) { }
else if (xmlStrEqual(childName, (const xmlChar *)"nd") == 1)
{
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref"); xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
if ( ref != NULL ) { if (ref != NULL)
{
way.path.push_back(stringToUint((const char *)ref)); way.path.push_back(stringToUint((const char *)ref));
xmlFree(ref); xmlFree(ref);
} }
@ -227,58 +269,74 @@ ExtractionWay XMLParser::_ReadXMLWay() {
return way; return way;
} }
ImportNode XMLParser::_ReadXMLNode() { ImportNode XMLParser::ReadXMLNode()
{
ImportNode node; ImportNode node;
xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat"); xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
if ( attribute != NULL ) { if (attribute != NULL)
node.lat = static_cast<NodeID>(COORDINATE_PRECISION*atof(( const char* ) attribute ) ); {
node.lat = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
xmlFree(attribute); xmlFree(attribute);
} }
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon"); attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
if ( attribute != NULL ) { if (attribute != NULL)
node.lon = static_cast<NodeID>(COORDINATE_PRECISION*atof(( const char* ) attribute )); {
node.lon = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
xmlFree(attribute); xmlFree(attribute);
} }
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id"); attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
if ( attribute != NULL ) { if (attribute != NULL)
{
node.id = stringToUint((const char *)attribute); node.id = stringToUint((const char *)attribute);
xmlFree(attribute); xmlFree(attribute);
} }
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { if (xmlTextReaderIsEmptyElement(inputReader) != 1)
{
const int depth = xmlTextReaderDepth(inputReader); const int depth = xmlTextReaderDepth(inputReader);
while ( xmlTextReaderRead( inputReader ) == 1 ) { while (xmlTextReaderRead(inputReader) == 1)
{
const int childType = xmlTextReaderNodeType(inputReader); const int childType = xmlTextReaderNodeType(inputReader);
// 1 = Element, 15 = EndElement // 1 = Element, 15 = EndElement
if ( childType != 1 && childType != 15 ) { if (childType != 1 && childType != 15)
{
continue; continue;
} }
const int childDepth = xmlTextReaderDepth(inputReader); const int childDepth = xmlTextReaderDepth(inputReader);
xmlChar *childName = xmlTextReaderName(inputReader); xmlChar *childName = xmlTextReaderName(inputReader);
if ( childName == NULL ) { if (childName == NULL)
{
continue; continue;
} }
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) { if (depth == childDepth && childType == 15 &&
xmlStrEqual(childName, (const xmlChar *)"node") == 1)
{
xmlFree(childName); xmlFree(childName);
break; break;
} }
if ( childType != 1 ) { if (childType != 1)
{
xmlFree(childName); xmlFree(childName);
continue; continue;
} }
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
{
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k"); xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v"); xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
if ( k != NULL && value != NULL ) { if (k != NULL && value != NULL)
node.keyVals.emplace(std::string(reinterpret_cast<char*>(k)), std::string(reinterpret_cast<char*>(value))); {
node.keyVals.emplace(std::string((char *)(k)),
std::string((char *)(value)));
} }
if ( k != NULL ) { if (k != NULL)
{
xmlFree(k); xmlFree(k);
} }
if ( value != NULL ) { if (value != NULL)
{
xmlFree(value); xmlFree(value);
} }
} }

View File

@ -33,20 +33,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <libxml/xmlreader.h> #include <libxml/xmlreader.h>
class XMLParser : public BaseParser { class XMLParser : public BaseParser
{
public: public:
XMLParser( XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se);
const char* filename,
ExtractorCallbacks * ec,
ScriptingEnvironment & se
);
bool ReadHeader(); bool ReadHeader();
bool Parse(); bool Parse();
private: private:
InputRestrictionContainer _ReadXMLRestriction(); InputRestrictionContainer ReadXMLRestriction();
ExtractionWay _ReadXMLWay(); ExtractionWay ReadXMLWay();
ImportNode _ReadXMLNode(); ImportNode ReadXMLNode();
xmlTextReaderPtr inputReader; xmlTextReaderPtr inputReader;
}; };

View File

@ -126,6 +126,40 @@ static inline uint64_t stringToInt64(const std::string& input) {
return value; return value;
} }
// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
static inline double StringToDouble(const char *p)
{
double r = 0.0;
bool neg = false;
if (*p == '-')
{
neg = true;
++p;
}
while (*p >= '0' && *p <= '9')
{
r = (r*10.0) + (*p - '0');
++p;
}
if (*p == '.')
{
double f = 0.0;
int n = 0;
++p;
while (*p >= '0' && *p <= '9')
{
f = (f*10.0) + (*p - '0');
++p;
++n;
}
r += f / std::pow(10.0, n);
}
if (neg)
{
r = -r;
}
return r;
}
static inline void doubleToString(const double value, std::string & output){ static inline void doubleToString(const double value, std::string & output){
output.clear(); output.clear();