text: 
  #include "osm_store.h"
  #include <iostream>
  using namespace std;
  namespace bg = boost::geometry;
  
  // Views of data structures.
  //
  
  NodeList<NodeVec::const_iterator> makeNodeList(const NodeVec &nodeVec) {
  	return { nodeVec.cbegin(), nodeVec.cend() };
  }
  
  WayList<WayVec::const_iterator> makeWayList( const WayVec &outerWayVec, const WayVec &innerWayVec) {
  	return { outerWayVec.cbegin(), outerWayVec.cend(), innerWayVec.cbegin(), innerWayVec.cend() };
  }
  
  //
  // Internal data structures.
  //
  
  LatpLon NodeStore::at(NodeID i) const {
  	try {
  		return mLatpLons.at(i);
  	}
  	catch (std::out_of_range &err){
  		stringstream ss;
  		ss << "Could not find node " << i;
  		throw std::out_of_range(ss.str());
  	}
  }
  
  // @brief Return whether a latp/lon pair is on the store.
  // @param i Any possible OSM ID
  // @return 1 if found, 0 otherwise
  // @note This function is named as count for consistent naming with stl functions.
  size_t NodeStore::count(NodeID i) const {
  	return mLatpLons.count(i);
  }
  
  // @brief Insert a latp/lon pair.
  // @param i OSM ID of a node
  // @param coord a latp/lon pair to be inserted
  // @invariant The OSM ID i must be larger than previously inserted OSM IDs of nodes
  //            (though unnecessarily for current impl, future impl may impose that)
  void NodeStore::insert_back(NodeID i, LatpLon coord) {
  	mLatpLons.emplace(i, coord);
  }
  
  // @brief Make the store empty
  void NodeStore::clear() {
  	mLatpLons.clear();
  }
  
  size_t NodeStore::size() { return mLatpLons.size(); }
  
  
  // way store
  
  // @brief Lookup a node list
  // @param i OSM ID of a way
  // @return A node list
  // @exception NotFound
  NodeList<WayStoreIterator> WayStore::at(WayID i) const {
  	try {
  		const auto &way = mNodeLists.at(i);
  		return { way.cbegin(), way.cend() };
  	}
  	catch (std::out_of_range &err){
  		stringstream ss;
  		ss << "Could not find way " << i;
  		throw std::out_of_range(ss.str());
  	}
  }
  
  bool WayStore::isClosed(WayID i) const {
  	const auto &way = mNodeLists.at(i);
  	return way.front() == way.back();
  }
  
  NodeVec WayStore::nodesFor(WayID i) const {
  	return mNodeLists.at(i);
  }
  NodeID WayStore::firstNode(WayID i) const {
  	return mNodeLists.at(i).front();
  }
  NodeID WayStore::lastNode(WayID i) const {
  	return mNodeLists.at(i).back();
  }
  
  // @brief Return whether a node list is on the store.
  // @param i Any possible OSM ID
  // @return 1 if found, 0 otherwise
  // @note This function is named as count for consistent naming with stl functions.
  size_t WayStore::count(WayID i) const {
  	return mNodeLists.count(i);
  }
  
  // @brief Insert a node list.
  // @param i OSM ID of a way
  // @param nodeVec a node vector to be inserted
  // @invariant The OSM ID i must be larger than previously inserted OSM IDs of ways
  //            (though unnecessarily for current impl, future impl may impose that)
  void WayStore::insert_back(WayID i, const NodeVec &nodeVec) {
  	mNodeLists.emplace(i, nodeVec);
  }
  
  // @brief Make the store empty
  void WayStore::clear() {
  	mNodeLists.clear();
  }
  
  size_t WayStore::size() { return mNodeLists.size(); }
  
  
  // relation store
  
  // @brief Lookup a way list
  // @param i Pseudo OSM ID of a relational way
  // @return A way list
  // @exception NotFound
  WayList<RelationStoreIterator> RelationStore::at(WayID i) const {
  	try
  	{
  		const auto &outInList = mOutInLists.at(i);
  		return { outInList.first.cbegin(), outInList.first.cend(),
  			outInList.second.cbegin(), outInList.second.cend() };
  	}
  	catch (std::out_of_range &err){
  		stringstream ss;
  		ss << "Could not find pseudo OSM ID of polygon " << i;
  		throw std::out_of_range(ss.str());
  	}
  }
  
  // @brief Return whether a way list is on the store.
  // @param i Any possible OSM ID
  // @return 1 if found, 0 otherwise
  // @note This function is named as count for consistent naming with stl functions.
  size_t RelationStore::count(WayID i) const {
  	return mOutInLists.count(i);
  }
  
  // @brief Insert a way list.
  // @param i Pseudo OSM ID of a relation
  // @param outerWayVec A outer way vector to be inserted
  // @param innerWayVec A inner way vector to be inserted
  // @invariant The pseudo OSM ID i must be smaller than previously inserted pseudo OSM IDs of relations
  //            (though unnecessarily for current impl, future impl may impose that)
  void RelationStore::insert_front(WayID i, const WayVec &outerWayVec, const WayVec &innerWayVec) {
  	mOutInLists.emplace(i, make_pair(outerWayVec, innerWayVec));
  }
  
  // @brief Make the store empty
  void RelationStore::clear() {
  	mOutInLists.clear();
  }
  
  size_t RelationStore::size() { return mOutInLists.size(); }
  
  
  //
  // OSM store, containing all above.
  //
  
  void OSMStore::reportSize() {
  	cout << "Stored " << nodes.size() << " nodes, " << ways.size() << " ways, " << relations.size() << " relations" << endl;
  }
  
  void OSMStore::clear()
  {
  	nodes.clear();
  	ways.clear();
  	relations.clear();
  }
  
  // Relation -> MultiPolygon
  MultiPolygon OSMStore::wayListMultiPolygon(WayID relId) const {
  	return wayListMultiPolygon(relations.at(relId));
  }
  
  MultiPolygon OSMStore::wayListMultiPolygon(const WayVec &outerWayVec, const WayVec &innerWayVec) const {
  	return wayListMultiPolygon(makeWayList(outerWayVec, innerWayVec));
  }
  
  Linestring OSMStore::wayListLinestring(const WayVec &outerWayVec, const WayVec &innerWayVec) const {
  	MultiPolygon mp = wayListMultiPolygon(makeWayList(outerWayVec, innerWayVec));
  	if(mp.size()>=1)
  	{
  		Linestring out;
  		for(auto pt: mp[0].outer())
  			bg::append(out, pt);
  		return out;
  	}
  	return Linestring();
  }
  
  // Way -> Polygon
  Polygon OSMStore::nodeListPolygon(WayID wayId) const {
  	return nodeListPolygon(ways.at(wayId));
  }
  
  Polygon OSMStore::nodeListPolygon(const NodeVec &nodeVec) const {
  	return nodeListPolygon(makeNodeList(nodeVec));
  }
  
  // Way -> Linestring
  
  Linestring OSMStore::nodeListLinestring(WayID wayId) const {
  	return nodeListLinestring(ways.at(wayId));
  }
  
  Linestring OSMStore::nodeListLinestring(const NodeVec &nodeVec) const {
  	return nodeListLinestring(makeNodeList(nodeVec));
  }
  
  
  