Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Yershov <yershov@corp.mail.ru>2015-08-11 16:05:52 +0300
committerAlex Zolotarev <alex@maps.me>2015-09-23 03:01:19 +0300
commitcd6c2837830857381ec91b0578cbf1593ac51ed5 (patch)
tree88b68eb3d6bc311c4aadbc713ad77db4ce32ea0d /generator
parent07f90e34cb993a4430ab8ac865a08e2096336b92 (diff)
Refactor creating XMLElement
Diffstat (limited to 'generator')
-rw-r--r--generator/first_pass_parser.hpp72
-rw-r--r--generator/generator.pro1
-rw-r--r--generator/generator_tests/osm_o5m_source_test.cpp4
-rw-r--r--generator/generator_tests/source_to_element_test.cpp41
-rw-r--r--generator/osm2type.cpp4
-rw-r--r--generator/osm_element.hpp24
-rw-r--r--generator/osm_o5m_source.hpp11
-rw-r--r--generator/osm_source.cpp162
-rw-r--r--generator/osm_source.hpp7
-rw-r--r--generator/xml_element.cpp143
-rw-r--r--generator/xml_element.hpp183
11 files changed, 337 insertions, 315 deletions
diff --git a/generator/first_pass_parser.hpp b/generator/first_pass_parser.hpp
deleted file mode 100644
index 719e45a303..0000000000
--- a/generator/first_pass_parser.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#pragma once
-
-#include "generator/xml_element.hpp"
-#include "generator/osm_decl.hpp"
-
-#include "indexer/mercator.hpp"
-
-#include "base/string_utils.hpp"
-
-
-template <class THolder>
-class FirstPassParser : public BaseOSMParser
-{
- THolder & m_holder;
-
-public:
- FirstPassParser(THolder & holder) : m_holder(holder)
- {
- }
-
-protected:
- virtual void EmitElement(XMLElement * p)
- {
- if (p->tagKey == XMLElement::ET_NODE)
- {
- // store point
-
- // convert to mercator
- p->lat = MercatorBounds::LatToY(p->lat);
- p->lon = MercatorBounds::LonToX(p->lon);
-
- m_holder.AddNode(p->id, p->lat, p->lon);
- }
- else if (p->tagKey == XMLElement::ET_WAY)
- {
- // store way
- WayElement way(p->id);
-
- for (auto const & e: p->childs)
- if (e.tagKey == XMLElement::ET_ND)
- way.nodes.push_back(e.ref);
-
- if (way.IsValid())
- m_holder.AddWay(p->id, way);
- }
- else if (p->tagKey == XMLElement::ET_RELATION)
- {
- // store relation
-
- RelationElement relation;
- for (auto const & e: p->childs)
- {
- if (e.tagKey == XMLElement::ET_MEMBER)
- {
- if (e.type == "node")
- relation.nodes.push_back(make_pair(e.ref, e.role));
- else if (e.type == "way")
- relation.ways.push_back(make_pair(e.ref, e.role));
- // we just ignore type == "relation"
- }
- else if (e.tagKey == XMLElement::ET_TAG)
- {
- // relation tags writing as is
- relation.tags.insert(make_pair(e.k, e.v));
- }
- }
-
- if (relation.IsValid())
- m_holder.AddRelation(p->id, relation);
- }
- }
-};
diff --git a/generator/generator.pro b/generator/generator.pro
index f64455cb40..3db8b861ab 100644
--- a/generator/generator.pro
+++ b/generator/generator.pro
@@ -47,7 +47,6 @@ HEADERS += \
feature_generator.hpp \
feature_merger.hpp \
feature_sorter.hpp \
- first_pass_parser.hpp \
gen_mwm_info.hpp \
generate_info.hpp \
osm2meta.hpp \
diff --git a/generator/generator_tests/osm_o5m_source_test.cpp b/generator/generator_tests/osm_o5m_source_test.cpp
index e87cb7e354..da312cdec3 100644
--- a/generator/generator_tests/osm_o5m_source_test.cpp
+++ b/generator/generator_tests/osm_o5m_source_test.cpp
@@ -32,8 +32,8 @@ UNIT_TEST(OSM_O5M_Source_Node_read_test)
CHECK_EQUAL(em.uid, 395071, ());
CHECK_EQUAL(em.version, 8, ());
CHECK_EQUAL(em.changeset, 12059128, ());
- CHECK_EQUAL(em.lon, 387666704, ());
- CHECK_EQUAL(em.lat, 550927062, ());
+ CHECK_EQUAL(em.lon, 38.7666704, ());
+ CHECK_EQUAL(em.lat, 55.0927062, ());
auto const & tags = em.Tags();
auto tagIterator = tags.begin();
diff --git a/generator/generator_tests/source_to_element_test.cpp b/generator/generator_tests/source_to_element_test.cpp
index 15e8ac4db1..2dd97cf0a4 100644
--- a/generator/generator_tests/source_to_element_test.cpp
+++ b/generator/generator_tests/source_to_element_test.cpp
@@ -14,24 +14,16 @@
#include "source_data.hpp"
-struct DummyParser : public BaseOSMParser
-{
- vector<XMLElement> & m_e;
- DummyParser(vector<XMLElement> & e) : BaseOSMParser() , m_e(e) {}
- void EmitElement(XMLElement * p) override
- {
- m_e.push_back(*p);
- }
-};
-
UNIT_TEST(Source_To_Element_create_from_xml_test)
{
istringstream ss(way_xml_data);
SourceReader reader(ss);
vector<XMLElement> elements;
- DummyParser parser(elements);
- ParseXMLSequence(reader, parser);
+ BuildFeaturesFromXML(reader, [&elements](XMLElement * e)
+ {
+ elements.push_back(*e);
+ });
TEST_EQUAL(elements.size(), 10, (elements));
}
@@ -43,8 +35,10 @@ UNIT_TEST(Source_To_Element_create_from_o5m_test)
SourceReader reader(ss);
vector<XMLElement> elements;
- DummyParser parser(elements);
- BuildFeaturesFromO5M(reader, parser);
+ BuildFeaturesFromO5M(reader, [&elements](XMLElement * e)
+ {
+ elements.push_back(*e);
+ });
TEST_EQUAL(elements.size(), 10, (elements));
}
@@ -54,16 +48,25 @@ UNIT_TEST(Source_To_Element_check_equivalence)
SourceReader readerXML(ss1);
vector<XMLElement> elementsXML;
- DummyParser parserForXML(elementsXML);
- ParseXMLSequence(readerXML, parserForXML);
+ BuildFeaturesFromXML(readerXML, [&elementsXML](XMLElement * e)
+ {
+ elementsXML.push_back(*e);
+ });
string src(begin(relation_o5m_data), end(relation_o5m_data));
istringstream ss2(src);
SourceReader readerO5M(ss2);
vector<XMLElement> elementsO5M;
- DummyParser parserForO5M(elementsO5M);
- BuildFeaturesFromO5M(readerO5M, parserForO5M);
+ BuildFeaturesFromO5M(readerO5M, [&elementsO5M](XMLElement * e)
+ {
+ elementsO5M.push_back(*e);
+ });
+
+ TEST_EQUAL(elementsXML.size(), elementsO5M.size(), ());
- TEST_EQUAL(elementsXML, elementsO5M, ());
+ for (size_t i = 0; i < elementsO5M.size(); ++i)
+ {
+ TEST_EQUAL(elementsXML[i], elementsO5M[i], ());
+ }
}
diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp
index 6a2878834a..7a764460ca 100644
--- a/generator/osm2type.cpp
+++ b/generator/osm2type.cpp
@@ -68,7 +68,7 @@ namespace ftype
TResult res = TResult();
for (auto & e : p->childs)
{
- if (e.tagKey == XMLElement::ET_TAG)
+ if (e.type == XMLElement::EntityType::Tag)
{
if (e.k.empty() || is_skip_tag(e.k))
continue;
@@ -319,7 +319,7 @@ namespace ftype
void ApplyRules(initializer_list<Rule<FuncT>> const & rules) const
{
for (auto & e : m_element->childs)
- if (e.tagKey == XMLElement::ET_TAG)
+ if (e.type == XMLElement::EntityType::Tag)
for (auto const & rule: rules)
if (e.k == rule.key)
{
diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp
index a0e4f8cd48..fcbf7de3e9 100644
--- a/generator/osm_element.hpp
+++ b/generator/osm_element.hpp
@@ -23,7 +23,7 @@
/// @param TEmitter Feature accumulating policy
/// @param THolder Nodes, ways, relations holder
template <class TEmitter, class THolder>
-class SecondPassParser : public BaseOSMParser
+class SecondPassParser
{
TEmitter & m_emitter;
THolder & m_holder;
@@ -125,7 +125,7 @@ class SecondPassParser : public BaseOSMParser
void GetNameKeys(NameKeysT & keys) const
{
for (auto const & p : m_current->childs)
- if (p.tagKey == XMLElement::ET_TAG)
+ if (p.type == XMLElement::EntityType::Tag)
{
if (strings::StartsWith(p.k, "name"))
keys.insert(p.k);
@@ -145,7 +145,7 @@ class SecondPassParser : public BaseOSMParser
return;
}
- bool const isWay = (m_current->tagKey == XMLElement::ET_WAY);
+ bool const isWay = (m_current->type == XMLElement::EntityType::Way);
bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e);
NameKeysT nameKeys;
@@ -201,7 +201,7 @@ class SecondPassParser : public BaseOSMParser
// Get tags from parent relations.
m_relationsProcess.Reset(p->id, p);
- if (p->tagKey == XMLElement::ET_NODE)
+ if (p->type == XMLElement::EntityType::Node)
{
// additional process of nodes ONLY if there is no native types
FeatureParams fp;
@@ -209,7 +209,7 @@ class SecondPassParser : public BaseOSMParser
if (!ftype::IsValidTypes(fp))
m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess);
}
- else if (p->tagKey == XMLElement::ET_WAY)
+ else if (p->type == XMLElement::EntityType::Way)
{
// always make additional process of ways
m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess);
@@ -403,13 +403,13 @@ class SecondPassParser : public BaseOSMParser
public:
/// The main entry point for parsing process.
- virtual void EmitElement(XMLElement * p)
+ void EmitElement(XMLElement * p)
{
FeatureParams params;
if (!ParseType(p, params))
return;
- if (p->tagKey == XMLElement::ET_NODE)
+ if (p->type == XMLElement::EntityType::Node)
{
m2::PointD pt;
if (p->childs.empty() || !GetPoint(p->id, pt))
@@ -417,14 +417,14 @@ public:
EmitPoint(pt, params, osm::Id::Node(p->id));
}
- else if (p->tagKey == XMLElement::ET_WAY)
+ else if (p->type == XMLElement::EntityType::Way)
{
FeatureBuilderT ft;
// Parse geometry.
for (auto const & e : p->childs)
{
- if (e.tagKey == XMLElement::ET_ND)
+ if (e.type == XMLElement::EntityType::Nd)
{
m2::PointD pt;
if (!GetPoint(e.ref, pt))
@@ -450,7 +450,7 @@ public:
EmitLine(ft, params, isCoastLine);
}
- else if (p->tagKey == XMLElement::ET_RELATION)
+ else if (p->type == XMLElement::EntityType::Relation)
{
{
// 1. Check, if this is our processable relation. Here we process only polygon relations.
@@ -458,7 +458,7 @@ public:
size_t const count = p->childs.size();
for (; i < count; ++i)
{
- if (p->childs[i].tagKey == XMLElement::ET_TAG &&
+ if (p->childs[i].type == XMLElement::EntityType::Tag &&
p->childs[i].k == "type" &&
p->childs[i].v == "multipolygon")
{
@@ -475,7 +475,7 @@ public:
// 3. Iterate ways to get 'outer' and 'inner' geometries
for (auto const & e : p->childs)
{
- if (e.tagKey == XMLElement::ET_MEMBER && e.type == "way")
+ if (e.type == XMLElement::EntityType::Member && e.memberType == XMLElement::EntityType::Way)
{
if (e.role == "outer")
outer.AddWay(e.ref);
diff --git a/generator/osm_o5m_source.hpp b/generator/osm_o5m_source.hpp
index 23700e9baf..be62eac092 100644
--- a/generator/osm_o5m_source.hpp
+++ b/generator/osm_o5m_source.hpp
@@ -242,11 +242,12 @@ public:
struct Entity
{
+ using EntityType = O5MSource::EntityType;
EntityType type = EntityType::Reset;
int64_t id = 0;
uint64_t version = 0;
- int32_t lon = 0;
- int32_t lat = 0;
+ double lon = 0;
+ double lat = 0;
int64_t timestamp = 0;
int64_t changeset = 0;
uint64_t uid = 0;
@@ -454,10 +455,12 @@ public:
}
}
+#define DECODE_O5M_COORD(coord) (static_cast<double>(coord) / 1E+7)
+
void ReadLonLat(Entity * const e)
{
- e->lon = (m_lon += ReadVarInt());
- e->lat = (m_lat += ReadVarInt());
+ e->lon = DECODE_O5M_COORD(m_lon += ReadVarInt());
+ e->lat = DECODE_O5M_COORD(m_lat += ReadVarInt());
}
O5MSource * ReadEntity(Entity * const entity)
diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp
index 5c9ff74260..482382d411 100644
--- a/generator/osm_source.cpp
+++ b/generator/osm_source.cpp
@@ -1,7 +1,6 @@
#include "generator/coastlines_generator.hpp"
#include "generator/data_cache_file.hpp"
#include "generator/feature_generator.hpp"
-#include "generator/first_pass_parser.hpp"
#include "generator/osm_decl.hpp"
#include "generator/osm_element.hpp"
#include "generator/osm_o5m_source.hpp"
@@ -20,8 +19,6 @@
#include "defines.hpp"
-#define DECODE_O5M_COORD(coord) (static_cast<double>(coord) / 1E+7)
-
SourceReader::SourceReader()
: m_file(unique_ptr<istream,Deleter>(&cin, Deleter(false)))
{
@@ -343,70 +340,96 @@ public:
};
} // anonymous namespace
-template <typename HolderT>
-void BuildIntermediateDataFromO5M(SourceReader & stream, HolderT & holder)
-{
- using TType = osm::O5MSource::EntityType;
- osm::O5MSource dataset([&stream](uint8_t * buffer, size_t size)
- {
- return stream.Read(reinterpret_cast<char *>(buffer), size);
- });
-
- for (auto const & em : dataset)
+template <typename TElement, typename TCache>
+void AddElementToCache(TCache & cache, TElement const & em)
+{
+ switch (em.type)
{
- switch (em.type)
+ case TElement::EntityType::Node:
{
- case TType::Node:
+ // Could do something with em.id, em.lon, em.lat here
+ // lon and lat are ints in 1E+7 * degree units
+ // convert to mercator
+ auto const pt = MercatorBounds::FromLatLon(em.lat, em.lon);
+ cache.AddNode(em.id, pt.y, pt.x);
+ break;
+ }
+ case TElement::EntityType::Way:
+ {
+ // store way
+ WayElement way(em.id);
+ for (uint64_t nd : em.Nodes())
+ way.nodes.push_back(nd);
+
+ if (way.IsValid())
+ cache.AddWay(em.id, way);
+ break;
+ }
+ case TElement::EntityType::Relation:
+ {
+ // store relation
+ RelationElement relation;
+ for (auto const & member : em.Members())
{
- // Could do something with em.id, em.lon, em.lat here
- // lon and lat are ints in 1E+7 * degree units
- // convert to mercator
- auto const pt = MercatorBounds::FromLatLon(DECODE_O5M_COORD(em.lat), DECODE_O5M_COORD(em.lon));
- holder.AddNode(em.id, pt.y, pt.x);
- break;
+ // Could do something with member ref (way or node or rel id depends on type), type and
+ // role
+ if (member.type == TElement::EntityType::Node)
+ relation.nodes.emplace_back(make_pair(member.ref, string(member.role)));
+ else if (member.type == TElement::EntityType::Way)
+ relation.ways.emplace_back(make_pair(member.ref, string(member.role)));
+ // we just ignore type == "relation"
}
- case TType::Way:
- {
- // store way
- WayElement way(em.id);
- for (uint64_t nd : em.Nodes())
- way.nodes.push_back(nd);
- if (way.IsValid())
- holder.AddWay(em.id, way);
- break;
- }
- case TType::Relation:
- {
- // store relation
- RelationElement relation;
- for (auto const & member : em.Members())
- {
- // Could do something with member ref (way or node or rel id depends on type), type and
- // role
- if (member.type == TType::Node)
- relation.nodes.emplace_back(make_pair(member.ref, string(member.role)));
- else if (member.type == TType::Way)
- relation.ways.emplace_back(make_pair(member.ref, string(member.role)));
- // we just ignore type == "relation"
- }
-
- for (auto const & tag : em.Tags())
- relation.tags.emplace(make_pair(string(tag.key), string(tag.value)));
+ for (auto const & tag : em.Tags())
+ relation.tags.emplace(make_pair(string(tag.key), string(tag.value)));
- if (relation.IsValid())
- holder.AddRelation(em.id, relation);
+ if (relation.IsValid())
+ cache.AddRelation(em.id, relation);
- break;
- }
- default:
- break;
+ break;
}
+ default:
+ break;
}
}
-void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser)
+template <typename TCache>
+void BuildIntermediateDataFromXML(SourceReader & stream, TCache & cache)
+{
+ BaseOSMParser parser([&](XMLElement * e)
+ {
+ AddElementToCache(cache, *e);
+ });
+
+ ParseXMLSequence(stream, parser);
+}
+
+void BuildFeaturesFromXML(SourceReader & stream, function<void(XMLElement *)> processor)
+{
+ BaseOSMParser parser([&](XMLElement * e)
+ {
+ processor(e);
+ });
+
+ ParseXMLSequence(stream, parser);
+}
+
+template <typename TCache>
+void BuildIntermediateDataFromO5M(SourceReader & stream, TCache & cache)
+{
+ using TType = osm::O5MSource::EntityType;
+
+ osm::O5MSource dataset([&stream](uint8_t * buffer, size_t size)
+ {
+ return stream.Read(reinterpret_cast<char *>(buffer), size);
+ });
+
+ for (auto const & e : dataset)
+ AddElementToCache(cache, e);
+}
+
+void BuildFeaturesFromO5M(SourceReader & stream, function<void(XMLElement *)> processor)
{
using TType = osm::O5MSource::EntityType;
@@ -424,33 +447,33 @@ void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser)
{
case TType::Node:
{
- p.tagKey = XMLElement::ET_NODE;
- p.lat = DECODE_O5M_COORD(em.lat);
- p.lon = DECODE_O5M_COORD(em.lon);
+ p.type = XMLElement::EntityType::Node;
+ p.lat = em.lat;
+ p.lon = em.lon;
break;
}
case TType::Way:
{
- p.tagKey = XMLElement::ET_WAY;
+ p.type = XMLElement::EntityType::Way;
for (uint64_t nd : em.Nodes())
p.AddND(nd);
break;
}
case TType::Relation:
{
- p.tagKey = XMLElement::ET_RELATION;
+ p.type = XMLElement::EntityType::Relation;
for (auto const & member : em.Members())
{
switch (member.type)
{
case TType::Node:
- p.AddMEMBER(member.ref, "node", member.role);
+ p.AddMEMBER(member.ref, XMLElement::EntityType::Node, member.role);
break;
case TType::Way:
- p.AddMEMBER(member.ref, "way", member.role);
+ p.AddMEMBER(member.ref, XMLElement::EntityType::Way, member.role);
break;
case TType::Relation:
- p.AddMEMBER(member.ref, "relation", member.role);
+ p.AddMEMBER(member.ref, XMLElement::EntityType::Relation, member.role);
break;
default: break;
@@ -464,7 +487,7 @@ void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser)
for (auto const & tag : em.Tags())
p.AddKV(tag.key, tag.value);
- parser.EmitElement(&p);
+ processor(&p);
}
}
@@ -488,14 +511,16 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info)
bucketer, cache, info.m_makeCoasts ? classif().GetCoastType() : 0,
info.GetAddressesFileName());
+ auto fn = [&parser](XMLElement * e) { parser.EmitElement(e); };
+
SourceReader reader = info.m_osmFileName.empty() ? SourceReader() : SourceReader(info.m_osmFileName);
switch (info.m_osmFileType)
{
case feature::GenerateInfo::OsmSourceType::XML:
- ParseXMLSequence(reader, parser);
+ BuildFeaturesFromXML(reader, fn);
break;
case feature::GenerateInfo::OsmSourceType::O5M:
- BuildFeaturesFromO5M(reader, parser);
+ BuildFeaturesFromO5M(reader, fn);
break;
}
@@ -533,11 +558,8 @@ bool GenerateIntermediateDataImpl(feature::GenerateInfo & info)
switch (info.m_osmFileType)
{
case feature::GenerateInfo::OsmSourceType::XML:
- {
- FirstPassParser<TDataCache> parser(cache);
- ParseXMLSequence(reader, parser);
+ BuildIntermediateDataFromXML(reader, cache);
break;
- }
case feature::GenerateInfo::OsmSourceType::O5M:
BuildIntermediateDataFromO5M(reader, cache);
break;
diff --git a/generator/osm_source.hpp b/generator/osm_source.hpp
index 246534153f..9db9f85cdd 100644
--- a/generator/osm_source.hpp
+++ b/generator/osm_source.hpp
@@ -1,9 +1,11 @@
#pragma once
#include "generator/generate_info.hpp"
+#include "generator/xml_element.hpp"
#include "std/iostream.hpp"
#include "std/unique_ptr.hpp"
+#include "std/function.hpp"
class SourceReader
{
@@ -33,7 +35,6 @@ public:
bool GenerateFeatures(feature::GenerateInfo & info);
bool GenerateIntermediateData(feature::GenerateInfo & info);
-class BaseOSMParser;
-
-void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser);
+void BuildFeaturesFromO5M(SourceReader & stream, function<void(XMLElement *)> processor);
+void BuildFeaturesFromXML(SourceReader & stream, function<void(XMLElement *)> processor);
diff --git a/generator/xml_element.cpp b/generator/xml_element.cpp
index 07972865c0..5c03965117 100644
--- a/generator/xml_element.cpp
+++ b/generator/xml_element.cpp
@@ -1,7 +1,6 @@
#include "generator/xml_element.hpp"
#include "coding/parse_xml.hpp"
-#include "base/string_utils.hpp"
#include "std/cstdio.hpp"
#include "std/algorithm.hpp"
@@ -12,7 +11,7 @@ void XMLElement::AddKV(string const & k, string const & v)
childs.push_back(XMLElement());
XMLElement & e = childs.back();
- e.tagKey = ET_TAG;
+ e.type = EntityType::Tag;
e.k = k;
e.v = v;
}
@@ -22,44 +21,67 @@ void XMLElement::AddND(uint64_t ref)
childs.push_back(XMLElement());
XMLElement & e = childs.back();
- e.tagKey = ET_ND;
+ e.type = EntityType::Nd;
e.ref = ref;
}
-void XMLElement::AddMEMBER(uint64_t ref, string const & type, string const & role)
+void XMLElement::AddMEMBER(uint64_t ref, EntityType type, string const & role)
{
childs.push_back(XMLElement());
XMLElement & e = childs.back();
- e.tagKey = ET_MEMBER;
+ e.type = EntityType::Member;
e.ref = ref;
- e.type = type;
+ e.memberType = type;
e.role = role;
}
+string DebugPrint(XMLElement::EntityType e)
+{
+ switch (e)
+ {
+ case XMLElement::EntityType::Unknown:
+ return "Unknown";
+ case XMLElement::EntityType::Way:
+ return "Way";
+ case XMLElement::EntityType::Tag:
+ return "Tag";
+ case XMLElement::EntityType::Relation:
+ return "Relation";
+ case XMLElement::EntityType::Osm:
+ return "Osm";
+ case XMLElement::EntityType::Node:
+ return "Node";
+ case XMLElement::EntityType::Nd:
+ return "Nd";
+ case XMLElement::EntityType::Member:
+ return "Member";
+ }
+}
+
string XMLElement::ToString(string const & shift) const
{
stringstream ss;
ss << (shift.empty() ? "\n" : shift);
- switch (tagKey)
+ switch (type)
{
- case ET_NODE:
- ss << "Node: " << id << " (" << fixed << setw(7) << lat << ", " << lon << ")";
+ case EntityType::Node:
+ ss << "Node: " << id << " (" << fixed << setw(7) << lat << ", " << lon << ")" << " subelements: " << childs.size();
break;
- case ET_ND:
+ case EntityType::Nd:
ss << "Nd ref: " << ref;
break;
- case ET_WAY:
- ss << "Way: " << id << " elements: " << childs.size();
+ case EntityType::Way:
+ ss << "Way: " << id << " subelements: " << childs.size();
break;
- case ET_RELATION:
- ss << "Relation: " << id << " elements: " << childs.size();
+ case EntityType::Relation:
+ ss << "Relation: " << id << " subelements: " << childs.size();
break;
- case ET_TAG:
+ case EntityType::Tag:
ss << "Tag: " << k << " = " << v;
break;
- case ET_MEMBER:
- ss << "Member: " << ref << " type: " << type << " role: " << role;
+ case EntityType::Member:
+ ss << "Member: " << ref << " type: " << DebugPrint(memberType) << " role: " << role;
break;
default:
ss << "Unknown element";
@@ -79,90 +101,3 @@ string DebugPrint(XMLElement const & e)
{
return e.ToString();
}
-
-
-void BaseOSMParser::AddAttr(string const & key, string const & value)
-{
- if (!m_current)
- return;
-
- if (key == "id")
- CHECK ( strings::to_uint64(value, m_current->id), ("Unknown element with invalid id : ", value) );
- else if (key == "lon")
- CHECK ( strings::to_double(value, m_current->lon), ("Bad node lon : ", value) );
- else if (key == "lat")
- CHECK ( strings::to_double(value, m_current->lat), ("Bad node lat : ", value) );
- else if (key == "ref")
- CHECK ( strings::to_uint64(value, m_current->ref), ("Bad node ref in way : ", value) );
- else if (key == "k")
- m_current->k = value;
- else if (key == "v")
- m_current->v = value;
- else if (key == "type")
- m_current->type = value;
- else if (key == "role")
- m_current->role = value;
-}
-
-bool BaseOSMParser::Push(string const & tagName)
-{
- ASSERT_GREATER_OR_EQUAL(tagName.size(), 2, ());
-
- // As tagKey we use first two char of tag name.
- XMLElement::ETag tagKey = XMLElement::ETag(*reinterpret_cast<uint16_t const *>(tagName.data()));
-
- switch (tagKey)
- {
- // This tags will ignored in Push function.
- case XMLElement::ET_MEMBER:
- case XMLElement::ET_TAG:
- case XMLElement::ET_ND:
- return false;
- default: break;
- }
-
- switch (++m_depth)
- {
- case 1:
- m_current = nullptr;
- break;
- case 2:
- m_current = &m_parent;
- m_current->tagKey = tagKey;
- break;
- default:
- m_current = &m_child;
- m_current->tagKey = tagKey;
- }
- return true;
-}
-
-void BaseOSMParser::Pop(string const &)
-{
- switch (--m_depth)
- {
- case 0:
- break;
-
- case 1:
- EmitElement(m_current);
- m_parent.Clear();
- break;
-
- default:
- switch (m_child.tagKey)
- {
- case XMLElement::ET_MEMBER:
- m_parent.AddMEMBER(m_child.ref, m_child.type, m_child.role);
- break;
- case XMLElement::ET_TAG:
- m_parent.AddKV(m_child.k, m_child.v);
- break;
- case XMLElement::ET_ND:
- m_parent.AddND(m_child.ref);
- default: break;
- }
- m_current = &m_parent;
- m_child.Clear();
- }
-}
diff --git a/generator/xml_element.hpp b/generator/xml_element.hpp
index 42fb3b0540..3dd38745c2 100644
--- a/generator/xml_element.hpp
+++ b/generator/xml_element.hpp
@@ -1,52 +1,53 @@
#pragma once
#include "base/math.hpp"
-
+#include "base/string_utils.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
#include "std/map.hpp"
#include "std/iostream.hpp"
+#include "std/function.hpp"
#include "std/exception.hpp"
#include "std/iomanip.hpp"
struct XMLElement
{
- enum ETag
+ enum class EntityType
{
- ET_UNKNOWN = 0,
- ET_OSM = 0x736F, // "os"
- ET_NODE = 0x6F6E, // "no"
- ET_WAY = 0x6177, // "wa"
- ET_RELATION = 0x6572, // "re"
- ET_TAG = 0x6174, // "ta"
- ET_ND = 0x646E, // "nd"
- ET_MEMBER = 0x656D // "me"
+ Unknown = 0x0,
+ Node = 0x6F6E, // "no"
+ Way = 0x6177, // "wa"
+ Relation = 0x6572, // "re"
+ Tag = 0x6174, // "ta"
+ Nd = 0x646E, // "nd"
+ Member = 0x656D, // "me"
+ Osm = 0x736F, // "os"
};
- ETag tagKey = ET_UNKNOWN;
+ EntityType type = EntityType::Unknown;
uint64_t id = 0;
double lon = 0;
double lat = 0;
uint64_t ref = 0;
string k;
string v;
- string type;
+ EntityType memberType = EntityType::Unknown;
string role;
vector<XMLElement> childs;
void Clear()
{
- tagKey = ET_UNKNOWN;
+ type = EntityType::Unknown;
id = 0;
lon = 0;
lat = 0;
ref = 0;
k.clear();
v.clear();
- type.clear();
+ memberType = EntityType::Unknown;
role.clear();
childs.clear();
@@ -54,25 +55,83 @@ struct XMLElement
string ToString(string const & shift = string()) const;
+ vector<uint64_t> Nodes() const
+ {
+ vector<uint64_t> nds;
+ for (auto const & e : childs)
+ {
+ if (e.type == EntityType::Nd)
+ nds.push_back(e.ref);
+ }
+ return move(nds);
+ }
+
+ struct Member
+ {
+ uint64_t ref;
+ EntityType type;
+ string role;
+ };
+
+ static EntityType StringToEntityType(string const & t)
+ {
+ if (t == "way")
+ return EntityType::Way;
+ if (t == "node")
+ return EntityType::Node;
+ if (t == "relation")
+ return EntityType::Relation;
+ ASSERT(false, ("Unknown type", t));
+ return EntityType::Unknown;
+ }
+
+ vector<Member> Members() const
+ {
+ vector<Member> members;
+ for (auto const & e : childs)
+ {
+ if (e.type == EntityType::Member)
+ members.push_back({e.ref, e.memberType, e.role});
+ }
+ return move(members);
+ }
+
+ struct Tag
+ {
+ string key;
+ string value;
+ };
+
+ vector<Tag> Tags() const
+ {
+ vector<Tag> tags;
+ for (auto const & e : childs)
+ {
+ if (e.type == EntityType::Tag)
+ tags.push_back({e.k, e.v});
+ }
+ return move(tags);
+ }
+
bool operator == (XMLElement const & e) const
{
return (
- tagKey == e.tagKey
+ type == e.type
&& id == e.id
&& my::AlmostEqualAbs(lon, e.lon, 1e-7)
&& my::AlmostEqualAbs(lat, e.lat, 1e-7)
&& ref == e.ref
&& k == e.k
&& v == e.v
- && type == e.type
+ && memberType == e.memberType
&& role == e.role
- && childs == childs
+ && childs == e.childs
);
}
void AddKV(string const & k, string const & v);
void AddND(uint64_t ref);
- void AddMEMBER(uint64_t ref, string const & type, string const & role);
+ void AddMEMBER(uint64_t ref, EntityType type, string const & role);
};
string DebugPrint(XMLElement const & e);
@@ -82,18 +141,90 @@ class BaseOSMParser
XMLElement m_parent;
XMLElement m_child;
- size_t m_depth;
+ size_t m_depth = 0;
+ XMLElement * m_current = nullptr;
-protected:
- XMLElement * m_current;
+ using TEmmiterFn = function<void(XMLElement *)>;
+ TEmmiterFn m_EmmiterFn;
public:
- BaseOSMParser() : m_depth(0), m_current(0) {}
+ BaseOSMParser(TEmmiterFn fn) : m_EmmiterFn(fn) {}
- void AddAttr(string const & key, string const & value);
- bool Push(string const & tagName);
- void Pop(string const &);
void CharData(string const &) {}
- virtual void EmitElement(XMLElement * p) = 0;
+ void AddAttr(string const & key, string const & value)
+ {
+ if (!m_current)
+ return;
+
+ if (key == "id")
+ CHECK ( strings::to_uint64(value, m_current->id), ("Unknown element with invalid id : ", value) );
+ else if (key == "lon")
+ CHECK ( strings::to_double(value, m_current->lon), ("Bad node lon : ", value) );
+ else if (key == "lat")
+ CHECK ( strings::to_double(value, m_current->lat), ("Bad node lat : ", value) );
+ else if (key == "ref")
+ CHECK ( strings::to_uint64(value, m_current->ref), ("Bad node ref in way : ", value) );
+ else if (key == "k")
+ m_current->k = value;
+ else if (key == "v")
+ m_current->v = value;
+ else if (key == "type")
+ m_current->memberType = XMLElement::StringToEntityType(value);
+ else if (key == "role")
+ m_current->role = value;
+ }
+
+ bool Push(string const & tagName)
+ {
+ ASSERT_GREATER_OR_EQUAL(tagName.size(), 2, ());
+
+ // As tagKey we use first two char of tag name.
+ XMLElement::EntityType tagKey = XMLElement::EntityType(*reinterpret_cast<uint16_t const *>(tagName.data()));
+
+ switch (++m_depth)
+ {
+ case 1:
+ m_current = nullptr;
+ break;
+ case 2:
+ m_current = &m_parent;
+ m_current->type = tagKey;
+ break;
+ default:
+ m_current = &m_child;
+ m_current->type = tagKey;
+ }
+ return true;
+ }
+
+ void Pop(string const & v)
+ {
+ switch (--m_depth)
+ {
+ case 0:
+ break;
+
+ case 1:
+ m_EmmiterFn(m_current);
+ m_parent.Clear();
+ break;
+
+ default:
+ switch (m_child.type)
+ {
+ case XMLElement::EntityType::Member:
+ m_parent.AddMEMBER(m_child.ref, m_child.memberType, m_child.role);
+ break;
+ case XMLElement::EntityType::Tag:
+ m_parent.AddKV(m_child.k, m_child.v);
+ break;
+ case XMLElement::EntityType::Nd:
+ m_parent.AddND(m_child.ref);
+ default: break;
+ }
+ m_current = &m_parent;
+ m_child.Clear();
+ }
+ }
};