Merge commit '879f7eb04200d7d2c28af565229bf6e3d54274fd' into retry/libosmium

This commit is contained in:
karenzshea
2016-10-03 13:08:59 -04:00
208 changed files with 11590 additions and 4051 deletions
+81 -10
View File
@@ -110,8 +110,12 @@ namespace gdalcpp {
namespace detail {
struct init_wrapper {
#if GDAL_VERSION_MAJOR >= 2
init_wrapper() { GDALAllRegister(); }
#else
init_wrapper() { OGRRegisterAll(); }
~init_wrapper() { OGRCleanupAll(); }
#endif
};
struct init_library {
@@ -237,6 +241,8 @@ namespace gdalcpp {
detail::Options m_options;
SRS m_srs;
std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
uint64_t m_edit_count = 0;
uint64_t m_max_edit_count = 0;
public:
@@ -255,6 +261,15 @@ namespace gdalcpp {
}
}
~Dataset() {
try {
if (m_edit_count > 0) {
commit_transaction();
}
} catch (...) {
}
}
const std::string& driver_name() const {
return m_driver_name;
}
@@ -282,10 +297,14 @@ namespace gdalcpp {
exec(sql.c_str());
}
Dataset& start_transaction() {
#if GDAL_VERSION_MAJOR >= 2
m_dataset->StartTransaction();
#else
OGRLayer* layer = m_dataset->GetLayer(0);
if (layer) {
layer->StartTransaction();
}
#endif
return *this;
}
@@ -293,7 +312,38 @@ namespace gdalcpp {
Dataset& commit_transaction() {
#if GDAL_VERSION_MAJOR >= 2
m_dataset->CommitTransaction();
#else
OGRLayer* layer = m_dataset->GetLayer(0);
if (layer) {
layer->CommitTransaction();
}
#endif
m_edit_count = 0;
return *this;
}
void prepare_edit() {
if (m_max_edit_count != 0 && m_edit_count == 0) {
start_transaction();
}
}
void finalize_edit() {
if (m_max_edit_count != 0 && ++m_edit_count > m_max_edit_count) {
commit_transaction();
}
}
Dataset& enable_auto_transactions(uint64_t edits = 100000) {
m_max_edit_count = edits;
return *this;
}
Dataset& disable_auto_transactions() {
if (m_max_edit_count != 0 && m_edit_count > 0) {
commit_transaction();
}
m_max_edit_count = 0;
return *this;
}
@@ -346,19 +396,32 @@ namespace gdalcpp {
return *this;
}
void create_feature(OGRFeature* feature) {
dataset().prepare_edit();
OGRErr result = m_layer->CreateFeature(feature);
if (result != OGRERR_NONE) {
throw gdal_error(std::string("creating feature in layer '") + name() + "' failed", result, dataset().driver_name(), dataset().dataset_name());
}
dataset().finalize_edit();
}
Layer& start_transaction() {
#if GDAL_VERSION_MAJOR < 2
OGRErr result = m_layer->StartTransaction();
if (result != OGRERR_NONE) {
throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
}
#endif
return *this;
}
Layer& commit_transaction() {
#if GDAL_VERSION_MAJOR < 2
OGRErr result = m_layer->CommitTransaction();
if (result != OGRERR_NONE) {
throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
}
#endif
return *this;
}
@@ -366,36 +429,44 @@ namespace gdalcpp {
class Feature {
struct ogr_feature_deleter {
void operator()(OGRFeature* feature) {
OGRFeature::DestroyFeature(feature);
}
}; // struct ogr_feature_deleter
Layer& m_layer;
OGRFeature m_feature;
std::unique_ptr<OGRFeature, ogr_feature_deleter> m_feature;
public:
Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
m_layer(layer),
m_feature(m_layer.get().GetLayerDefn()) {
OGRErr result = m_feature.SetGeometryDirectly(geometry.release());
m_feature(OGRFeature::CreateFeature(m_layer.get().GetLayerDefn())) {
if (!m_feature) {
throw std::bad_alloc();
}
OGRErr result = m_feature->SetGeometryDirectly(geometry.release());
if (result != OGRERR_NONE) {
throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
}
}
void add_to_layer() {
OGRErr result = m_layer.get().CreateFeature(&m_feature);
if (result != OGRERR_NONE) {
throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
}
m_layer.create_feature(m_feature.get());
}
template <class T>
Feature& set_field(int n, T&& arg) {
m_feature.SetField(n, std::forward<T>(arg));
m_feature->SetField(n, std::forward<T>(arg));
return *this;
}
template <class T>
Feature& set_field(const char* name, T&& arg) {
m_feature.SetField(name, std::forward<T>(arg));
m_feature->SetField(name, std::forward<T>(arg));
return *this;
}
File diff suppressed because it is too large Load Diff
@@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iosfwd>
#include <utility>
#include <osmium/area/detail/vector.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
@@ -53,108 +54,178 @@ namespace osmium {
*/
namespace detail {
class ProtoRing;
enum class role_type : uint8_t {
unknown = 0,
outer = 1,
inner = 2,
empty = 3
};
/**
* This helper class for the Assembler class models a segment.
* Segments are the connection between
* two nodes and they all have their smaller coordinate at the
* beginning of the segment. Smaller, in this case, means smaller x
* coordinate, and if they are the same smaller y coordinate.
* This helper class for the Assembler class models a segment,
* the connection between two nodes.
*
* Internally segments have their smaller coordinate at the
* beginning of the segment. Smaller, in this case, means smaller
* x coordinate, and, if they are the same, smaller y coordinate.
*/
class NodeRefSegment {
// First node in order described above.
osmium::NodeRef m_first;
// Second node in order described above.
osmium::NodeRef m_second;
/// Role of the member this segment was from.
const char* m_role;
/// Way this segment was from.
// Way this segment was from.
const osmium::Way* m_way;
// The ring this segment is part of. Initially nullptr, this
// will be filled in once we know which ring the segment is in.
ProtoRing* m_ring;
// The role of this segment from the member role.
role_type m_role;
// Nodes have to be reversed to get the intended order.
bool m_reverse = false;
// We found the right direction for this segment in the ring.
// (This depends on whether it is an inner or outer ring.)
bool m_direction_done = false;
public:
void swap_locations() {
using std::swap;
swap(m_first, m_second);
}
explicit NodeRefSegment() noexcept :
NodeRefSegment() noexcept :
m_first(),
m_second(),
m_role(nullptr),
m_way(nullptr) {
m_way(nullptr),
m_ring(nullptr),
m_role(role_type::unknown) {
}
explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, role_type role = role_type::unknown, const osmium::Way* way = nullptr) noexcept :
m_first(nr1),
m_second(nr2),
m_role(role),
m_way(way) {
m_way(way),
m_ring(nullptr),
m_role(role) {
if (nr2.location() < nr1.location()) {
swap_locations();
using std::swap;
swap(m_first, m_second);
}
}
NodeRefSegment(const NodeRefSegment&) = default;
NodeRefSegment(NodeRefSegment&&) = default;
/**
* The ring this segment is a part of. nullptr if we don't
* have the ring yet.
*/
ProtoRing* ring() const noexcept {
return m_ring;
}
NodeRefSegment& operator=(const NodeRefSegment&) = default;
NodeRefSegment& operator=(NodeRefSegment&&) = default;
/**
* Returns true if the segment has already been placed in a
* ring.
*/
bool is_done() const noexcept {
return m_ring != nullptr;
}
~NodeRefSegment() = default;
void set_ring(ProtoRing* ring) noexcept {
assert(ring);
m_ring = ring;
}
/// Return first NodeRef of Segment according to sorting order (bottom left to top right).
bool is_reverse() const noexcept {
return m_reverse;
}
void reverse() noexcept {
m_reverse = !m_reverse;
}
bool is_direction_done() const noexcept {
return m_direction_done;
}
void mark_direction_done() noexcept {
m_direction_done = true;
}
void mark_direction_not_done() noexcept {
m_direction_done = false;
}
/**
* Return first NodeRef of Segment according to sorting
* order (bottom left to top right).
*/
const osmium::NodeRef& first() const noexcept {
return m_first;
}
/// Return second NodeRef of Segment according to sorting order (bottom left to top right).
/**
* Return second NodeRef of Segment according to sorting
* order (bottom left to top right).
*/
const osmium::NodeRef& second() const noexcept {
return m_second;
}
bool to_left_of(const osmium::Location& location) const {
// std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
/**
* Return real first NodeRef of Segment.
*/
const osmium::NodeRef& start() const noexcept {
return m_reverse ? m_second : m_first;
}
if (first().location() == location || second().location() == location) {
return false;
}
const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
return a.y() < b.y();
});
if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
// std::cerr << " false\n";
return false;
}
int64_t ax = mm.first.x();
int64_t bx = mm.second.x();
int64_t lx = location.x();
int64_t ay = mm.first.y();
int64_t by = mm.second.y();
int64_t ly = location.y();
return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
/**
* Return real second NodeRef of Segment.
*/
const osmium::NodeRef& stop() const noexcept {
return m_reverse ? m_first : m_second;
}
bool role_outer() const noexcept {
return !strcmp(m_role, "outer");
return m_role == role_type::outer;
}
bool role_inner() const noexcept {
return !strcmp(m_role, "inner");
return m_role == role_type::inner;
}
bool role_empty() const noexcept {
return m_role == role_type::empty;
}
const char* role_name() const noexcept {
static const char* names[] = { "unknown", "outer", "inner", "empty" };
return names[int(m_role)];
}
const osmium::Way* way() const noexcept {
return m_way;
}
/**
* The "determinant" of this segment. Used for calculating
* the winding order or a ring.
*/
int64_t det() const noexcept {
const vec a{start()};
const vec b{stop()};
return a * b;
}
}; // class NodeRefSegment
/// NodeRefSegments are equal if both their locations are equal
inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
return lhs.first().location() == rhs.first().location() &&
lhs.second().location() == rhs.second().location();
}
inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
@@ -162,12 +233,33 @@ namespace osmium {
}
/**
* NodeRefSegments are "smaller" if they are to the left and down of another
* segment. The first() location is checked first() and only if they have the
* same first() location the second() location is taken into account.
* A NodeRefSegment is "smaller" if the first point is to the
* left and down of the first point of the second segment.
* If both first points are the same, the segment with the higher
* slope comes first. If the slope is the same, the shorter
* segment comes first.
*/
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
if (lhs.first().location() == rhs.first().location()) {
const vec p0{lhs.first().location()};
const vec p1{lhs.second().location()};
const vec q0{rhs.first().location()};
const vec q1{rhs.second().location()};
const vec p = p1 - p0;
const vec q = q1 - q0;
if (p.x == 0 && q.x == 0) {
return p.y < q.y;
}
const auto a = p.y * q.x;
const auto b = q.y * p.x;
if (a == b) {
return p.x < q.x;
}
return a > b;
}
return lhs.first().location() < rhs.first().location();
}
inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
@@ -184,7 +276,10 @@ namespace osmium {
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
return out << segment.first() << "--" << segment.second();
return out << segment.start() << "--" << segment.stop()
<< "[" << (segment.is_reverse() ? 'R' : '_')
<< (segment.is_done() ? 'd' : '_')
<< (segment.is_direction_done() ? 'D' : '_') << "]";
}
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
@@ -194,7 +289,7 @@ namespace osmium {
return false;
}
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
if (m1.first > m2.second || m2.first > m1.second) {
@@ -210,55 +305,94 @@ namespace osmium {
* might be slightly different than the numerically correct
* location.
*
* This function uses integer arithmentic as much as possible and
* This function uses integer arithmetic as much as possible and
* will not work if the segments are longer than about half the
* planet. This shouldn't happen with real data, so it isn't a big
* problem.
*
* If the segments touch in one of their endpoints, it doesn't
* count as an intersection.
* If the segments touch in one or both of their endpoints, it
* doesn't count as an intersection.
*
* If the segments intersect not in a single point but in multiple
* points, ie if they overlap, this is NOT detected.
* points, ie if they are collinear and overlap, the smallest
* of the endpoints that is in the overlapping section is returned.
*
* @returns Undefined osmium::Location if there is no intersection
* or a defined Location if the segments intersect.
*/
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
if (s1.first().location() == s2.first().location() ||
s1.first().location() == s2.second().location() ||
s1.second().location() == s2.first().location() ||
s1.second().location() == s2.second().location()) {
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
// See http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
// for some hints about how the algorithm works.
const vec p0{s1.first()};
const vec p1{s1.second()};
const vec q0{s2.first()};
const vec q1{s2.second()};
if ((p0 == q0 && p1 == q1) ||
(p0 == q1 && p1 == q0)) {
// segments are the same
return osmium::Location();
}
int64_t s1ax = s1.first().x();
int64_t s1ay = s1.first().y();
int64_t s1bx = s1.second().x();
int64_t s1by = s1.second().y();
int64_t s2ax = s2.first().x();
int64_t s2ay = s2.first().y();
int64_t s2bx = s2.second().x();
int64_t s2by = s2.second().y();
int64_t d = (s2by - s2ay) * (s1bx - s1ax) -
(s2bx - s2ax) * (s1by - s1ay);
const vec pd = p1 - p0;
const int64_t d = pd * (q1 - q0);
if (d != 0) {
int64_t na = (s2bx - s2ax) * (s1ay - s2ay) -
(s2by - s2ay) * (s1ax - s2ax);
// segments are not collinear
int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) -
(s1by - s1ay) * (s1ax - s2ax);
if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) {
// touching at an end point
return osmium::Location();
}
// intersection in a point
const int64_t na = (q1.x - q0.x) * (p0.y - q0.y) -
(q1.y - q0.y) * (p0.x - q0.x);
const int64_t nb = (p1.x - p0.x) * (p0.y - q0.y) -
(p1.y - p0.y) * (p0.x - q0.x);
if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) ||
(d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
const double ua = double(na) / d;
const vec i = p0 + ua * (p1 - p0);
return osmium::Location(int32_t(i.x), int32_t(i.y));
}
double ua = double(na) / d;
int32_t ix = int32_t(s1ax + ua*(s1bx - s1ax));
int32_t iy = int32_t(s1ay + ua*(s1by - s1ay));
return osmium::Location();
}
return osmium::Location(ix, iy);
// segments are collinear
if (pd * (q0 - p0) == 0) {
// segments are on the same line
struct seg_loc {
int segment;
osmium::Location location;
};
seg_loc sl[4];
sl[0] = {0, s1.first().location() };
sl[1] = {0, s1.second().location()};
sl[2] = {1, s2.first().location() };
sl[3] = {1, s2.second().location()};
std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) {
return a.location < b.location;
});
if (sl[1].location == sl[2].location) {
return osmium::Location();
}
if (sl[0].segment != sl[1].segment) {
if (sl[0].location == sl[1].location) {
return sl[2].location;
} else {
return sl[1].location;
}
}
}
@@ -34,10 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <set>
#include <vector>
@@ -47,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
class Way;
namespace area {
namespace detail {
@@ -58,214 +59,155 @@ namespace osmium {
public:
typedef std::vector<NodeRefSegment> segments_type;
using segments_type = std::vector<NodeRefSegment*>;
private:
// segments in this ring
// Segments in this ring.
segments_type m_segments;
bool m_outer {true};
// if this is an outer ring, these point to it's inner rings (if any)
// If this is an outer ring, these point to it's inner rings
// (if any).
std::vector<ProtoRing*> m_inner;
// The smallest segment. Will be kept current whenever a new
// segment is added to the ring.
NodeRefSegment* m_min_segment;
// If this is an inner ring, points to the outer ring.
ProtoRing* m_outer_ring;
int64_t m_sum;
public:
explicit ProtoRing(const NodeRefSegment& segment) noexcept :
m_segments() {
explicit ProtoRing(NodeRefSegment* segment) noexcept :
m_segments(),
m_inner(),
m_min_segment(segment),
m_outer_ring(nullptr),
m_sum(0) {
add_segment_back(segment);
}
explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
std::copy(sbegin, send, m_segments.begin());
void add_segment_back(NodeRefSegment* segment) {
assert(segment);
if (*segment < *m_min_segment) {
m_min_segment = segment;
}
m_segments.push_back(segment);
segment->set_ring(this);
m_sum += segment->det();
}
bool outer() const noexcept {
return m_outer;
NodeRefSegment* min_segment() const noexcept {
return m_min_segment;
}
void set_inner() noexcept {
m_outer = false;
ProtoRing* outer_ring() const noexcept {
return m_outer_ring;
}
segments_type& segments() noexcept {
return m_segments;
void set_outer_ring(ProtoRing* outer_ring) noexcept {
assert(outer_ring);
assert(m_inner.empty());
m_outer_ring = outer_ring;
}
const std::vector<ProtoRing*>& inner_rings() const noexcept {
return m_inner;
}
void add_inner_ring(ProtoRing* ring) {
assert(ring);
assert(!m_outer_ring);
m_inner.push_back(ring);
}
bool is_outer() const noexcept {
return !m_outer_ring;
}
const segments_type& segments() const noexcept {
return m_segments;
}
void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
m_segments.erase(sbegin, send);
const NodeRef& get_node_ref_start() const noexcept {
return m_segments.front()->start();
}
void add_segment_front(const NodeRefSegment& segment) {
m_segments.insert(m_segments.begin(), segment);
const NodeRef& get_node_ref_stop() const noexcept {
return m_segments.back()->stop();
}
void add_segment_back(const NodeRefSegment& segment) {
m_segments.push_back(segment);
bool closed() const noexcept {
return get_node_ref_start().location() == get_node_ref_stop().location();
}
const NodeRefSegment& get_segment_front() const {
return m_segments.front();
void reverse() {
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
segment->reverse();
});
std::reverse(m_segments.begin(), m_segments.end());
m_sum = -m_sum;
}
NodeRefSegment& get_segment_front() {
return m_segments.front();
void mark_direction_done() {
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
segment->mark_direction_done();
});
}
const NodeRef& get_node_ref_front() const {
return get_segment_front().first();
bool is_cw() const noexcept {
return m_sum <= 0;
}
const NodeRefSegment& get_segment_back() const {
return m_segments.back();
int64_t sum() const noexcept {
return m_sum;
}
NodeRefSegment& get_segment_back() {
return m_segments.back();
}
const NodeRef& get_node_ref_back() const {
return get_segment_back().second();
}
bool closed() const {
return m_segments.front().first().location() == m_segments.back().second().location();
}
int64_t sum() const {
int64_t sum = 0;
for (const auto& segment : m_segments) {
sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
void fix_direction() noexcept {
if (is_cw() == is_outer()) {
reverse();
}
return sum;
}
bool is_cw() const {
return sum() <= 0;
void reset() {
m_inner.clear();
m_outer_ring = nullptr;
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
segment->mark_direction_not_done();
});
}
int64_t area() const {
return std::abs(sum()) / 2;
void get_ways(std::set<const osmium::Way*>& ways) const {
for (const auto& segment : m_segments) {
ways.insert(segment->way());
}
}
void swap_segments(ProtoRing& other) {
using std::swap;
swap(m_segments, other.m_segments);
void join_forward(ProtoRing& other) {
for (NodeRefSegment* segment : other.m_segments) {
add_segment_back(segment);
}
}
void add_inner_ring(ProtoRing* ring) {
m_inner.push_back(ring);
}
const std::vector<ProtoRing*>& inner_rings() const {
return m_inner;
void join_backward(ProtoRing& other) {
for (auto it = other.m_segments.rbegin(); it != other.m_segments.rend(); ++it) {
(*it)->reverse();
add_segment_back(*it);
}
}
void print(std::ostream& out) const {
out << "[";
bool first = true;
if (!m_segments.empty()) {
out << m_segments.front()->start().ref();
}
for (const auto& segment : m_segments) {
if (first) {
out << segment.first().ref();
}
out << ',' << segment.second().ref();
first = false;
out << ',' << segment->stop().ref();
}
out << "]";
}
void reverse() {
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
segment.swap_locations();
});
std::reverse(m_segments.begin(), m_segments.end());
}
/**
* Merge other ring to end of this ring.
*/
void merge_ring(const ProtoRing& other, bool debug) {
if (debug) {
std::cerr << " MERGE rings ";
print(std::cerr);
std::cerr << " to ";
other.print(std::cerr);
std::cerr << "\n";
}
m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
if (debug) {
std::cerr << " result ring: ";
print(std::cerr);
std::cerr << "\n";
}
}
void merge_ring_reverse(const ProtoRing& other, bool debug) {
if (debug) {
std::cerr << " MERGE rings (reverse) ";
print(std::cerr);
std::cerr << " to ";
other.print(std::cerr);
std::cerr << "\n";
}
size_t n = m_segments.size();
m_segments.resize(n + other.m_segments.size());
std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
segment.swap_locations();
return segment;
});
if (debug) {
std::cerr << " result ring: ";
print(std::cerr);
std::cerr << "\n";
}
}
const NodeRef& min_node() const {
auto it = std::min_element(m_segments.begin(), m_segments.end());
if (location_less()(it->first(), it->second())) {
return it->first();
} else {
return it->second();
}
}
bool is_in(ProtoRing* outer) {
osmium::Location testpoint = segments().front().first().location();
bool is_in = false;
for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
(testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
is_in = !is_in;
}
}
return is_in;
}
void get_ways(std::set<const osmium::Way*>& ways) {
for (const auto& segment : m_segments) {
ways.insert(segment.way());
}
}
bool contains(const NodeRefSegment& segment) const {
for (const auto& s : m_segments) {
if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
return true;
}
}
return false;
out << "]-" << (is_outer() ? "OUTER" : "INNER");
}
}; // class ProtoRing
@@ -35,12 +35,16 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/area/detail/node_ref_segment.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
@@ -52,6 +56,24 @@ namespace osmium {
namespace detail {
/**
* Iterate over all relation members and the vector of ways at the
* same time and call given function with the relation member and
* way as parameter. This takes into account that there might be
* non-way members in the relation.
*/
template <typename F>
inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, F&& func) {
auto way_it = ways.cbegin();
for (const osmium::RelationMember& member : relation.members()) {
if (member.type() == osmium::item_type::way) {
assert(way_it != ways.cend());
func(member, **way_it);
++way_it;
}
}
}
/**
* This is a helper class for the area assembler. It models
* a list of segments.
@@ -64,6 +86,51 @@ namespace osmium {
bool m_debug;
static role_type parse_role(const char* role) noexcept {
if (role[0] == '\0') {
return role_type::empty;
} else if (!std::strcmp(role, "outer")) {
return role_type::outer;
} else if (!std::strcmp(role, "inner")) {
return role_type::inner;
}
return role_type::unknown;
}
/**
* Calculate the number of segments in all the ways together.
*/
static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
return std::accumulate(members.cbegin(), members.cend(), 0, [](size_t sum, const osmium::Way* way) {
if (way->nodes().empty()) {
return sum;
} else {
return sum + way->nodes().size() - 1;
}
});
}
uint32_t extract_segments_from_way_impl(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way, role_type role) {
uint32_t duplicate_nodes = 0;
osmium::NodeRef previous_nr;
for (const osmium::NodeRef& nr : way.nodes()) {
if (previous_nr.location()) {
if (previous_nr.location() != nr.location()) {
m_segments.emplace_back(previous_nr, nr, role, &way);
} else {
++duplicate_nodes;
if (problem_reporter) {
problem_reporter->report_duplicate_node(previous_nr.ref(), nr.ref(), nr.location());
}
}
}
previous_nr = nr;
}
return duplicate_nodes;
}
public:
explicit SegmentList(bool debug) noexcept :
@@ -84,12 +151,31 @@ namespace osmium {
return m_segments.size();
}
/// Is the segment list empty?
bool empty() const noexcept {
return m_segments.empty();
}
typedef slist_type::const_iterator const_iterator;
typedef slist_type::iterator iterator;
using const_iterator = slist_type::const_iterator;
using iterator = slist_type::iterator;
NodeRefSegment& front() {
return m_segments.front();
}
NodeRefSegment& back() {
return m_segments.back();
}
const NodeRefSegment& operator[](size_t n) const noexcept {
assert(n < m_segments.size());
return m_segments[n];
}
NodeRefSegment& operator[](size_t n) noexcept {
assert(n < m_segments.size());
return m_segments[n];
}
iterator begin() noexcept {
return m_segments.begin();
@@ -115,11 +201,6 @@ namespace osmium {
m_debug = debug;
}
/// Clear the list of segments. All segments are removed.
void clear() {
m_segments.clear();
}
/// Sort the list of segments.
void sort() {
std::sort(m_segments.begin(), m_segments.end());
@@ -128,32 +209,37 @@ namespace osmium {
/**
* Extract segments from given way and add them to the list.
*
* Segments connecting two nodes with the same location (ie same
* node or different node with same location) are removed.
*
* XXX should two nodes with same location be reported?
* Segments connecting two nodes with the same location (ie
* same node or different nodes with same location) are
* removed after reporting the duplicate node.
*/
void extract_segments_from_way(const osmium::Way& way, const char* role) {
osmium::NodeRef last_nr;
for (const osmium::NodeRef& nr : way.nodes()) {
if (last_nr.location() && last_nr.location() != nr.location()) {
m_segments.emplace_back(last_nr, nr, role, &way);
}
last_nr = nr;
uint32_t extract_segments_from_way(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way) {
if (way.nodes().empty()) {
return 0;
}
m_segments.reserve(way.nodes().size() - 1);
return extract_segments_from_way_impl(problem_reporter, way, role_type::outer);
}
/**
* Extract all segments from all ways that make up this
* multipolygon relation and add them to the list.
*/
void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
auto member_it = relation.members().begin();
for (size_t offset : members) {
const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
extract_segments_from_way(way, member_it->role());
++member_it;
uint32_t extract_segments_from_ways(osmium::area::ProblemReporter* problem_reporter, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
assert(relation.members().size() >= members.size());
const size_t num_segments = get_num_segments(members);
if (problem_reporter) {
problem_reporter->set_nodes(num_segments);
}
m_segments.reserve(num_segments);
uint32_t duplicate_nodes = 0;
for_each_member(relation, members, [this, &problem_reporter, &duplicate_nodes](const osmium::RelationMember& member, const osmium::Way& way) {
duplicate_nodes += extract_segments_from_way_impl(problem_reporter, way, parse_role(member.role()));
});
return duplicate_nodes;
}
/**
@@ -162,17 +248,35 @@ namespace osmium {
* same segment. So if there are three, for instance, two will
* be removed and one will be left.
*/
void erase_duplicate_segments() {
uint32_t erase_duplicate_segments(osmium::area::ProblemReporter* problem_reporter) {
uint32_t duplicate_segments = 0;
while (true) {
auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
if (it == m_segments.end()) {
return;
break;
}
if (m_debug) {
std::cerr << " erase duplicate segment: " << *it << "\n";
}
// Only count and report duplicate segments if they
// belong to the same way or if they don't both have
// the role "inner". Those cases are definitely wrong.
// If the duplicate segments belong to different
// "inner" ways, they could be touching inner rings
// which are perfectly okay. Note that for this check
// the role has to be correct in the member data.
if (it->way() == std::next(it)->way() || !it->role_inner() || !std::next(it)->role_inner()) {
++duplicate_segments;
if (problem_reporter) {
problem_reporter->report_duplicate_segment(it->first(), it->second());
}
}
m_segments.erase(it, it+2);
}
return duplicate_segments;
}
/**
@@ -182,14 +286,14 @@ namespace osmium {
* reported to this object.
* @returns true if there are intersections.
*/
bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
uint32_t find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
if (m_segments.empty()) {
return false;
return 0;
}
bool found_intersections = false;
uint32_t found_intersections = 0;
for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend()-1; ++it1) {
const NodeRefSegment& s1 = *it1;
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
const NodeRefSegment& s2 = *it2;
@@ -203,12 +307,13 @@ namespace osmium {
if (y_range_overlap(s1, s2)) {
osmium::Location intersection = calculate_intersection(s1, s2);
if (intersection) {
found_intersections = true;
++found_intersections;
if (m_debug) {
std::cerr << " segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
}
if (problem_reporter) {
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(),
s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
}
}
}
@@ -0,0 +1,121 @@
#ifndef OSMIUM_AREA_DETAIL_VECTOR_HPP
#define OSMIUM_AREA_DETAIL_VECTOR_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <iosfwd>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
namespace osmium {
namespace area {
namespace detail {
/**
* This helper class models a 2D vector in the mathematical sense.
* It uses 64 bit integers internally which has enough precision
* for most operations with inputs based on 32 bit locations.
*/
struct vec {
int64_t x;
int64_t y;
constexpr vec(int64_t a, int64_t b) noexcept :
x(a),
y(b) {
}
constexpr explicit vec(const osmium::Location& l) noexcept :
x(l.x()),
y(l.y()) {
}
constexpr explicit vec(const osmium::NodeRef& nr) noexcept :
x(nr.x()),
y(nr.y()) {
}
}; // struct vec
// addition
constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
return vec{a.x + b.x, a.y + b.y};
}
// subtraction
constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
return vec{a.x - b.x, a.y - b.y};
}
// cross product
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
return a.x * b.y - a.y * b.x;
}
// scale vector
constexpr inline vec operator*(double s, const vec& v) noexcept {
return vec{int64_t(s * v.x), int64_t(s * v.y)};
}
// scale vector
constexpr inline vec operator*(const vec& v, double s) noexcept {
return vec{int64_t(s * v.x), int64_t(s * v.y)};
}
// equality
constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
return a.x == b.x && a.y == b.y;
}
// inequality
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
return !(a == b);
}
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const vec& v) {
return out << '(' << v.x << ',' << v.y << ')';
}
} // namespace detail
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_DETAIL_VECTOR_HPP
@@ -34,11 +34,11 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
#include <osmium/area/stats.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
@@ -47,7 +47,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/relations/collector.hpp>
#include <osmium/relations/detail/member_meta.hpp>
namespace osmium {
@@ -74,13 +73,15 @@ namespace osmium {
template <typename TAssembler>
class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
using collector_type = osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false>;
typedef typename TAssembler::config_type assembler_config_type;
using assembler_config_type = typename TAssembler::config_type;
const assembler_config_type m_assembler_config;
osmium::memory::Buffer m_output_buffer;
osmium::area::area_stats m_stats;
static constexpr size_t initial_output_buffer_size = 1024 * 1024;
static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
@@ -107,6 +108,10 @@ namespace osmium {
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
}
const osmium::area::area_stats& stats() const noexcept {
return m_stats;
}
/**
* We are interested in all relations tagged with type=multipolygon
* or type=boundary.
@@ -121,7 +126,7 @@ namespace osmium {
return false;
}
if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
return true;
}
@@ -155,26 +160,32 @@ namespace osmium {
// way is closed and has enough nodes, build simple multipolygon
TAssembler assembler(m_assembler_config);
assembler(way, m_output_buffer);
m_stats += assembler.stats();
possibly_flush_output_buffer();
}
} catch (osmium::invalid_location&) {
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
void complete_relation(osmium::relations::RelationMeta& relation_meta) {
const osmium::Relation& relation = this->get_relation(relation_meta);
std::vector<size_t> offsets;
const osmium::memory::Buffer& buffer = this->members_buffer();
std::vector<const osmium::Way*> ways;
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
offsets.push_back(this->get_offset(member.type(), member.ref()));
const size_t offset = this->get_offset(member.type(), member.ref());
ways.push_back(&buffer.get<const osmium::Way>(offset));
}
}
try {
TAssembler assembler(m_assembler_config);
assembler(relation, offsets, this->members_buffer(), m_output_buffer);
assembler(relation, ways, m_output_buffer);
m_stats += assembler.stats();
possibly_flush_output_buffer();
} catch (osmium::invalid_location&) {
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
@@ -33,12 +33,17 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
class NodeRef;
class Way;
namespace area {
/**
@@ -62,6 +67,9 @@ namespace osmium {
// ID of the relation/way we are currently working on
osmium::object_id_type m_object_id;
// Number of nodes in the area
size_t m_nodes;
public:
ProblemReporter() = default;
@@ -79,6 +87,10 @@ namespace osmium {
m_object_id = object_id;
}
void set_nodes(size_t nodes) noexcept {
m_nodes = nodes;
}
// Disable "unused-parameter" warning, so that the compiler will not complain.
// We can't remove the parameter names, because then doxygen will complain.
#pragma GCC diagnostic push
@@ -87,13 +99,23 @@ namespace osmium {
/**
* Report a duplicate node, ie. two nodes with the same location.
*
* @param node_id1 ID of the first node.
* @param node_id2 ID of the second node.
* @param location Location of both nodes.
* @param node_id1 ID of the first node.
* @param node_id2 ID of the second node.
* @param location Location of both nodes.
*/
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
}
/**
* Report a node/location where rings touch. This is often wrong,
* but not necessarily so.
*
* @param node_id ID of the node.
* @param location Location of the node.
*/
virtual void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) {
}
/**
* Report an intersection between two segments.
*
@@ -109,21 +131,33 @@ namespace osmium {
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
}
/**
* Report a duplicate segments. Two or more segments are directly
* on top of each other. This can be a problem, if there is a
* spike for instance, or it could be okay, if there are touching
* inner rings.
*
* @param nr1 NodeRef of one end of the segment.
* @param nr2 NodeRef of the other end of the segment.
*/
virtual void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
}
/**
* Report an open ring.
*
* @param end1 Location of the first open end.
* @param end2 Location of the second open end.
* @param nr NodeRef of one end of the ring.
* @param way Optional pointer to way the end node is in.
*/
virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
virtual void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) {
}
/**
* Report a segment that should have role "outer", but has a different role.
*
* @param way_id ID of the way this segment is in.
* @param seg_start Start of the segment with the wrong role.
* @param seg_end End of the segment with the wrong role.
* @param way_id ID of the way this segment is in.
* @param seg_start Start of the segment with the wrong role.
* @param seg_end End of the segment with the wrong role.
*/
virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
}
@@ -138,6 +172,32 @@ namespace osmium {
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
}
/**
* Report a way that is in multiple rings.
*
* @param way The way.
*/
virtual void report_way_in_multiple_rings(const osmium::Way& way) {
}
/**
* Report a way with role inner that has the same tags as the
* relation or outer ways.
*
* @param way The way.
*/
virtual void report_inner_with_same_tags(const osmium::Way& way) {
}
/**
* In addition to reporting specific problems, this is used to
* report all ways belonging to areas having problems.
*
* @param way The way
*/
virtual void report_way(const osmium::Way& way) {
}
#pragma GCC diagnostic pop
}; // class ProblemReporter
@@ -42,6 +42,9 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
class NodeRef;
class Way;
namespace area {
class ProblemReporterException : public ProblemReporterStream {
@@ -62,6 +65,12 @@ namespace osmium {
throw std::runtime_error(m_sstream.str());
}
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
m_sstream.str();
ProblemReporterStream::report_touching_ring(node_id, location);
throw std::runtime_error(m_sstream.str());
}
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
m_sstream.str();
@@ -69,9 +78,15 @@ namespace osmium {
throw std::runtime_error(m_sstream.str());
}
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
m_sstream.str();
ProblemReporterStream::report_ring_not_closed(end1, end2);
ProblemReporterStream::report_duplicate_segment(nr1, nr2);
throw std::runtime_error(m_sstream.str());
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
m_sstream.str();
ProblemReporterStream::report_ring_not_closed(nr, way);
throw std::runtime_error(m_sstream.str());
}
@@ -87,6 +102,18 @@ namespace osmium {
throw std::runtime_error(m_sstream.str());
}
void report_way_in_multiple_rings(const osmium::Way& way) override {
m_sstream.str();
ProblemReporterStream::report_way_in_multiple_rings(way);
throw std::runtime_error(m_sstream.str());
}
void report_inner_with_same_tags(const osmium::Way& way) override {
m_sstream.str();
ProblemReporterStream::report_inner_with_same_tags(way);
throw std::runtime_error(m_sstream.str());
}
}; // class ProblemReporterException
} // namespace area
@@ -49,8 +49,12 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/area/problem_reporter.hpp>
#include <osmium/geom/factory.hpp>
#include <osmium/geom/ogr.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
@@ -66,26 +70,34 @@ namespace osmium {
gdalcpp::Layer m_layer_perror;
gdalcpp::Layer m_layer_lerror;
gdalcpp::Layer m_layer_ways;
void set_object(gdalcpp::Feature& feature) {
const char t[2] = { osmium::item_type_to_char(m_object_type), '\0' };
feature.set_field("obj_type", t);
feature.set_field("obj_id", int32_t(m_object_id));
feature.set_field("nodes", int32_t(m_nodes));
}
void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location));
feature.set_field("id1", static_cast<double>(id1));
feature.set_field("id2", static_cast<double>(id2));
feature.set_field("problem_type", problem_type);
set_object(feature);
feature.set_field("id1", double(id1));
feature.set_field("id2", double(id2));
feature.set_field("problem", problem_type);
feature.add_to_layer();
}
void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
ogr_linestring->addPoint(ogr_point1.get());
ogr_linestring->addPoint(ogr_point2.get());
auto ogr_linestring = std::unique_ptr<OGRLineString>{new OGRLineString{}};
ogr_linestring->addPoint(loc1.lon(), loc1.lat());
ogr_linestring->addPoint(loc2.lon(), loc2.lat());
gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring));
set_object(feature);
feature.set_field("id1", static_cast<double>(id1));
feature.set_field("id2", static_cast<double>(id2));
feature.set_field("problem_type", problem_type);
feature.set_field("problem", problem_type);
feature.add_to_layer();
}
@@ -93,15 +105,36 @@ namespace osmium {
explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) :
m_layer_perror(dataset, "perrors", wkbPoint),
m_layer_lerror(dataset, "lerrors", wkbLineString) {
m_layer_lerror(dataset, "lerrors", wkbLineString),
m_layer_ways(dataset, "ways", wkbLineString) {
m_layer_perror.add_field("id1", OFTReal, 10);
m_layer_perror.add_field("id2", OFTReal, 10);
m_layer_perror.add_field("problem_type", OFTString, 30);
// 64bit integers are not supported in GDAL < 2, so we
// are using a workaround here in fields where we expect
// node IDs, we use real numbers.
m_layer_perror
.add_field("obj_type", OFTString, 1)
.add_field("obj_id", OFTInteger, 10)
.add_field("nodes", OFTInteger, 8)
.add_field("id1", OFTReal, 12, 1)
.add_field("id2", OFTReal, 12, 1)
.add_field("problem", OFTString, 30)
;
m_layer_lerror.add_field("id1", OFTReal, 10);
m_layer_lerror.add_field("id2", OFTReal, 10);
m_layer_lerror.add_field("problem_type", OFTString, 30);
m_layer_lerror
.add_field("obj_type", OFTString, 1)
.add_field("obj_id", OFTInteger, 10)
.add_field("nodes", OFTInteger, 8)
.add_field("id1", OFTReal, 12, 1)
.add_field("id2", OFTReal, 12, 1)
.add_field("problem", OFTString, 30)
;
m_layer_ways
.add_field("obj_type", OFTString, 1)
.add_field("obj_id", OFTInteger, 10)
.add_field("way_id", OFTInteger, 10)
.add_field("nodes", OFTInteger, 8)
;
}
~ProblemReporterOGR() override = default;
@@ -110,24 +143,82 @@ namespace osmium {
write_point("duplicate_node", node_id1, node_id2, location);
}
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
write_point("intersection", m_object_id, 0, intersection);
write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
write_point("touching_ring", node_id, 0, location);
}
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
write_point("ring_not_closed", m_object_id, 0, end1);
write_point("ring_not_closed", m_object_id, 0, end2);
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
write_point("intersection", way1_id, way2_id, intersection);
write_line("intersection", way1_id, way2_id, way1_seg_start, way1_seg_end);
write_line("intersection", way2_id, way1_id, way2_seg_start, way2_seg_end);
}
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
}
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
write_line("role_should_be_outer", way_id, 0, seg_start, seg_end);
}
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
write_line("role_should_be_inner", way_id, 0, seg_start, seg_end);
}
void report_way_in_multiple_rings(const osmium::Way& way) override {
if (way.nodes().size() < 2) {
return;
}
try {
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
set_object(feature);
feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0);
feature.set_field("problem", "way_in_multiple_rings");
feature.add_to_layer();
} catch (const osmium::geometry_error&) {
// XXX
}
}
void report_inner_with_same_tags(const osmium::Way& way) override {
if (way.nodes().size() < 2) {
return;
}
try {
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
set_object(feature);
feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0);
feature.set_field("problem", "inner_with_same_tags");
feature.add_to_layer();
} catch (const osmium::geometry_error&) {
// XXX
}
}
void report_way(const osmium::Way& way) override {
if (way.nodes().empty()) {
return;
}
if (way.nodes().size() == 1) {
const auto& first_nr = way.nodes()[0];
write_point("single_node_in_way", way.id(), first_nr.ref(), first_nr.location());
return;
}
try {
gdalcpp::Feature feature(m_layer_ways, m_ogr_factory.create_linestring(way));
set_object(feature);
feature.set_field("way_id", int32_t(way.id()));
feature.add_to_layer();
} catch (const osmium::geometry_error&) {
// XXX
}
}
}; // class ProblemReporterOGR
@@ -38,7 +38,9 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/area/problem_reporter.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
@@ -57,7 +59,7 @@ namespace osmium {
~ProblemReporterStream() override = default;
void header(const char* msg) {
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << " (with " << m_nodes << " nodes): ";
}
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
@@ -65,6 +67,11 @@ namespace osmium {
*m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
}
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
header("touching ring");
*m_out << "node_id=" << node_id << " location=" << location << "\n";
}
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
header("intersection");
@@ -72,9 +79,19 @@ namespace osmium {
<< " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
}
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
header("duplicate segment");
*m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
header("ring not closed");
*m_out << "end1=" << end1 << " end2=" << end2 << "\n";
*m_out << "node_id=" << nr.ref() << " location=" << nr.location();
if (way) {
*m_out << " on way " << way->id();
}
*m_out << "\n";
}
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
@@ -87,6 +104,16 @@ namespace osmium {
*m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
}
void report_way_in_multiple_rings(const osmium::Way& way) override {
header("way in multiple rings");
*m_out << "way_id=" << way.id() << '\n';
}
void report_inner_with_same_tags(const osmium::Way& way) override {
header("inner way with same tags as relation or outer");
*m_out << "way_id=" << way.id() << '\n';
}
}; // class ProblemReporterStream
} // namespace area
+128
View File
@@ -0,0 +1,128 @@
#ifndef OSMIUM_AREA_STATS_HPP
#define OSMIUM_AREA_STATS_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <ostream>
namespace osmium {
namespace area {
/**
* These statistics are generated by the area assembler code. They
* tell the user of the assembler a lot about the objects this area
* is made out of, what happened during the assembly, and what errors
* there were.
*/
struct area_stats {
uint64_t area_really_complex_case = 0; ///< Most difficult case with rings touching in multiple points
uint64_t area_simple_case = 0; ///< Simple case, no touching rings
uint64_t area_touching_rings_case = 0; ///< More difficult case with touching rings
uint64_t duplicate_nodes = 0; ///< Consecutive identical nodes or consecutive nodes with same location
uint64_t duplicate_segments = 0; ///< Segments duplicated (going back and forth)
uint64_t from_relations = 0; ///< Area created from multipolygon relation
uint64_t from_ways = 0; ///< Area created from way
uint64_t inner_rings = 0; ///< Number of inner rings
uint64_t inner_with_same_tags = 0; ///< Number of inner ways with same tags as area
uint64_t intersections = 0; ///< Number of intersections between segments
uint64_t member_ways = 0; ///< Number of ways in the area
uint64_t no_tags_on_relation = 0; ///< No tags on relation (old-style multipolygon with tags on outer ways)
uint64_t no_way_in_mp_relation = 0; ///< Multipolygon relation with no way members
uint64_t nodes = 0; ///< Number of nodes in the area
uint64_t open_rings = 0; ///< Number of open rings in the area
uint64_t outer_rings = 0; ///< Number of outer rings in the area
uint64_t short_ways = 0; ///< Number of ways with less than two nodes
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
uint64_t touching_rings = 0; ///< Rings touching in a node
uint64_t ways_in_multiple_rings = 0; ///< Different segments of a way ended up in different rings
uint64_t wrong_role = 0; ///< Member has wrong role (not "outer", "inner", or empty)
area_stats& operator+=(const area_stats& other) noexcept {
area_really_complex_case += other.area_really_complex_case;
area_simple_case += other.area_simple_case;
area_touching_rings_case += other.area_touching_rings_case;
duplicate_nodes += other.duplicate_nodes;
duplicate_segments += other.duplicate_segments;
from_relations += other.from_relations;
from_ways += other.from_ways;
inner_rings += other.inner_rings;
inner_with_same_tags += other.inner_with_same_tags;
intersections += other.intersections;
member_ways += other.member_ways;
no_tags_on_relation += other.no_tags_on_relation;
no_way_in_mp_relation += other.no_way_in_mp_relation;
nodes += other.nodes;
open_rings += other.open_rings;
outer_rings += other.outer_rings;
short_ways += other.short_ways;
single_way_in_mp_relation += other.single_way_in_mp_relation;
touching_rings += other.touching_rings;
ways_in_multiple_rings += other.ways_in_multiple_rings;
wrong_role += other.wrong_role;
return *this;
}
}; // struct area_stats
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const area_stats& s) {
return out << " area_really_complex_case=" << s.area_really_complex_case
<< " area_simple_case=" << s.area_simple_case
<< " area_touching_rings_case=" << s.area_touching_rings_case
<< " duplicate_nodes=" << s.duplicate_nodes
<< " duplicate_segments=" << s.duplicate_segments
<< " from_relations=" << s.from_relations
<< " from_ways=" << s.from_ways
<< " inner_rings=" << s.inner_rings
<< " inner_with_same_tags=" << s.inner_with_same_tags
<< " intersections=" << s.intersections
<< " member_ways=" << s.member_ways
<< " no_tags_on_relation=" << s.no_tags_on_relation
<< " no_way_in_mp_relation=" << s.no_way_in_mp_relation
<< " nodes=" << s.nodes
<< " open_rings=" << s.open_rings
<< " outer_rings=" << s.outer_rings
<< " short_ways=" << s.short_ways
<< " single_way_in_mp_relation=" << s.single_way_in_mp_relation
<< " touching_rings=" << s.touching_rings
<< " ways_in_multiple_rings=" << s.ways_in_multiple_rings
<< " wrong_role=" << s.wrong_role;
}
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_STATS_HPP
+36 -1
View File
@@ -46,8 +46,15 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/builder/builder.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm.hpp>
namespace osmium {
@@ -261,6 +268,34 @@ namespace osmium {
}; // class member_type
class member_type_string {
osmium::item_type m_type;
osmium::object_id_type m_ref;
std::string m_role;
public:
member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
m_type(type),
m_ref(ref),
m_role(std::move(role)) {
}
osmium::item_type type() const noexcept {
return m_type;
}
osmium::object_id_type ref() const noexcept {
return m_ref;
}
const char* role() const noexcept {
return m_role.c_str();
}
}; // class member_type_string
class comment_type {
osmium::Timestamp m_date;
+1 -2
View File
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <new>
@@ -101,7 +100,7 @@ namespace osmium {
*
*/
void add_padding(bool self = false) {
auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) {
std::fill_n(m_buffer.reserve_space(padding), padding, 0);
if (self) {
@@ -56,7 +56,7 @@ namespace osmium {
* Use osmium::builder::add_way_node_list() instead.
*/
OSMIUM_DEPRECATED inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
size_t pos = buffer.committed();
const size_t pos = buffer.committed();
{
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
for (const auto& node_ref : nodes) {
@@ -72,7 +72,7 @@ namespace osmium {
* Use osmium::builder::add_tag_list() instead.
*/
inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
size_t pos = buffer.committed();
const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
for (const auto& p : tags) {
@@ -88,7 +88,7 @@ namespace osmium {
* Use osmium::builder::add_tag_list() instead.
*/
inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
size_t pos = buffer.committed();
const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
for (const auto& p : tags) {
@@ -104,7 +104,7 @@ namespace osmium {
* Use osmium::builder::add_tag_list() instead.
*/
inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
size_t pos = buffer.committed();
const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
func(tl_builder);
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <limits>
@@ -44,16 +43,23 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <osmium/builder/builder.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
class Node;
namespace memory {
class Buffer;
} // namespace memory
@@ -186,9 +192,9 @@ namespace osmium {
}; // class NodeRefListBuilder
typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
using WayNodeListBuilder = NodeRefListBuilder<WayNodeList>;
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
@@ -353,8 +359,8 @@ namespace osmium {
}; // class OSMObjectBuilder
typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
using NodeBuilder = OSMObjectBuilder<osmium::Node>;
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
class WayBuilder : public OSMObjectBuilder<osmium::Way> {
@@ -398,7 +404,7 @@ namespace osmium {
}; // class AreaBuilder
typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
} // namespace builder
+9 -1
View File
@@ -34,8 +34,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
#include <osmium/osm/diff_object.hpp>
@@ -49,7 +51,7 @@ namespace osmium {
* underlying OSMObjects.
*/
template <typename TBasicIterator>
class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
class DiffIterator {
static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
@@ -76,6 +78,12 @@ namespace osmium {
public:
using iterator_category = std::input_iterator_tag;
using value_type = const osmium::DiffObject;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
DiffIterator(TBasicIterator begin, TBasicIterator end) :
m_prev(begin),
m_curr(begin),
+7 -2
View File
@@ -36,11 +36,16 @@ DEALINGS IN THE SOFTWARE.
#include <memory>
#include <utility>
#include <osmium/fwd.hpp>
#include <osmium/handler.hpp>
namespace osmium {
class Node;
class Way;
class Relation;
class Area;
class Changeset;
namespace handler {
namespace detail {
@@ -143,7 +148,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
class DynamicHandler : public osmium::handler::Handler {
typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
using impl_ptr = std::unique_ptr<osmium::handler::detail::HandlerWrapperBase>;
impl_ptr m_impl;
public:
@@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <string>
#include <utility>
#include <vector>
#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
#include <osmium/handler/node_locations_for_ways.hpp> // IWYU pragma: keep
#include <osmium/io/file.hpp>
#include <osmium/io/header.hpp>
#include <osmium/io/reader.hpp>
+19 -15
View File
@@ -46,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
@@ -148,7 +150,7 @@ namespace osmium {
/**
* Add all points of an outer or inner ring to a multipolygon.
*/
void add_points(const osmium::OuterRing& nodes) {
void add_points(const osmium::NodeRefList& nodes) {
osmium::Location last_location;
for (const osmium::NodeRef& node_ref : nodes) {
if (last_location != node_ref.location()) {
@@ -169,7 +171,7 @@ namespace osmium {
template <typename... TArgs>
explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
m_projection(),
m_impl(std::forward<TArgs>(args)...) {
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
}
/**
@@ -179,15 +181,16 @@ namespace osmium {
template <typename... TArgs>
explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
m_projection(std::move(projection)),
m_impl(std::forward<TArgs>(args)...) {
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
}
typedef TProjection projection_type;
typedef typename TGeomImpl::point_type point_type;
typedef typename TGeomImpl::linestring_type linestring_type;
typedef typename TGeomImpl::polygon_type polygon_type;
typedef typename TGeomImpl::multipolygon_type multipolygon_type;
typedef typename TGeomImpl::ring_type ring_type;
using projection_type = TProjection;
using point_type = typename TGeomImpl::point_type;
using linestring_type = typename TGeomImpl::linestring_type;
using polygon_type = typename TGeomImpl::polygon_type;
using multipolygon_type = typename TGeomImpl::multipolygon_type;
using ring_type = typename TGeomImpl::ring_type;
int epsg() const {
return m_projection.epsg();
@@ -280,13 +283,13 @@ namespace osmium {
}
if (num_points < 2) {
throw osmium::geometry_error("need at least two points for linestring");
throw osmium::geometry_error{"need at least two points for linestring"};
}
return linestring_finish(num_points);
}
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
try {
return create_linestring(way.nodes(), un, dir);
} catch (osmium::geometry_error& e) {
@@ -354,13 +357,13 @@ namespace osmium {
}
if (num_points < 4) {
throw osmium::geometry_error("need at least four points for polygon");
throw osmium::geometry_error{"need at least four points for polygon"};
}
return polygon_finish(num_points);
}
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
try {
return create_polygon(way.nodes(), un, dir);
} catch (osmium::geometry_error& e) {
@@ -378,8 +381,8 @@ namespace osmium {
m_impl.multipolygon_start();
for (auto it = area.cbegin(); it != area.cend(); ++it) {
const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
if (it->type() == osmium::item_type::outer_ring) {
auto& ring = static_cast<const osmium::OuterRing&>(*it);
if (num_polygons > 0) {
m_impl.multipolygon_polygon_finish();
}
@@ -390,6 +393,7 @@ namespace osmium {
++num_rings;
++num_polygons;
} else if (it->type() == osmium::item_type::inner_ring) {
auto& ring = static_cast<const osmium::InnerRing&>(*it);
m_impl.multipolygon_inner_ring_start();
add_points(ring);
m_impl.multipolygon_inner_ring_finish();
@@ -399,7 +403,7 @@ namespace osmium {
// if there are no rings, this area is invalid
if (num_rings == 0) {
throw osmium::geometry_error("area contains no rings");
throw osmium::geometry_error{"invalid area"};
}
m_impl.multipolygon_polygon_finish();
+7 -6
View File
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <string>
#include <utility>
@@ -53,13 +54,13 @@ namespace osmium {
public:
typedef std::string point_type;
typedef std::string linestring_type;
typedef std::string polygon_type;
typedef std::string multipolygon_type;
typedef std::string ring_type;
using point_type = std::string;
using linestring_type = std::string;
using polygon_type = std::string;
using multipolygon_type = std::string;
using ring_type = std::string;
GeoJSONFactoryImpl(int precision = 7) :
GeoJSONFactoryImpl(int /* srid */, int precision = 7) :
m_precision(precision) {
}
+37 -20
View File
@@ -42,9 +42,14 @@ DEALINGS IN THE SOFTWARE.
* @attention If you include this file, you'll need to link with `libgeos`.
*/
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
@@ -59,11 +64,13 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/geom/factory.hpp>
#include <osmium/geom/coordinates.hpp>
#include <osmium/util/compatibility.hpp>
// MSVC doesn't support throw_with_nested yet
#ifdef _MSC_VER
# define THROW throw
#else
# include <exception>
# define THROW std::throw_with_nested
#endif
@@ -71,8 +78,8 @@ namespace osmium {
struct geos_geometry_error : public geometry_error {
geos_geometry_error(const char* message) :
geometry_error(std::string("geometry creation failed in GEOS library: ") + message) {
explicit geos_geometry_error(const char* message) :
geometry_error(std::string{"geometry creation failed in GEOS library: "} + message) {
}
}; // struct geos_geometry_error
@@ -93,19 +100,29 @@ namespace osmium {
public:
typedef std::unique_ptr<geos::geom::Point> point_type;
typedef std::unique_ptr<geos::geom::LineString> linestring_type;
typedef std::unique_ptr<geos::geom::Polygon> polygon_type;
typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
typedef std::unique_ptr<geos::geom::LinearRing> ring_type;
using point_type = std::unique_ptr<geos::geom::Point>;
using linestring_type = std::unique_ptr<geos::geom::LineString>;
using polygon_type = std::unique_ptr<geos::geom::Polygon>;
using multipolygon_type = std::unique_ptr<geos::geom::MultiPolygon>;
using ring_type = std::unique_ptr<geos::geom::LinearRing>;
explicit GEOSFactoryImpl(geos::geom::GeometryFactory& geos_factory) :
explicit GEOSFactoryImpl(int /* srid */, geos::geom::GeometryFactory& geos_factory) :
m_precision_model(nullptr),
m_our_geos_factory(nullptr),
m_geos_factory(&geos_factory) {
}
explicit GEOSFactoryImpl(int srid = -1) :
/**
* @deprecated Do not set SRID explicitly. It will be set to the
* correct value automatically.
*/
OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
m_precision_model(new geos::geom::PrecisionModel),
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
m_geos_factory(m_our_geos_factory.get()) {
}
explicit GEOSFactoryImpl(int srid) :
m_precision_model(new geos::geom::PrecisionModel),
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
m_geos_factory(m_our_geos_factory.get()) {
@@ -116,7 +133,7 @@ namespace osmium {
point_type make_point(const osmium::geom::Coordinates& xy) const {
try {
return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y)));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -126,7 +143,7 @@ namespace osmium {
void linestring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -134,7 +151,7 @@ namespace osmium {
void linestring_add_location(const osmium::geom::Coordinates& xy) {
try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -142,7 +159,7 @@ namespace osmium {
linestring_type linestring_finish(size_t /* num_points */) {
try {
return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -166,7 +183,7 @@ namespace osmium {
});
m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
m_rings.clear();
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -174,7 +191,7 @@ namespace osmium {
void multipolygon_outer_ring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -182,7 +199,7 @@ namespace osmium {
void multipolygon_outer_ring_finish() {
try {
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -190,7 +207,7 @@ namespace osmium {
void multipolygon_inner_ring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -198,7 +215,7 @@ namespace osmium {
void multipolygon_inner_ring_finish() {
try {
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -206,7 +223,7 @@ namespace osmium {
void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -219,7 +236,7 @@ namespace osmium {
});
m_polygons.clear();
return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
} catch (geos::util::GEOSException& e) {
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ namespace osmium {
namespace haversine {
/// @brief Earth's quadratic mean radius for WGS84
constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
constexpr const double EARTH_RADIUS_IN_METERS = 6372797.560856;
/**
* Calculate distance in meters between two sets of coordinates.
+20 -18
View File
@@ -62,33 +62,34 @@ namespace osmium {
public:
typedef std::unique_ptr<OGRPoint> point_type;
typedef std::unique_ptr<OGRLineString> linestring_type;
typedef std::unique_ptr<OGRPolygon> polygon_type;
typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
typedef std::unique_ptr<OGRLinearRing> ring_type;
using point_type = std::unique_ptr<OGRPoint>;
using linestring_type = std::unique_ptr<OGRLineString>;
using polygon_type = std::unique_ptr<OGRPolygon>;
using multipolygon_type = std::unique_ptr<OGRMultiPolygon>;
using ring_type = std::unique_ptr<OGRLinearRing>;
private:
linestring_type m_linestring;
multipolygon_type m_multipolygon;
polygon_type m_polygon;
ring_type m_ring;
linestring_type m_linestring{nullptr};
multipolygon_type m_multipolygon{nullptr};
polygon_type m_polygon{nullptr};
ring_type m_ring{nullptr};
public:
OGRFactoryImpl() = default;
explicit OGRFactoryImpl(int /* srid */) {
}
/* Point */
point_type make_point(const osmium::geom::Coordinates& xy) const {
return point_type(new OGRPoint(xy.x, xy.y));
return point_type{new OGRPoint{xy.x, xy.y}};
}
/* LineString */
void linestring_start() {
m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
m_linestring.reset(new OGRLineString{});
}
void linestring_add_location(const osmium::geom::Coordinates& xy) {
@@ -97,13 +98,14 @@ namespace osmium {
}
linestring_type linestring_finish(size_t /* num_points */) {
assert(!!m_linestring);
return std::move(m_linestring);
}
/* Polygon */
void polygon_start() {
m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
m_ring.reset(new OGRLinearRing{});
}
void polygon_add_location(const osmium::geom::Coordinates& xy) {
@@ -112,7 +114,7 @@ namespace osmium {
}
polygon_type polygon_finish(size_t /* num_points */) {
std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
auto polygon = std::unique_ptr<OGRPolygon>{new OGRPolygon{}};
polygon->addRingDirectly(m_ring.release());
return polygon;
}
@@ -120,11 +122,11 @@ namespace osmium {
/* MultiPolygon */
void multipolygon_start() {
m_multipolygon.reset(new OGRMultiPolygon());
m_multipolygon.reset(new OGRMultiPolygon{});
}
void multipolygon_polygon_start() {
m_polygon.reset(new OGRPolygon());
m_polygon.reset(new OGRPolygon{});
}
void multipolygon_polygon_finish() {
@@ -134,7 +136,7 @@ namespace osmium {
}
void multipolygon_outer_ring_start() {
m_ring.reset(new OGRLinearRing());
m_ring.reset(new OGRLinearRing{});
}
void multipolygon_outer_ring_finish() {
@@ -144,7 +146,7 @@ namespace osmium {
}
void multipolygon_inner_ring_start() {
m_ring.reset(new OGRLinearRing());
m_ring.reset(new OGRLinearRing{});
}
void multipolygon_inner_ring_finish() {
+16 -6
View File
@@ -70,15 +70,19 @@ namespace osmium {
public:
CRS(const std::string& crs) :
explicit CRS(const std::string& crs) :
m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
if (!m_crs) {
throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
throw osmium::projection_error(std::string{"creation of CRS failed: "} + pj_strerrno(*pj_get_errno_ref()));
}
}
CRS(int epsg) :
CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
explicit CRS(const char* crs) :
CRS(std::string{crs}) {
}
explicit CRS(int epsg) :
CRS(std::string{"+init=epsg:"} + std::to_string(epsg)) {
}
/**
@@ -127,13 +131,19 @@ namespace osmium {
public:
Projection(const std::string& proj_string) :
explicit Projection(const std::string& proj_string) :
m_epsg(-1),
m_proj_string(proj_string),
m_crs_user(proj_string) {
}
Projection(int epsg) :
explicit Projection(const char* proj_string) :
m_epsg(-1),
m_proj_string(proj_string),
m_crs_user(proj_string) {
}
explicit Projection(int epsg) :
m_epsg(epsg),
m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
m_crs_user(epsg) {
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/factory.hpp>
@@ -53,13 +55,13 @@ namespace osmium {
public:
typedef void point_type;
typedef void linestring_type;
typedef void polygon_type;
typedef void multipolygon_type;
typedef void ring_type;
using point_type = void;
using linestring_type = void;
using polygon_type = void;
using multipolygon_type = void;
using ring_type = void;
RapidGeoJSONFactoryImpl(TWriter& writer) :
RapidGeoJSONFactoryImpl(int /* srid */, TWriter& writer) :
m_writer(&writer) {
}
+44 -1
View File
@@ -33,9 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstdint>
#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/osm/location.hpp>
namespace osmium {
@@ -57,24 +60,64 @@ namespace osmium {
*/
struct Tile {
/// x coordinate
uint32_t x;
/// y coordinate
uint32_t y;
/// Zoom level
uint32_t z;
/**
* Create a tile with the given zoom level and x any y tile
* coordinates.
*
* The values are not checked for validity.
*
* @pre @code zoom <= 30 && x < 2^zoom && y < 2^zoom @endcode
*/
explicit Tile(uint32_t zoom, uint32_t tx, uint32_t ty) noexcept : x(tx), y(ty), z(zoom) {
assert(zoom <= 30u);
assert(x < (1u << zoom));
assert(y < (1u << zoom));
}
/**
* Create a tile with the given zoom level that contains the given
* location.
*
* The values are not checked for validity.
*
* @pre @code location.valid() && zoom <= 30 @endcode
*/
explicit Tile(uint32_t zoom, const osmium::Location& location) :
z(zoom) {
osmium::geom::Coordinates c = lonlat_to_mercator(location);
assert(zoom <= 30u);
assert(location.valid());
const osmium::geom::Coordinates c = lonlat_to_mercator(location);
const int32_t n = 1 << zoom;
const double scale = detail::max_coordinate_epsg3857 * 2 / n;
x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1));
y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1));
}
/**
* Check whether this tile is valid. For a tile to be valid the
* zoom level must be between 0 and 30 and the coordinates must
* each be between 0 and 2^zoom-1.
*/
bool valid() const noexcept {
if (z > 30) {
return false;
}
const uint32_t max = 1 << z;
return x < max && y < max;
}
}; // struct Tile
/// Tiles are equal if all their attributes are equal.
inline bool operator==(const Tile& a, const Tile& b) {
return a.z == b.z && a.x == b.x && a.y == b.y;
}
+2 -2
View File
@@ -44,11 +44,11 @@ namespace osmium {
*/
struct projection_error : public std::runtime_error {
projection_error(const std::string& what) :
explicit projection_error(const std::string& what) :
std::runtime_error(what) {
}
projection_error(const char* what) :
explicit projection_error(const char* what) :
std::runtime_error(what) {
}
+15 -15
View File
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
@@ -60,14 +61,13 @@ namespace osmium {
template <typename T>
inline void str_push(std::string& str, T data) {
size_t size = str.size();
str.resize(size + sizeof(T));
std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
str.append(reinterpret_cast<const char*>(&data), sizeof(T));
}
inline std::string convert_to_hex(const std::string& str) {
static const char* lookup_hex = "0123456789ABCDEF";
std::string out;
out.reserve(str.size() * 2);
for (char c : str) {
out += lookup_hex[(c >> 4) & 0xf];
@@ -79,9 +79,6 @@ namespace osmium {
class WKBFactoryImpl {
/// OSM data always uses SRID 4326 (WGS84).
static constexpr uint32_t srid = 4326;
/**
* Type of WKB geometry.
* These definitions are from
@@ -112,6 +109,7 @@ namespace osmium {
std::string m_data;
uint32_t m_points {0};
int m_srid;
wkb_type m_wkb_type;
out_type m_out_type;
@@ -130,11 +128,11 @@ namespace osmium {
#endif
if (m_wkb_type == wkb_type::ewkb) {
str_push(str, type | wkbSRID);
str_push(str, srid);
str_push(str, m_srid);
} else {
str_push(str, type);
}
size_t offset = str.size();
const size_t offset = str.size();
if (add_length) {
str_push(str, static_cast<uint32_t>(0));
}
@@ -142,18 +140,20 @@ namespace osmium {
}
void set_size(const size_t offset, const size_t size) {
*reinterpret_cast<uint32_t*>(&m_data[offset]) = static_cast_with_assert<uint32_t>(size);
uint32_t s = static_cast_with_assert<uint32_t>(size);
std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]);
}
public:
typedef std::string point_type;
typedef std::string linestring_type;
typedef std::string polygon_type;
typedef std::string multipolygon_type;
typedef std::string ring_type;
using point_type = std::string;
using linestring_type = std::string;
using polygon_type = std::string;
using multipolygon_type = std::string;
using ring_type = std::string;
explicit WKBFactoryImpl(wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
explicit WKBFactoryImpl(int srid, wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
m_srid(srid),
m_wkb_type(wtype),
m_out_type(otype) {
}
+27 -10
View File
@@ -45,29 +45,44 @@ namespace osmium {
namespace geom {
enum class wkt_type : bool {
wkt = false,
ewkt = true
}; // enum class wkt_type
namespace detail {
class WKTFactoryImpl {
std::string m_srid_prefix;
std::string m_str;
int m_precision;
wkt_type m_wkt_type;
public:
typedef std::string point_type;
typedef std::string linestring_type;
typedef std::string polygon_type;
typedef std::string multipolygon_type;
typedef std::string ring_type;
using point_type = std::string;
using linestring_type = std::string;
using polygon_type = std::string;
using multipolygon_type = std::string;
using ring_type = std::string;
WKTFactoryImpl(int precision = 7) :
m_precision(precision) {
WKTFactoryImpl(int srid, int precision = 7, wkt_type wtype = wkt_type::wkt) :
m_srid_prefix(),
m_precision(precision),
m_wkt_type(wtype) {
if (m_wkt_type == wkt_type::ewkt) {
m_srid_prefix = "SRID=";
m_srid_prefix += std::to_string(srid);
m_srid_prefix += ';';
}
}
/* Point */
point_type make_point(const osmium::geom::Coordinates& xy) const {
std::string str {"POINT"};
std::string str {m_srid_prefix};
str += "POINT";
xy.append_to_string(str, '(', ' ', ')', m_precision);
return str;
}
@@ -75,7 +90,8 @@ namespace osmium {
/* LineString */
void linestring_start() {
m_str = "LINESTRING(";
m_str = m_srid_prefix;
m_str += "LINESTRING(";
}
void linestring_add_location(const osmium::geom::Coordinates& xy) {
@@ -97,7 +113,8 @@ namespace osmium {
/* MultiPolygon */
void multipolygon_start() {
m_str = "MULTIPOLYGON(";
m_str = m_srid_prefix;
m_str += "MULTIPOLYGON(";
}
void multipolygon_polygon_start() {
+41 -15
View File
@@ -33,56 +33,82 @@ DEALINGS IN THE SOFTWARE.
*/
#include <osmium/fwd.hpp>
namespace osmium {
class Area;
class Changeset;
class ChangesetDiscussion;
class InnerRing;
class Node;
class OSMObject;
class OuterRing;
class Relation;
class RelationMemberList;
class TagList;
class Way;
class WayNodeList;
/**
* @brief Osmium handlers provide callbacks for OSM objects
*/
namespace handler {
/**
* Handler base class. Never used directly. Derive your own class from
* this class and "overwrite" the functions. Your functions must be
* named the same, but don't have to be const or noexcept or take
* their argument as const.
*
* Usually you will overwrite the node(), way(), and relation()
* functions. If your program supports multipolygons, also the area()
* function. You can also use the osm_object() function which is
* called for all OSM objects (nodes, ways, relations, and areas)
* right before each of their specific callbacks is called.
*
* If you are working with changesets, implement the changeset()
* function.
*/
class Handler {
public:
void osm_object(const osmium::OSMObject&) const {
void osm_object(const osmium::OSMObject&) const noexcept {
}
void node(const osmium::Node&) const {
void node(const osmium::Node&) const noexcept {
}
void way(const osmium::Way&) const {
void way(const osmium::Way&) const noexcept {
}
void relation(const osmium::Relation&) const {
void relation(const osmium::Relation&) const noexcept {
}
void area(const osmium::Area&) const {
void area(const osmium::Area&) const noexcept {
}
void changeset(const osmium::Changeset&) const {
void changeset(const osmium::Changeset&) const noexcept {
}
void tag_list(const osmium::TagList&) const {
void tag_list(const osmium::TagList&) const noexcept {
}
void way_node_list(const osmium::WayNodeList&) const {
void way_node_list(const osmium::WayNodeList&) const noexcept {
}
void relation_member_list(const osmium::RelationMemberList&) const {
void relation_member_list(const osmium::RelationMemberList&) const noexcept {
}
void outer_ring(const osmium::OuterRing&) const {
void outer_ring(const osmium::OuterRing&) const noexcept {
}
void inner_ring(const osmium::InnerRing&) const {
void inner_ring(const osmium::InnerRing&) const noexcept {
}
void changeset_discussion(const osmium::ChangesetDiscussion&) const {
void changeset_discussion(const osmium::ChangesetDiscussion&) const noexcept {
}
void flush() const {
void flush() const noexcept {
}
}; // class Handler
+1 -1
View File
@@ -67,7 +67,7 @@ namespace osmium {
template <typename... THandler>
class ChainHandler : public osmium::handler::Handler {
typedef std::tuple<THandler&...> handlers_type;
using handlers_type = std::tuple<THandler&...>;
handlers_type m_handlers;
template <int N, int SIZE, typename THandlers>
@@ -51,11 +51,11 @@ namespace osmium {
*/
struct out_of_order_error : public std::runtime_error {
out_of_order_error(const std::string& what) :
explicit out_of_order_error(const std::string& what) :
std::runtime_error(what) {
}
out_of_order_error(const char* what) :
explicit out_of_order_error(const char* what) :
std::runtime_error(what) {
}
@@ -57,7 +57,7 @@ namespace osmium {
*/
class DiskStore : public osmium::handler::Handler {
typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, size_t>;
size_t m_offset = 0;
int m_data_fd;
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <limits>
#include <type_traits>
#include <osmium/handler.hpp>
@@ -50,7 +51,7 @@ namespace osmium {
namespace handler {
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
using dummy_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
/**
* Handler to retrieve locations from nodes and add them to ways.
@@ -69,8 +70,8 @@ namespace osmium {
public:
typedef TStoragePosIDs index_pos_type;
typedef TStorageNegIDs index_neg_type;
using index_pos_type = TStoragePosIDs;
using index_neg_type = TStorageNegIDs;
private:
@@ -80,6 +81,8 @@ namespace osmium {
/// Object that handles the actual storage of the node locations (with negative IDs).
TStorageNegIDs& m_storage_neg;
osmium::unsigned_object_id_type m_last_id{0};
bool m_ignore_errors {false};
bool m_must_sort {false};
@@ -115,7 +118,11 @@ namespace osmium {
* Store the location of the node in the storage.
*/
void node(const osmium::Node& node) {
m_must_sort = true;
if (node.positive_id() < m_last_id) {
m_must_sort = true;
}
m_last_id = node.positive_id();
const osmium::object_id_type id = node.id();
if (id >= 0) {
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
@@ -144,6 +151,7 @@ namespace osmium {
m_storage_pos.sort();
m_storage_neg.sort();
m_must_sort = false;
m_last_id = std::numeric_limits<osmium::unsigned_object_id_type>::max();
}
bool error = false;
for (auto& node_ref : way.nodes()) {
@@ -152,7 +160,7 @@ namespace osmium {
if (!node_ref.location()) {
error = true;
}
} catch (osmium::not_found&) {
} catch (const osmium::not_found&) {
error = true;
}
}
@@ -52,7 +52,7 @@ namespace osmium {
*/
class ObjectRelations : public osmium::handler::Handler {
typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
using index_type = osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type>;
index_type& m_index_n2w;
index_type& m_index_n2r;
@@ -54,9 +54,9 @@ namespace osmium {
}
assert(config.size() > 1);
const std::string& filename = config[1];
int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
if (fd == -1) {
throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno));
}
return new T(fd);
}
@@ -33,10 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <new> // IWYU pragma: keep
#include <stdexcept>
#include <osmium/index/index.hpp>
#include <osmium/util/memory_mapping.hpp>
namespace osmium {
@@ -63,22 +66,26 @@ namespace osmium {
mmap_vector_base(int fd, size_t capacity, size_t size = 0) :
m_size(size),
m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) {
assert(size <= capacity);
std::fill(data() + size, data() + capacity, osmium::index::empty_value<T>());
shrink_to_fit();
}
explicit mmap_vector_base(size_t capacity = mmap_vector_size_increment) :
m_size(0),
m_mapping(capacity) {
std::fill_n(data(), capacity, osmium::index::empty_value<T>());
}
~mmap_vector_base() noexcept = default;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef T* iterator;
typedef const T* const_iterator;
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = value_type*;
using const_iterator = const value_type*;
void close() {
m_mapping.unmap();
@@ -105,6 +112,7 @@ namespace osmium {
}
T& operator[](size_t n) {
assert(n < m_size);
return data()[n];
}
@@ -120,20 +128,21 @@ namespace osmium {
}
void shrink_to_fit() {
// XXX do something here
while (m_size > 0 && data()[m_size - 1] == osmium::index::empty_value<T>()) {
--m_size;
}
}
void push_back(const T& value) {
if (m_size >= capacity()) {
resize(m_size+1);
}
data()[m_size] = value;
++m_size;
resize(m_size+1);
data()[m_size-1] = value;
}
void reserve(size_t new_capacity) {
if (new_capacity > capacity()) {
const size_t old_capacity = capacity();
m_mapping.resize(new_capacity);
std::fill(data() + old_capacity, data() + new_capacity, osmium::index::empty_value<T>());
}
}
@@ -141,9 +150,6 @@ namespace osmium {
if (new_size > capacity()) {
reserve(new_size + osmium::detail::mmap_vector_size_increment);
}
if (new_size > size()) {
new (data() + size()) T[new_size - size()];
}
m_size = new_size;
}
@@ -33,6 +33,11 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <osmium/index/detail/mmap_vector_base.hpp>
#include <osmium/index/detail/tmpfile.hpp>
#include <osmium/util/file.hpp>
@@ -48,6 +53,16 @@ namespace osmium {
template <typename T>
class mmap_vector_file : public mmap_vector_base<T> {
size_t filesize(int fd) const {
const size_t size = osmium::util::file_size(fd);
if (size % sizeof(T) != 0) {
throw std::runtime_error("Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ").");
}
return size / sizeof(T);
}
public:
mmap_vector_file() :
@@ -59,8 +74,8 @@ namespace osmium {
explicit mmap_vector_file(int fd) :
mmap_vector_base<T>(
fd,
osmium::util::file_size(fd) / sizeof(T),
osmium::util::file_size(fd) / sizeof(T)) {
std::max(osmium::detail::mmap_vector_size_increment, filesize(fd)),
filesize(fd)) {
}
~mmap_vector_file() noexcept = default;
@@ -55,10 +55,10 @@ namespace osmium {
public:
typedef TValue element_type;
typedef TVector vector_type;
typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_iterator const_iterator;
using element_type = TValue;
using vector_type = TVector;
using iterator = typename vector_type::iterator;
using const_iterator = typename vector_type::const_iterator;
VectorBasedDenseMap() :
m_vector() {
@@ -88,7 +88,7 @@ namespace osmium {
not_found_error(id);
}
return value;
} catch (std::out_of_range&) {
} catch (const std::out_of_range&) {
not_found_error(id);
}
}
@@ -146,10 +146,10 @@ namespace osmium {
public:
typedef typename std::pair<TId, TValue> element_type;
typedef TVector<element_type> vector_type;
typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_iterator const_iterator;
using element_type = typename std::pair<TId, TValue>;
using vector_type = TVector<element_type>;
using iterator = typename vector_type::iterator;
using const_iterator = typename vector_type::const_iterator;
private:
@@ -52,10 +52,10 @@ namespace osmium {
public:
typedef typename std::pair<TId, TValue> element_type;
typedef TVector<element_type> vector_type;
typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_iterator const_iterator;
using element_type = typename std::pair<TId, TValue>;
using vector_type = TVector<element_type>;
using iterator = typename vector_type::iterator;
using const_iterator = typename vector_type::const_iterator;
private:
@@ -127,7 +127,7 @@ namespace osmium {
}
void remove(const TId id, const TValue value) {
auto r = get_all(id);
const auto r = get_all(id);
for (auto it = r.first; it != r.second; ++it) {
if (it->second == value) {
it->second = 0;
+2 -2
View File
@@ -49,11 +49,11 @@ namespace osmium {
*/
struct not_found : public std::runtime_error {
not_found(const std::string& what) :
explicit not_found(const std::string& what) :
std::runtime_error(what) {
}
not_found(const char* what) :
explicit not_found(const char* what) :
std::runtime_error(what) {
}
+7 -7
View File
@@ -98,10 +98,10 @@ namespace osmium {
public:
/// The "key" type, usually osmium::unsigned_object_id_type.
typedef TId key_type;
using key_type = TId;
/// The "value" type, usually a Location or size_t.
typedef TValue value_type;
using value_type = TValue;
Map() = default;
@@ -171,10 +171,10 @@ namespace osmium {
public:
typedef TId id_type;
typedef TValue value_type;
typedef osmium::index::map::Map<id_type, value_type> map_type;
typedef std::function<map_type*(const std::vector<std::string>&)> create_map_func;
using id_type = TId;
using value_type = TValue;
using map_type = osmium::index::map::Map<id_type, value_type>;
using create_map_func = std::function<map_type*(const std::vector<std::string>&)>;
private:
@@ -207,7 +207,7 @@ namespace osmium {
}
bool has_map_type(const std::string& map_type_name) const {
return m_callbacks.count(map_type_name);
return m_callbacks.count(map_type_name) != 0;
}
std::vector<std::string> map_types() const {
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iterator>
#include <map>
#include <stdexcept>
#include <vector>
#include <osmium/index/map.hpp>
@@ -98,7 +97,7 @@ namespace osmium {
}
void dump_as_list(const int fd) final {
typedef typename std::map<TId, TValue>::value_type t;
using t = typename std::map<TId, TValue>::value_type;
std::vector<t> v;
v.reserve(m_elements.size());
std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
+4 -4
View File
@@ -52,7 +52,7 @@ namespace osmium {
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
typedef typename std::pair<TId, TValue> element_type;
using element_type = typename std::pair<TId, TValue>;
Multimap(const Multimap&) = delete;
Multimap& operator=(const Multimap&) = delete;
@@ -65,10 +65,10 @@ namespace osmium {
public:
/// The "key" type, usually osmium::unsigned_object_id_type.
typedef TId key_type;
using key_type = TId;
/// The "value" type, usually a Location or size_t.
typedef TValue value_type;
using value_type = TValue;
Multimap() = default;
@@ -77,7 +77,7 @@ namespace osmium {
/// Set the field with id to value.
virtual void set(const TId id, const TValue value) = 0;
typedef element_type* iterator;
using iterator = element_type*;
// virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
@@ -50,10 +50,10 @@ namespace osmium {
template <typename TId, typename TValue>
class HybridIterator {
typedef SparseMemArray<TId, TValue> main_map_type;
typedef SparseMemMultimap<TId, TValue> extra_map_type;
using main_map_type = SparseMemArray<TId, TValue>;
using extra_map_type = SparseMemMultimap<TId, TValue>;
typedef typename std::pair<TId, TValue> element_type;
using element_type = typename std::pair<TId, TValue>;
typename main_map_type::iterator m_begin_main;
typename main_map_type::iterator m_end_main;
@@ -120,16 +120,16 @@ namespace osmium {
template <typename TId, typename TValue>
class Hybrid : public Multimap<TId, TValue> {
typedef SparseMemArray<TId, TValue> main_map_type;
typedef SparseMemMultimap<TId, TValue> extra_map_type;
using main_map_type = SparseMemArray<TId, TValue>;
using extra_map_type = SparseMemMultimap<TId, TValue>;
main_map_type m_main;
extra_map_type m_extra;
public:
typedef HybridIterator<TId, TValue> iterator;
typedef const HybridIterator<TId, TValue> const_iterator;
using iterator = HybridIterator<TId, TValue>;
using const_iterator = const HybridIterator<TId, TValue>;
Hybrid() :
m_main(),
@@ -63,12 +63,11 @@ namespace osmium {
public:
typedef typename std::multimap<const TId, TValue> collection_type;
typedef typename collection_type::iterator iterator;
typedef typename collection_type::const_iterator const_iterator;
typedef typename collection_type::value_type value_type;
typedef typename std::pair<TId, TValue> element_type;
using collection_type = typename std::multimap<const TId, TValue>;
using iterator = typename collection_type::iterator;
using const_iterator = typename collection_type::const_iterator;
using value_type = typename collection_type::value_type;
using element_type = typename std::pair<TId, TValue>;
private:
+2 -1
View File
@@ -45,8 +45,9 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
#include <osmium/io/opl_input.hpp> // IWYU pragma: export
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
#include <osmium/io/xml_input.hpp> // IWYU pragma: export
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
#endif // OSMIUM_IO_ANY_INPUT_HPP
@@ -43,10 +43,9 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <string>
#include <system_error>
#include <bzlib.h>
@@ -55,6 +54,7 @@ DEALINGS IN THE SOFTWARE.
#endif
#include <osmium/io/compression.hpp>
#include <osmium/io/detail/read_write.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp>
@@ -109,7 +109,7 @@ namespace osmium {
explicit Bzip2Compressor(int fd, fsync sync) :
Compressor(sync),
m_file(fdopen(dup(fd), "wb")),
m_file(fdopen(::dup(fd), "wb")),
m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
if (!m_bzfile) {
@@ -165,7 +165,7 @@ namespace osmium {
explicit Bzip2Decompressor(int fd) :
Decompressor(),
m_file(fdopen(dup(fd), "rb")),
m_file(fdopen(::dup(fd), "rb")),
m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
if (!m_bzfile) {
@@ -215,6 +215,8 @@ namespace osmium {
buffer.resize(static_cast<std::string::size_type>(nread));
}
set_offset(size_t(ftell(m_file)));
return buffer;
}
+36 -9
View File
@@ -33,11 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <atomic>
#include <cerrno>
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
@@ -54,6 +55,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/file.hpp>
namespace osmium {
@@ -86,6 +88,9 @@ namespace osmium {
class Decompressor {
std::atomic<size_t> m_file_size {0};
std::atomic<size_t> m_offset {0};
public:
static constexpr unsigned int input_buffer_size = 1024 * 1024;
@@ -105,6 +110,22 @@ namespace osmium {
virtual void close() = 0;
size_t file_size() const noexcept {
return m_file_size;
}
void set_file_size(size_t size) noexcept {
m_file_size = size;
}
size_t offset() const noexcept {
return m_offset;
}
void set_offset(size_t offset) noexcept {
m_offset = offset;
}
}; // class Decompressor
/**
@@ -118,16 +139,16 @@ namespace osmium {
public:
typedef std::function<osmium::io::Compressor*(int, fsync)> create_compressor_type;
typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>;
using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>;
using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, size_t)>;
private:
typedef std::map<const osmium::io::file_compression,
std::tuple<create_compressor_type,
create_decompressor_type_fd,
create_decompressor_type_buffer>> compression_map_type;
using compression_map_type = std::map<const osmium::io::file_compression,
std::tuple<create_compressor_type,
create_decompressor_type_fd,
create_decompressor_type_buffer>>;
compression_map_type m_callbacks;
@@ -182,7 +203,9 @@ namespace osmium {
auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
p->set_file_size(osmium::util::file_size(fd));
return p;
}
error(compression);
@@ -241,6 +264,7 @@ namespace osmium {
int m_fd;
const char *m_buffer;
size_t m_buffer_size;
size_t m_offset = 0;
public:
@@ -284,6 +308,9 @@ namespace osmium {
buffer.resize(std::string::size_type(nread));
}
m_offset += buffer.size();
set_offset(m_offset);
return buffer;
}
@@ -34,29 +34,35 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <future>
#include <cmath>
#include <cstring>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <boost/crc.hpp>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_util.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/crc.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/util/minmax.hpp>
@@ -66,8 +72,6 @@ namespace osmium {
namespace io {
class File;
namespace detail {
constexpr const char* color_bold = "\x1b[1m";
@@ -80,6 +84,10 @@ namespace osmium {
constexpr const char* color_magenta = "\x1b[35m";
constexpr const char* color_cyan = "\x1b[36m";
constexpr const char* color_white = "\x1b[37m";
constexpr const char* color_backg_red = "\x1b[41m";
constexpr const char* color_backg_green = "\x1b[42m";
constexpr const char* color_reset = "\x1b[0m";
struct debug_output_options {
@@ -90,6 +98,11 @@ namespace osmium {
/// Output with ANSI colors?
bool use_color;
/// Add CRC32 checksum to each object?
bool add_crc32;
/// Write in form of a diff file?
bool format_as_diff;
};
/**
@@ -102,16 +115,47 @@ namespace osmium {
const char* m_utf8_prefix = "";
const char* m_utf8_suffix = "";
char m_diff_char = '\0';
void append_encoded_string(const char* data) {
append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix);
}
template <typename... TArgs>
void output_formatted(const char* format, TArgs&&... args) {
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
}
void write_color(const char* color) {
if (m_options.use_color) {
*m_out += color;
}
}
void write_diff() {
if (!m_diff_char) {
return;
}
if (m_options.use_color) {
if (m_diff_char == '-') {
*m_out += color_backg_red;
*m_out += color_white;
*m_out += color_bold;
*m_out += '-';
*m_out += color_reset;
return;
} else if (m_diff_char == '+') {
*m_out += color_backg_green;
*m_out += color_white;
*m_out += color_bold;
*m_out += '+';
*m_out += color_reset;
return;
}
}
*m_out += m_diff_char;
}
void write_string(const char* string) {
*m_out += '"';
write_color(color_blue);
@@ -121,6 +165,7 @@ namespace osmium {
}
void write_object_type(const char* object_type, bool visible = true) {
write_diff();
if (visible) {
write_color(color_bold);
} else {
@@ -132,6 +177,7 @@ namespace osmium {
}
void write_fieldname(const char* name) {
write_diff();
*m_out += " ";
write_color(color_cyan);
*m_out += name;
@@ -161,7 +207,9 @@ namespace osmium {
void write_timestamp(const osmium::Timestamp& timestamp) {
if (timestamp.valid()) {
*m_out += timestamp.to_iso();
output_formatted(" (%d)", timestamp.seconds_since_epoch());
*m_out += " (";
output_int(timestamp.seconds_since_epoch());
*m_out += ')';
} else {
write_error("NOT SET");
}
@@ -169,53 +217,63 @@ namespace osmium {
}
void write_meta(const osmium::OSMObject& object) {
output_formatted("%" PRId64 "\n", object.id());
output_int(object.id());
*m_out += '\n';
if (m_options.add_metadata) {
write_fieldname("version");
output_formatted(" %d", object.version());
*m_out += " ";
output_int(object.version());
if (object.visible()) {
*m_out += " visible\n";
} else {
write_error(" deleted\n");
}
write_fieldname("changeset");
output_formatted("%d\n", object.changeset());
output_int(object.changeset());
*m_out += '\n';
write_fieldname("timestamp");
write_timestamp(object.timestamp());
write_fieldname("user");
output_formatted(" %d ", object.uid());
*m_out += " ";
output_int(object.uid());
*m_out += ' ';
write_string(object.user());
*m_out += '\n';
}
}
void write_tags(const osmium::TagList& tags, const char* padding="") {
if (!tags.empty()) {
write_fieldname("tags");
*m_out += padding;
output_formatted(" %d\n", tags.size());
if (tags.empty()) {
return;
}
write_fieldname("tags");
*m_out += padding;
*m_out += " ";
output_int(tags.size());
*m_out += '\n';
osmium::max_op<size_t> max;
for (const auto& tag : tags) {
max.update(std::strlen(tag.key()));
}
for (const auto& tag : tags) {
*m_out += " ";
write_string(tag.key());
auto spacing = max() - std::strlen(tag.key());
while (spacing--) {
*m_out += " ";
}
*m_out += " = ";
write_string(tag.value());
*m_out += '\n';
osmium::max_op<size_t> max;
for (const auto& tag : tags) {
max.update(std::strlen(tag.key()));
}
for (const auto& tag : tags) {
write_diff();
*m_out += " ";
write_string(tag.key());
auto spacing = max() - std::strlen(tag.key());
while (spacing--) {
*m_out += " ";
}
*m_out += " = ";
write_string(tag.value());
*m_out += '\n';
}
}
void write_location(const osmium::Location& location) {
write_fieldname("lon/lat");
output_formatted(" %.7f,%.7f", location.lon_without_check(), location.lat_without_check());
*m_out += " ";
location.as_string_without_check(std::back_inserter(*m_out));
if (!location.valid()) {
write_error(" INVALID LOCATION!");
}
@@ -230,13 +288,30 @@ namespace osmium {
}
const auto& bl = box.bottom_left();
const auto& tr = box.top_right();
output_formatted("%.7f,%.7f %.7f,%.7f", bl.lon_without_check(), bl.lat_without_check(), tr.lon_without_check(), tr.lat_without_check());
bl.as_string(std::back_inserter(*m_out));
*m_out += ' ';
tr.as_string(std::back_inserter(*m_out));
if (!box.valid()) {
write_error(" INVALID BOX!");
}
*m_out += '\n';
}
template <typename T>
void write_crc32(const T& object) {
write_fieldname("crc32");
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(object);
output_formatted(" %x\n", crc32().checksum());
}
void write_crc32(const osmium::Changeset& object) {
write_fieldname("crc32");
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(object);
output_formatted(" %x\n", crc32().checksum());
}
public:
DebugOutputBlock(osmium::memory::Buffer&& buffer, const debug_output_options& options) :
@@ -265,6 +340,8 @@ namespace osmium {
}
void node(const osmium::Node& node) {
m_diff_char = m_options.format_as_diff ? node.diff_as_char() : '\0';
write_object_type("node", node.visible());
write_meta(node);
@@ -274,17 +351,24 @@ namespace osmium {
write_tags(node.tags());
if (m_options.add_crc32) {
write_crc32(node);
}
*m_out += '\n';
}
void way(const osmium::Way& way) {
m_diff_char = m_options.format_as_diff ? way.diff_as_char() : '\0';
write_object_type("way", way.visible());
write_meta(way);
write_tags(way.tags());
write_fieldname("nodes");
output_formatted(" %d", way.nodes().size());
*m_out += " ";
output_int(way.nodes().size());
if (way.nodes().size() < 2) {
write_error(" LESS THAN 2 NODES!\n");
} else if (way.nodes().size() > 2000) {
@@ -295,32 +379,45 @@ namespace osmium {
*m_out += " (open)\n";
}
int width = int(log10(way.nodes().size())) + 1;
const int width = int(std::log10(way.nodes().size())) + 1;
int n = 0;
for (const auto& node_ref : way.nodes()) {
write_diff();
write_counter(width, n++);
output_formatted("%10" PRId64, node_ref.ref());
if (node_ref.location().valid()) {
output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check());
*m_out += " (";
node_ref.location().as_string(std::back_inserter(*m_out));
*m_out += ')';
}
*m_out += '\n';
}
if (m_options.add_crc32) {
write_crc32(way);
}
*m_out += '\n';
}
void relation(const osmium::Relation& relation) {
static const char* short_typename[] = { "node", "way ", "rel " };
m_diff_char = m_options.format_as_diff ? relation.diff_as_char() : '\0';
write_object_type("relation", relation.visible());
write_meta(relation);
write_tags(relation.tags());
write_fieldname("members");
output_formatted(" %d\n", relation.members().size());
*m_out += " ";
output_int(relation.members().size());
*m_out += '\n';
int width = int(log10(relation.members().size())) + 1;
const int width = int(std::log10(relation.members().size())) + 1;
int n = 0;
for (const auto& member : relation.members()) {
write_diff();
write_counter(width, n++);
*m_out += short_typename[item_type_to_nwr_index(member.type())];
output_formatted(" %10" PRId64 " ", member.ref());
@@ -328,15 +425,20 @@ namespace osmium {
*m_out += '\n';
}
if (m_options.add_crc32) {
write_crc32(relation);
}
*m_out += '\n';
}
void changeset(const osmium::Changeset& changeset) {
write_object_type("changeset");
output_formatted("%d\n", changeset.id());
output_int(changeset.id());
*m_out += '\n';
write_fieldname("num changes");
output_formatted("%d", changeset.num_changes());
output_int(changeset.num_changes());
if (changeset.num_changes() == 0) {
write_error(" NO CHANGES!");
}
@@ -355,7 +457,9 @@ namespace osmium {
}
write_fieldname("user");
output_formatted(" %d ", changeset.uid());
*m_out += " ";
output_int(changeset.uid());
*m_out += ' ';
write_string(changeset.user());
*m_out += '\n';
@@ -364,9 +468,11 @@ namespace osmium {
if (changeset.num_comments() > 0) {
write_fieldname("comments");
output_formatted(" %d\n", changeset.num_comments());
*m_out += " ";
output_int(changeset.num_comments());
*m_out += '\n';
int width = int(log10(changeset.num_comments())) + 1;
const int width = int(std::log10(changeset.num_comments())) + 1;
int n = 0;
for (const auto& comment : changeset.discussion()) {
write_counter(width, n++);
@@ -376,7 +482,8 @@ namespace osmium {
output_formatted(" %*s", width, "");
write_comment_field("user");
output_formatted("%d ", comment.uid());
output_int(comment.uid());
*m_out += ' ';
write_string(comment.user());
output_formatted("\n %*s", width, "");
@@ -386,6 +493,10 @@ namespace osmium {
}
}
if (m_options.add_crc32) {
write_crc32(changeset);
}
*m_out += '\n';
}
@@ -412,8 +523,10 @@ namespace osmium {
DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_color = file.is_true("color");
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_color = file.is_true("color");
m_options.add_crc32 = file.is_true("add_crc32");
m_options.format_as_diff = file.is_true("diff");
}
DebugOutputFormat(const DebugOutputFormat&) = delete;
@@ -422,6 +535,10 @@ namespace osmium {
~DebugOutputFormat() noexcept final = default;
void write_header(const osmium::io::Header& header) final {
if (m_options.format_as_diff) {
return;
}
std::string out;
if (m_options.use_color) {
@@ -439,9 +556,9 @@ namespace osmium {
out += '\n';
for (const auto& box : header.boxes()) {
out += " ";
box.bottom_left().as_string(std::back_inserter(out), ',');
out += " ";
box.top_right().as_string(std::back_inserter(out), ',');
box.bottom_left().as_string(std::back_inserter(out));
out += ' ';
box.top_right().as_string(std::back_inserter(out));
out += '\n';
}
write_fieldname(out, "options");
@@ -38,11 +38,11 @@ DEALINGS IN THE SOFTWARE.
#include <future>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
@@ -154,18 +154,14 @@ namespace osmium {
public:
typedef std::function<
std::unique_ptr<Parser>(
future_string_queue_type&,
future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities
)
> create_parser_type;
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities)>;
private:
typedef std::map<osmium::io::file_format, create_parser_type> map_type;
using map_type = std::map<osmium::io::file_format, create_parser_type>;
map_type m_callbacks;
@@ -42,9 +42,9 @@ DEALINGS IN THE SOFTWARE.
#include <string>
#include <utility>
#include <protozero/exception.hpp>
#include <protozero/varint.hpp>
#include <osmium/builder/builder.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
@@ -52,19 +52,26 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/delta.hpp>
namespace osmium {
namespace builder {
class Builder;
} // namespace builder
/**
* Exception thrown when the o5m deocder failed. The exception contains
* (if available) information about the place where the error happened
@@ -529,7 +536,7 @@ namespace osmium {
uint64_t length = 0;
try {
length = protozero::decode_varint(&m_data, m_end);
} catch (protozero::end_of_buffer_exception&) {
} catch (const protozero::end_of_buffer_exception&) {
throw o5m_error("premature end of file");
}
@@ -0,0 +1,156 @@
#ifndef OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
#define OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstdlib>
#include <future>
#include <memory>
#include <string>
#include <utility>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/thread/util.hpp>
namespace osmium {
namespace io {
namespace detail {
class OPLParser : public Parser {
osmium::memory::Buffer m_buffer{1024*1024};
const char* m_data = nullptr;
uint64_t m_line_count = 0;
void maybe_flush() {
if (m_buffer.committed() > 800*1024) {
osmium::memory::Buffer buffer{1024*1024};
using std::swap;
swap(m_buffer, buffer);
send_to_output_queue(std::move(buffer));
}
}
void parse_line() {
if (opl_parse_line(m_line_count, m_data, m_buffer, read_types())) {
maybe_flush();
}
++m_line_count;
}
public:
OPLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
Parser(input_queue, output_queue, header_promise, read_types) {
set_header_value(osmium::io::Header{});
}
~OPLParser() noexcept final = default;
void run() final {
osmium::thread::set_thread_name("_osmium_opl_in");
std::string rest;
while (!input_done()) {
std::string input = get_input();
std::string::size_type ppos = 0;
if (!rest.empty()) {
ppos = input.find('\n');
if (ppos == std::string::npos) {
rest.append(input);
continue;
}
rest.append(input.substr(0, ppos));
m_data = rest.data();
parse_line();
rest.clear();
}
std::string::size_type pos = input.find('\n', ppos);
while (pos != std::string::npos) {
m_data = &input[ppos];
input[pos] = '\0';
parse_line();
ppos = pos + 1;
if (ppos >= input.size()) {
break;
}
pos = input.find('\n', ppos);
}
rest = input.substr(ppos);
}
if (m_buffer.committed() > 0) {
send_to_output_queue(std::move(m_buffer));
}
}
}; // class OPLParser
// we want the register_parser() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_opl_parser = ParserFactory::instance().register_parser(
file_format::opl,
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
});
// dummy function to silence the unused variable warning from above
inline bool get_registered_opl_parser() noexcept {
return registered_opl_parser;
}
} // namespace detail
} // namespace io
} // namespace osmium
#endif // OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
@@ -33,26 +33,26 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <future>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_util.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
@@ -65,8 +65,6 @@ namespace osmium {
namespace io {
class File;
namespace detail {
struct opl_output_options {
@@ -74,6 +72,12 @@ namespace osmium {
/// Should metadata of objects be added?
bool add_metadata;
/// Should node locations be added to ways?
bool locations_on_ways;
/// Write in form of a diff file?
bool format_as_diff;
};
/**
@@ -87,38 +91,71 @@ namespace osmium {
osmium::io::detail::append_utf8_encoded_string(*m_out, data);
}
void write_meta(const osmium::OSMObject& object) {
output_formatted("%" PRId64, object.id());
if (m_options.add_metadata) {
output_formatted(" v%d d", object.version());
*m_out += (object.visible() ? 'V' : 'D');
output_formatted(" c%d t", object.changeset());
*m_out += object.timestamp().to_iso();
output_formatted(" i%d u", object.uid());
append_encoded_string(object.user());
}
void write_field_int(char c, int64_t value) {
*m_out += c;
output_int(value);
}
void write_field_timestamp(char c, const osmium::Timestamp& timestamp) {
*m_out += c;
*m_out += timestamp.to_iso();
}
void write_tags(const osmium::TagList& tags) {
*m_out += " T";
bool first = true;
for (const auto& tag : object.tags()) {
if (first) {
first = false;
} else {
*m_out += ',';
}
append_encoded_string(tag.key());
if (tags.empty()) {
return;
}
auto it = tags.begin();
append_encoded_string(it->key());
*m_out += '=';
append_encoded_string(it->value());
for (++it; it != tags.end(); ++it) {
*m_out += ',';
append_encoded_string(it->key());
*m_out += '=';
append_encoded_string(tag.value());
append_encoded_string(it->value());
}
}
void write_meta(const osmium::OSMObject& object) {
output_int(object.id());
if (m_options.add_metadata) {
*m_out += ' ';
write_field_int('v', object.version());
*m_out += " d";
*m_out += (object.visible() ? 'V' : 'D');
*m_out += ' ';
write_field_int('c', object.changeset());
*m_out += ' ';
write_field_timestamp('t', object.timestamp());
*m_out += ' ';
write_field_int('i', object.uid());
*m_out += " u";
append_encoded_string(object.user());
}
write_tags(object.tags());
}
void write_location(const osmium::Location& location, const char x, const char y) {
*m_out += ' ';
*m_out += x;
if (location) {
output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
} else {
*m_out += ' ';
*m_out += x;
*m_out += ' ';
*m_out += y;
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
}
*m_out += ' ';
*m_out += y;
if (location) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
}
}
void write_diff(const osmium::OSMObject& object) {
if (m_options.format_as_diff) {
*m_out += object.diff_as_char();
}
}
@@ -148,70 +185,93 @@ namespace osmium {
}
void node(const osmium::Node& node) {
write_diff(node);
*m_out += 'n';
write_meta(node);
write_location(node.location(), 'x', 'y');
*m_out += '\n';
}
void write_field_ref(const osmium::NodeRef& node_ref) {
write_field_int('n', node_ref.ref());
*m_out += 'x';
if (node_ref.location()) {
node_ref.location().as_string(std::back_inserter(*m_out), 'y');
} else {
*m_out += 'y';
}
}
void way(const osmium::Way& way) {
write_diff(way);
*m_out += 'w';
write_meta(way);
*m_out += " N";
bool first = true;
for (const auto& node_ref : way.nodes()) {
if (first) {
first = false;
if (!way.nodes().empty()) {
auto it = way.nodes().begin();
if (m_options.locations_on_ways) {
write_field_ref(*it);
for (++it; it != way.nodes().end(); ++it) {
*m_out += ',';
write_field_ref(*it);
}
} else {
*m_out += ',';
write_field_int('n', it->ref());
for (++it; it != way.nodes().end(); ++it) {
*m_out += ',';
write_field_int('n', it->ref());
}
}
output_formatted("n%" PRId64, node_ref.ref());
}
*m_out += '\n';
}
void relation_member(const osmium::RelationMember& member) {
*m_out += item_type_to_char(member.type());
output_int(member.ref());
*m_out += '@';
append_encoded_string(member.role());
}
void relation(const osmium::Relation& relation) {
write_diff(relation);
*m_out += 'r';
write_meta(relation);
*m_out += " M";
bool first = true;
for (const auto& member : relation.members()) {
if (first) {
first = false;
} else {
if (!relation.members().empty()) {
auto it = relation.members().begin();
relation_member(*it);
for (++it; it != relation.members().end(); ++it) {
*m_out += ',';
relation_member(*it);
}
*m_out += item_type_to_char(member.type());
output_formatted("%" PRId64 "@", member.ref());
append_encoded_string(member.role());
}
*m_out += '\n';
}
void changeset(const osmium::Changeset& changeset) {
output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
*m_out += changeset.created_at().to_iso();
*m_out += " e";
*m_out += changeset.closed_at().to_iso();
output_formatted(" d%d i%d u", changeset.num_comments(), changeset.uid());
write_field_int('c', changeset.id());
*m_out += ' ';
write_field_int('k', changeset.num_changes());
*m_out += ' ';
write_field_timestamp('s', changeset.created_at());
*m_out += ' ';
write_field_timestamp('e', changeset.closed_at());
*m_out += ' ';
write_field_int('d', changeset.num_comments());
*m_out += ' ';
write_field_int('i', changeset.uid());
*m_out += " u";
append_encoded_string(changeset.user());
write_location(changeset.bounds().bottom_left(), 'x', 'y');
write_location(changeset.bounds().top_right(), 'X', 'Y');
*m_out += " T";
bool first = true;
for (const auto& tag : changeset.tags()) {
if (first) {
first = false;
} else {
*m_out += ',';
}
append_encoded_string(tag.key());
*m_out += '=';
append_encoded_string(tag.value());
}
write_tags(changeset.tags());
*m_out += '\n';
}
@@ -226,7 +286,9 @@ namespace osmium {
OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.locations_on_ways = file.is_true("locations_on_ways");
m_options.format_as_diff = file.is_true("diff");
}
OPLOutputFormat(const OPLOutputFormat&) = delete;
@@ -0,0 +1,747 @@
#ifndef OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
#define OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <limits>
#include <stdexcept>
#include <string>
#include <utf8.h>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/error.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
namespace builder {
class Builder;
} // namespace builder
/**
* Exception thrown when there was a problem with parsing the OPL format
* of a file.
*/
struct opl_error : public io_error {
uint64_t line = 0;
uint64_t column = 0;
const char* data;
std::string msg;
explicit opl_error(const std::string& what, const char* d = nullptr) :
io_error(std::string("OPL error: ") + what),
data(d),
msg("OPL error: ") {
msg.append(what);
}
explicit opl_error(const char* what, const char* d = nullptr) :
io_error(std::string("OPL error: ") + what),
data(d),
msg("OPL error: ") {
msg.append(what);
}
void set_pos(uint64_t l, uint64_t col) {
line = l;
column = col;
msg.append(" on line ");
msg.append(std::to_string(line));
msg.append(" column ");
msg.append(std::to_string(column));
}
const char* what() const noexcept override {
return msg.c_str();
}
}; // struct opl_error
namespace io {
namespace detail {
/**
* Consume consecutive space and tab characters. There must be
* at least one.
*/
inline void opl_parse_space(const char** s) {
if (**s != ' ' && **s != '\t') {
throw opl_error{"expected space or tab character", *s};
}
do {
++*s;
} while (**s == ' ' || **s == '\t');
}
/**
* Check whether s points to something else than the end of the
* string or a space or tab.
*/
inline bool opl_non_empty(const char *s) {
return *s != '\0' && *s != ' ' && *s != '\t';
}
/**
* Skip to the next space or tab character or the end of the
* string.
*/
inline const char* opl_skip_section(const char** s) noexcept {
while (opl_non_empty(*s)) {
++*s;
}
return *s;
}
/**
* Parse OPL-escaped strings with hex code with a '%' at the end.
* Appends resulting unicode character to the result string.
*
* Returns a pointer to next character that needs to be consumed.
*/
inline void opl_parse_escaped(const char** data, std::string& result) {
const char* s = *data;
uint32_t value = 0;
const int max_length = sizeof(value) * 2 /* hex chars per byte */;
int length = 0;
while (++length <= max_length) {
if (*s == '\0') {
throw opl_error{"eol", s};
}
if (*s == '%') {
++s;
utf8::utf32to8(&value, &value + 1, std::back_inserter(result));
*data = s;
return;
}
value <<= 4;
if (*s >= '0' && *s <= '9') {
value += *s - '0';
} else if (*s >= 'a' && *s <= 'f') {
value += *s - 'a' + 10;
} else if (*s >= 'A' && *s <= 'F') {
value += *s - 'A' + 10;
} else {
throw opl_error{"not a hex char", s};
}
++s;
}
throw opl_error{"hex escape too long", s};
}
/**
* Parse a string up to end of string or next space, tab, comma, or
* equal sign.
*
* Appends characters to the result string.
*
* Returns a pointer to next character that needs to be consumed.
*/
inline void opl_parse_string(const char** data, std::string& result) {
const char* s = *data;
while (true) {
if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == '=') {
break;
} else if (*s == '%') {
++s;
opl_parse_escaped(&s, result);
} else {
result += *s;
++s;
}
}
*data = s;
}
// Arbitrary limit how long integers can get
constexpr const int max_int_len = 16;
template <typename T>
inline T opl_parse_int(const char** s) {
if (**s == '\0') {
throw opl_error{"expected integer", *s};
}
const bool negative = (**s == '-');
if (negative) {
++*s;
}
int64_t value = 0;
int n = max_int_len;
while (**s >= '0' && **s <= '9') {
if (--n == 0) {
throw opl_error{"integer too long", *s};
}
value *= 10;
value += **s - '0';
++*s;
}
if (n == max_int_len) {
throw opl_error{"expected integer", *s};
}
if (negative) {
value = -value;
if (value < std::numeric_limits<T>::min()) {
throw opl_error{"integer too long", *s};
}
} else {
if (value > std::numeric_limits<T>::max()) {
throw opl_error{"integer too long", *s};
}
}
return T(value);
}
inline osmium::object_id_type opl_parse_id(const char** s) {
return opl_parse_int<osmium::object_id_type>(s);
}
inline osmium::changeset_id_type opl_parse_changeset_id(const char** s) {
return opl_parse_int<osmium::changeset_id_type>(s);
}
inline osmium::object_version_type opl_parse_version(const char** s) {
return opl_parse_int<osmium::object_version_type>(s);
}
inline bool opl_parse_visible(const char** data) {
if (**data == 'V') {
++*data;
return true;
}
if (**data == 'D') {
++*data;
return false;
}
throw opl_error{"invalid visible flag", *data};
}
inline osmium::user_id_type opl_parse_uid(const char** s) {
return opl_parse_int<osmium::user_id_type>(s);
}
inline osmium::Timestamp opl_parse_timestamp(const char** s) {
try {
if (**s == '\0' || **s == ' ' || **s == '\t') {
return osmium::Timestamp{};
}
osmium::Timestamp timestamp{*s};
*s += 20;
return timestamp;
} catch (const std::invalid_argument&) {
throw opl_error{"can not parse timestamp", *s};
}
}
/**
* Check if data points to given character and consume it.
* Throw error otherwise.
*/
inline void opl_parse_char(const char** data, char c) {
if (**data == c) {
++*data;
return;
}
std::string msg = "expected '";
msg += c;
msg += "'";
throw opl_error{msg, *data};
}
/**
* Parse a list of tags in the format 'key=value,key=value,...'
*
* Tags will be added to the buffer using a TagListBuilder.
*/
inline void opl_parse_tags(const char* s, osmium::memory::Buffer& buffer, osmium::builder::Builder* parent_builder = nullptr) {
osmium::builder::TagListBuilder builder{buffer, parent_builder};
std::string key;
std::string value;
while (true) {
opl_parse_string(&s, key);
opl_parse_char(&s, '=');
opl_parse_string(&s, value);
builder.add_tag(key, value);
if (*s == ' ' || *s == '\t' || *s == '\0') {
break;
}
opl_parse_char(&s, ',');
key.clear();
value.clear();
}
}
/**
* Parse a number of nodes in the format "nID,nID,nID..."
*
* Nodes will be added to the buffer using a WayNodeListBuilder.
*/
inline void opl_parse_way_nodes(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::WayBuilder* parent_builder = nullptr) {
if (s == e) {
return;
}
osmium::builder::WayNodeListBuilder builder{buffer, parent_builder};
while (s < e) {
opl_parse_char(&s, 'n');
if (s == e) {
throw opl_error{"expected integer", s};
}
const osmium::object_id_type ref = opl_parse_id(&s);
if (s == e) {
builder.add_node_ref(ref);
return;
}
osmium::Location location;
if (*s == 'x') {
++s;
location.set_lon_partial(&s);
if (*s == 'y') {
++s;
location.set_lat_partial(&s);
}
}
builder.add_node_ref(ref, location);
if (s == e) {
return;
}
opl_parse_char(&s, ',');
}
}
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::NodeBuilder builder{buffer};
osmium::Node& node = builder.object();
node.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
std::string user;
osmium::Location location;
while (**data) {
opl_parse_space(data);
const char c = **data;
if (c == '\0') {
break;
}
++(*data);
switch (c) {
case 'v':
node.set_version(opl_parse_version(data));
break;
case 'd':
node.set_visible(opl_parse_visible(data));
break;
case 'c':
node.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
node.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
node.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
break;
case 'T':
if (opl_non_empty(*data)) {
tags_begin = *data;
opl_skip_section(data);
}
break;
case 'x':
if (opl_non_empty(*data)) {
location.set_lon_partial(data);
}
break;
case 'y':
if (opl_non_empty(*data)) {
location.set_lat_partial(data);
}
break;
default:
--(*data);
throw opl_error{"unknown attribute", *data};
}
}
if (location.valid()) {
node.set_location(location);
}
builder.add_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
buffer.commit();
}
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::WayBuilder builder{buffer};
osmium::Way& way = builder.object();
way.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
const char* nodes_begin = nullptr;
const char* nodes_end = nullptr;
std::string user;
while (**data) {
opl_parse_space(data);
const char c = **data;
if (c == '\0') {
break;
}
++(*data);
switch (c) {
case 'v':
way.set_version(opl_parse_version(data));
break;
case 'd':
way.set_visible(opl_parse_visible(data));
break;
case 'c':
way.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
way.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
way.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
break;
case 'T':
if (opl_non_empty(*data)) {
tags_begin = *data;
opl_skip_section(data);
}
break;
case 'N':
nodes_begin = *data;
nodes_end = opl_skip_section(data);
break;
default:
--(*data);
throw opl_error{"unknown attribute", *data};
}
}
builder.add_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
buffer.commit();
}
inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
if (s == e) {
return;
}
osmium::builder::RelationMemberListBuilder builder{buffer, parent_builder};
while (s < e) {
osmium::item_type type = osmium::char_to_item_type(*s);
if (type != osmium::item_type::node &&
type != osmium::item_type::way &&
type != osmium::item_type::relation) {
throw opl_error{"unknown object type", s};
}
++s;
if (s == e) {
throw opl_error{"expected integer", s};
}
osmium::object_id_type ref = opl_parse_id(&s);
opl_parse_char(&s, '@');
if (s == e) {
builder.add_member(type, ref, "");
return;
}
std::string role;
opl_parse_string(&s, role);
builder.add_member(type, ref, role);
if (s == e) {
return;
}
opl_parse_char(&s, ',');
}
}
inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::RelationBuilder builder{buffer};
osmium::Relation& relation = builder.object();
relation.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
const char* members_begin = nullptr;
const char* members_end = nullptr;
std::string user;
while (**data) {
opl_parse_space(data);
const char c = **data;
if (c == '\0') {
break;
}
++(*data);
switch (c) {
case 'v':
relation.set_version(opl_parse_version(data));
break;
case 'd':
relation.set_visible(opl_parse_visible(data));
break;
case 'c':
relation.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
relation.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
relation.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
break;
case 'T':
if (opl_non_empty(*data)) {
tags_begin = *data;
opl_skip_section(data);
}
break;
case 'M':
members_begin = *data;
members_end = opl_skip_section(data);
break;
default:
--(*data);
throw opl_error{"unknown attribute", *data};
}
}
builder.add_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
if (members_begin != members_end) {
opl_parse_relation_members(members_begin, members_end, buffer, &builder);
}
buffer.commit();
}
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::ChangesetBuilder builder{buffer};
osmium::Changeset& changeset = builder.object();
changeset.set_id(opl_parse_changeset_id(data));
const char* tags_begin = nullptr;
osmium::Location location1;
osmium::Location location2;
std::string user;
while (**data) {
opl_parse_space(data);
const char c = **data;
if (c == '\0') {
break;
}
++(*data);
switch (c) {
case 'k':
changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
break;
case 's':
changeset.set_created_at(opl_parse_timestamp(data));
break;
case 'e':
changeset.set_closed_at(opl_parse_timestamp(data));
break;
case 'd':
changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
break;
case 'i':
changeset.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
break;
case 'x':
if (opl_non_empty(*data)) {
location1.set_lon_partial(data);
}
break;
case 'y':
if (opl_non_empty(*data)) {
location1.set_lat_partial(data);
}
break;
case 'X':
if (opl_non_empty(*data)) {
location2.set_lon_partial(data);
}
break;
case 'Y':
if (opl_non_empty(*data)) {
location2.set_lat_partial(data);
}
break;
case 'T':
if (opl_non_empty(*data)) {
tags_begin = *data;
opl_skip_section(data);
}
break;
default:
--(*data);
throw opl_error{"unknown attribute", *data};
}
}
if (location1.valid() && location2.valid()) {
changeset.bounds().extend(location1);
changeset.bounds().extend(location2);
}
builder.add_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
buffer.commit();
}
inline bool opl_parse_line(uint64_t line_count,
const char* data,
osmium::memory::Buffer& buffer,
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) {
const char* start_of_line = data;
try {
switch (*data) {
case '\0':
// ignore empty lines
break;
case '#':
// ignore lines starting with #
break;
case 'n':
if (read_types & osmium::osm_entity_bits::node) {
++data;
opl_parse_node(&data, buffer);
return true;
}
break;
case 'w':
if (read_types & osmium::osm_entity_bits::way) {
++data;
opl_parse_way(&data, buffer);
return true;
}
break;
case 'r':
if (read_types & osmium::osm_entity_bits::relation) {
++data;
opl_parse_relation(&data, buffer);
return true;
}
break;
case 'c':
if (read_types & osmium::osm_entity_bits::changeset) {
++data;
opl_parse_changeset(&data, buffer);
return true;
}
break;
default:
throw opl_error{"unknown type", data};
}
} catch (opl_error& e) {
e.set_pos(line_count, e.data ? e.data - start_of_line : 0);
throw;
}
return false;
}
} // namespace detail
} // namespace io
} // namespace osmium
#endif // OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
@@ -33,16 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <osmium/handler.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_util.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
@@ -70,9 +70,28 @@ namespace osmium {
m_out(std::make_shared<std::string>()) {
}
template <typename... TArgs>
void output_formatted(const char* format, TArgs&&... args) {
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
// Simple function to convert integer to string. This is much
// faster than using sprintf, but could be further optimized.
// See https://github.com/miloyip/itoa-benchmark .
void output_int(int64_t value) {
if (value < 0) {
*m_out += '-';
value = -value;
}
char temp[20];
char *t = temp;
do {
*t++ = char(value % 10) + '0';
value /= 10;
} while (value > 0);
const auto old_size = m_out->size();
m_out->resize(old_size + (t - temp));
char* data = &(*m_out)[old_size];
do {
*data++ += *--t;
} while (t != temp);
}
}; // class OutputBlock;
@@ -133,11 +152,11 @@ namespace osmium {
public:
typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)> create_output_type;
using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>;
private:
typedef std::map<osmium::io::file_format, create_output_type> map_type;
using map_type = std::map<osmium::io::file_format, create_output_type>;
map_type m_callbacks;
+1 -1
View File
@@ -78,7 +78,7 @@ namespace osmium {
// between representation as double and as int
const int64_t lonlat_resolution = 1000 * 1000 * 1000;
const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision;
const int64_t resolution_convert = lonlat_resolution / osmium::detail::coordinate_precision;
} // namespace detail
+141 -96
View File
@@ -33,10 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -44,35 +42,47 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <vector>
#include <protozero/iterators.hpp>
#include <protozero/pbf_message.hpp>
#include <protozero/types.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/zlib.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/delta.hpp>
namespace osmium {
namespace builder {
class Builder;
} // namespace builder
namespace io {
namespace detail {
using ptr_len_type = std::pair<const char*, size_t>;
using protozero::data_view;
using osm_string_len_type = std::pair<const char*, osmium::string_size_type>;
class PBFPrimitiveBlockDecoder {
static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
static constexpr const size_t initial_buffer_size = 2 * 1024 * 1024;
ptr_len_type m_data;
data_view m_data;
std::vector<osm_string_len_type> m_stringtable;
int64_t m_lon_offset = 0;
@@ -84,18 +94,18 @@ namespace osmium {
osmium::memory::Buffer m_buffer { initial_buffer_size };
void decode_stringtable(const ptr_len_type& data) {
void decode_stringtable(const data_view& data) {
if (!m_stringtable.empty()) {
throw osmium::pbf_error("more than one stringtable in pbf file");
}
protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
auto str_len = pbf_string_table.get_data();
if (str_len.second > osmium::max_osm_string_length) {
const auto str_view = pbf_string_table.get_view();
if (str_view.size() > osmium::max_osm_string_length) {
throw osmium::pbf_error("overlong string in string table");
}
m_stringtable.emplace_back(str_len.first, osmium::string_size_type(str_len.second));
m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size()));
}
}
@@ -104,7 +114,7 @@ namespace osmium {
while (pbf_primitive_block.next()) {
switch (pbf_primitive_block.tag()) {
case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
decode_stringtable(pbf_primitive_block.get_data());
decode_stringtable(pbf_primitive_block.get_view());
break;
case OSMFormat::PrimitiveBlock::optional_int32_granularity:
m_granularity = pbf_primitive_block.get_int32();
@@ -132,28 +142,28 @@ namespace osmium {
switch (pbf_primitive_group.tag()) {
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
if (m_read_types & osmium::osm_entity_bits::node) {
decode_node(pbf_primitive_group.get_data());
decode_node(pbf_primitive_group.get_view());
} else {
pbf_primitive_group.skip();
}
break;
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
if (m_read_types & osmium::osm_entity_bits::node) {
decode_dense_nodes(pbf_primitive_group.get_data());
decode_dense_nodes(pbf_primitive_group.get_view());
} else {
pbf_primitive_group.skip();
}
break;
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
if (m_read_types & osmium::osm_entity_bits::way) {
decode_way(pbf_primitive_group.get_data());
decode_way(pbf_primitive_group.get_view());
} else {
pbf_primitive_group.skip();
}
break;
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
if (m_read_types & osmium::osm_entity_bits::relation) {
decode_relation(pbf_primitive_group.get_data());
decode_relation(pbf_primitive_group.get_view());
} else {
pbf_primitive_group.skip();
}
@@ -165,7 +175,7 @@ namespace osmium {
}
}
osm_string_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) {
osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) {
osm_string_len_type user = std::make_pair("", 0);
protozero::pbf_message<OSMFormat::Info> pbf_info(data);
@@ -173,7 +183,7 @@ namespace osmium {
switch (pbf_info.tag()) {
case OSMFormat::Info::optional_int32_version:
{
auto version = pbf_info.get_int32();
const auto version = pbf_info.get_int32();
if (version < 0) {
throw osmium::pbf_error("object version must not be negative");
}
@@ -185,7 +195,7 @@ namespace osmium {
break;
case OSMFormat::Info::optional_int64_changeset:
{
auto changeset_id = pbf_info.get_int64();
const auto changeset_id = pbf_info.get_int64();
if (changeset_id < 0) {
throw osmium::pbf_error("object changeset_id must not be negative");
}
@@ -209,15 +219,15 @@ namespace osmium {
return user;
}
using kv_type = std::pair<protozero::pbf_reader::const_uint32_iterator, protozero::pbf_reader::const_uint32_iterator>;
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
if (keys.first != keys.second) {
if (!keys.empty()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
auto kit = keys.first;
auto vit = vals.first;
while (kit != keys.second) {
if (vit == vals.second) {
auto kit = keys.begin();
auto vit = vals.begin();
while (kit != keys.end()) {
if (vit == vals.end()) {
// this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error");
}
@@ -232,7 +242,7 @@ namespace osmium {
return int32_t((c * m_granularity + m_lon_offset) / resolution_convert);
}
void decode_node(const ptr_len_type& data) {
void decode_node(const data_view& data) {
osmium::builder::NodeBuilder builder(m_buffer);
osmium::Node& node = builder.object();
@@ -256,7 +266,7 @@ namespace osmium {
vals = pbf_node.get_packed_uint32();
break;
case OSMFormat::Node::optional_Info_info:
user = decode_info(pbf_node.get_data(), builder.object());
user = decode_info(pbf_node.get_view(), builder.object());
break;
case OSMFormat::Node::required_sint64_lat:
lat = pbf_node.get_sint64();
@@ -287,12 +297,14 @@ namespace osmium {
m_buffer.commit();
}
void decode_way(const ptr_len_type& data) {
void decode_way(const data_view& data) {
osmium::builder::WayBuilder builder(m_buffer);
kv_type keys;
kv_type vals;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
osm_string_len_type user = { "", 0 };
@@ -309,11 +321,17 @@ namespace osmium {
vals = pbf_way.get_packed_uint32();
break;
case OSMFormat::Way::optional_Info_info:
user = decode_info(pbf_way.get_data(), builder.object());
user = decode_info(pbf_way.get_view(), builder.object());
break;
case OSMFormat::Way::packed_sint64_refs:
refs = pbf_way.get_packed_sint64();
break;
case OSMFormat::Way::packed_sint64_lat:
lats = pbf_way.get_packed_sint64();
break;
case OSMFormat::Way::packed_sint64_lon:
lons = pbf_way.get_packed_sint64();
break;
default:
pbf_way.skip();
}
@@ -321,11 +339,26 @@ namespace osmium {
builder.add_user(user.first, user.second);
if (refs.first != refs.second) {
if (!refs.empty()) {
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
osmium::util::DeltaDecode<int64_t> ref;
while (refs.first != refs.second) {
wnl_builder.add_node_ref(ref.update(*refs.first++));
if (lats.empty()) {
for (const auto& ref_value : refs) {
wnl_builder.add_node_ref(ref.update(ref_value));
}
} else {
osmium::util::DeltaDecode<int64_t> lon;
osmium::util::DeltaDecode<int64_t> lat;
while (!refs.empty() && !lons.empty() && !lats.empty()) {
wnl_builder.add_node_ref(
ref.update(refs.front()),
osmium::Location{convert_pbf_coordinate(lon.update(lons.front())),
convert_pbf_coordinate(lat.update(lats.front()))}
);
refs.drop_front();
lons.drop_front();
lats.drop_front();
}
}
}
@@ -334,14 +367,14 @@ namespace osmium {
m_buffer.commit();
}
void decode_relation(const ptr_len_type& data) {
void decode_relation(const data_view& data) {
osmium::builder::RelationBuilder builder(m_buffer);
kv_type keys;
kv_type vals;
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> roles;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> types;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> roles;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types;
osm_string_len_type user = { "", 0 };
@@ -358,7 +391,7 @@ namespace osmium {
vals = pbf_relation.get_packed_uint32();
break;
case OSMFormat::Relation::optional_Info_info:
user = decode_info(pbf_relation.get_data(), builder.object());
user = decode_info(pbf_relation.get_view(), builder.object());
break;
case OSMFormat::Relation::packed_int32_roles_sid:
roles = pbf_relation.get_packed_int32();
@@ -376,21 +409,24 @@ namespace osmium {
builder.add_user(user.first, user.second);
if (refs.first != refs.second) {
if (!refs.empty()) {
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
osmium::util::DeltaDecode<int64_t> ref;
while (roles.first != roles.second && refs.first != refs.second && types.first != types.second) {
const auto& r = m_stringtable.at(*roles.first++);
int type = *types.first++;
while (!roles.empty() && !refs.empty() && !types.empty()) {
const auto& r = m_stringtable.at(roles.front());
const int type = types.front();
if (type < 0 || type > 2) {
throw osmium::pbf_error("unknown relation member type");
}
rml_builder.add_member(
osmium::item_type(type + 1),
ref.update(*refs.first++),
ref.update(refs.front()),
r.first,
r.second
);
roles.drop_front();
refs.drop_front();
types.drop_front();
}
}
@@ -399,22 +435,22 @@ namespace osmium {
m_buffer.commit();
}
void decode_dense_nodes(const ptr_len_type& data) {
void decode_dense_nodes(const data_view& data) {
bool has_info = false;
bool has_visibles = false;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> ids;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lats;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lons;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> ids;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> tags;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> versions;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> timestamps;
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> changesets;
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> uids;
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> user_sids;
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> visibles;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> versions;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> timestamps;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> changesets;
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> uids;
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles;
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
while (pbf_dense_nodes.next()) {
@@ -475,11 +511,11 @@ namespace osmium {
osmium::util::DeltaDecode<int64_t> dense_changeset;
osmium::util::DeltaDecode<int64_t> dense_timestamp;
auto tag_it = tags.first;
auto tag_it = tags.begin();
while (ids.first != ids.second) {
if (lons.first == lons.second ||
lats.first == lats.second) {
while (!ids.empty()) {
if (lons.empty() ||
lats.empty()) {
// this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error");
}
@@ -489,43 +525,50 @@ namespace osmium {
osmium::builder::NodeBuilder builder(m_buffer);
osmium::Node& node = builder.object();
node.set_id(dense_id.update(*ids.first++));
node.set_id(dense_id.update(ids.front()));
ids.drop_front();
if (has_info) {
if (versions.first == versions.second ||
changesets.first == changesets.second ||
timestamps.first == timestamps.second ||
uids.first == uids.second ||
user_sids.first == user_sids.second) {
if (versions.empty() ||
changesets.empty() ||
timestamps.empty() ||
uids.empty() ||
user_sids.empty()) {
// this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error");
}
auto version = *versions.first++;
const auto version = versions.front();
versions.drop_front();
if (version < 0) {
throw osmium::pbf_error("object version must not be negative");
}
node.set_version(static_cast<osmium::object_version_type>(version));
auto changeset_id = dense_changeset.update(*changesets.first++);
const auto changeset_id = dense_changeset.update(changesets.front());
changesets.drop_front();
if (changeset_id < 0) {
throw osmium::pbf_error("object changeset_id must not be negative");
}
node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
node.set_timestamp(dense_timestamp.update(*timestamps.first++) * m_date_factor / 1000);
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(*uids.first++)));
node.set_timestamp(dense_timestamp.update(timestamps.front()) * m_date_factor / 1000);
timestamps.drop_front();
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(uids.front())));
uids.drop_front();
if (has_visibles) {
if (visibles.first == visibles.second) {
if (visibles.empty()) {
// this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error");
}
visible = (*visibles.first++) != 0;
visible = (visibles.front() != 0);
visibles.drop_front();
}
node.set_visible(visible);
const auto& u = m_stringtable.at(dense_user_sid.update(*user_sids.first++));
const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
user_sids.drop_front();
builder.add_user(u.first, u.second);
} else {
builder.add_user("");
@@ -533,8 +576,10 @@ namespace osmium {
// even if the node isn't visible, there's still a record
// of its lat/lon in the dense arrays.
const auto lon = dense_longitude.update(*lons.first++);
const auto lat = dense_latitude.update(*lats.first++);
const auto lon = dense_longitude.update(lons.front());
lons.drop_front();
const auto lat = dense_latitude.update(lats.front());
lats.drop_front();
if (visible) {
builder.object().set_location(osmium::Location(
convert_pbf_coordinate(lon),
@@ -542,18 +587,18 @@ namespace osmium {
));
}
if (tag_it != tags.second) {
if (tag_it != tags.end()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
while (tag_it != tags.second && *tag_it != 0) {
while (tag_it != tags.end() && *tag_it != 0) {
const auto& k = m_stringtable.at(*tag_it++);
if (tag_it == tags.second) {
if (tag_it == tags.end()) {
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
}
const auto& v = m_stringtable.at(*tag_it++);
tl_builder.add_tag(k.first, k.second, v.first, v.second);
}
if (tag_it != tags.second) {
if (tag_it != tags.end()) {
++tag_it;
}
}
@@ -565,7 +610,7 @@ namespace osmium {
public:
PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) :
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
m_data(data),
m_read_types(read_types) {
}
@@ -582,7 +627,7 @@ namespace osmium {
try {
decode_primitive_block_metadata();
decode_primitive_block_data();
} catch (std::out_of_range&) {
} catch (const std::out_of_range&) {
throw osmium::pbf_error("string id out of range");
}
@@ -591,17 +636,17 @@ namespace osmium {
}; // class PBFPrimitiveBlockDecoder
inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) {
inline data_view decode_blob(const std::string& blob_data, std::string& output) {
int32_t raw_size = 0;
std::pair<const char*, protozero::pbf_length_type> zlib_data = {nullptr, 0};
protozero::data_view zlib_data;
protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data);
while (pbf_blob.next()) {
switch (pbf_blob.tag()) {
case FileFormat::Blob::optional_bytes_raw:
{
auto data_len = pbf_blob.get_data();
if (data_len.second > max_uncompressed_blob_size) {
auto data_len = pbf_blob.get_view();
if (data_len.size() > max_uncompressed_blob_size) {
throw osmium::pbf_error("illegal blob size");
}
return data_len;
@@ -613,7 +658,7 @@ namespace osmium {
}
break;
case FileFormat::Blob::optional_bytes_zlib_data:
zlib_data = pbf_blob.get_data();
zlib_data = pbf_blob.get_view();
break;
case FileFormat::Blob::optional_bytes_lzma_data:
throw osmium::pbf_error("lzma blobs not implemented");
@@ -622,10 +667,10 @@ namespace osmium {
}
}
if (zlib_data.second != 0 && raw_size != 0) {
if (zlib_data.size() != 0 && raw_size != 0) {
return osmium::io::detail::zlib_uncompress_string(
zlib_data.first,
static_cast<unsigned long>(zlib_data.second),
zlib_data.data(),
static_cast<unsigned long>(zlib_data.size()),
static_cast<unsigned long>(raw_size),
output
);
@@ -634,7 +679,7 @@ namespace osmium {
throw osmium::pbf_error("blob contains no data");
}
inline osmium::Box decode_header_bbox(const ptr_len_type& data) {
inline osmium::Box decode_header_bbox(const data_view& data) {
int64_t left = std::numeric_limits<int64_t>::max();
int64_t right = std::numeric_limits<int64_t>::max();
int64_t top = std::numeric_limits<int64_t>::max();
@@ -674,7 +719,7 @@ namespace osmium {
return box;
}
inline osmium::io::Header decode_header_block(const ptr_len_type& data) {
inline osmium::io::Header decode_header_block(const data_view& data) {
osmium::io::Header header;
int i = 0;
@@ -682,20 +727,20 @@ namespace osmium {
while (pbf_header_block.next()) {
switch (pbf_header_block.tag()) {
case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
header.add_box(decode_header_bbox(pbf_header_block.get_data()));
header.add_box(decode_header_bbox(pbf_header_block.get_view()));
break;
case OSMFormat::HeaderBlock::repeated_string_required_features:
{
auto feature = pbf_header_block.get_data();
if (!strncmp("OsmSchema-V0.6", feature.first, feature.second)) {
auto feature = pbf_header_block.get_view();
if (!std::strncmp("OsmSchema-V0.6", feature.data(), feature.size())) {
// intentionally left blank
} else if (!strncmp("DenseNodes", feature.first, feature.second)) {
} else if (!std::strncmp("DenseNodes", feature.data(), feature.size())) {
header.set("pbf_dense_nodes", true);
} else if (!strncmp("HistoricalInformation", feature.first, feature.second)) {
} else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) {
header.set_has_multiple_object_versions(true);
} else {
std::string msg("required feature not supported: ");
msg.append(feature.first, feature.second);
msg.append(feature.data(), feature.size());
throw osmium::pbf_error(msg);
}
}
@@ -708,7 +753,7 @@ namespace osmium {
break;
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
{
auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
const auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
header.set("osmosis_replication_timestamp", timestamp);
header.set("timestamp", timestamp);
}
@@ -38,25 +38,22 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <future>
#include <memory>
#include <sstream>
#include <string>
#include <thread>
#include <type_traits>
#include <protozero/pbf_message.hpp>
#include <protozero/types.hpp>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/pbf_decoder.hpp>
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/osm.hpp>
#include <osmium/io/header.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
@@ -80,7 +77,7 @@ namespace osmium {
*/
std::string read_from_input_queue(size_t size) {
while (m_input_buffer.size() < size) {
std::string new_data = get_input();
const std::string new_data = get_input();
if (input_done()) {
throw osmium::pbf_error("truncated data (EOF encountered)");
}
@@ -106,7 +103,7 @@ namespace osmium {
try {
const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
} catch (osmium::pbf_error&) {
} catch (const osmium::pbf_error&) {
return 0; // EOF
}
@@ -123,13 +120,13 @@ namespace osmium {
* type. Return the size of the following Blob.
*/
size_t decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>&& pbf_blob_header, const char* expected_type) {
std::pair<const char*, size_t> blob_header_type;
protozero::data_view blob_header_type;
size_t blob_header_datasize = 0;
while (pbf_blob_header.next()) {
switch (pbf_blob_header.tag()) {
case FileFormat::BlobHeader::required_string_type:
blob_header_type = pbf_blob_header.get_data();
blob_header_type = pbf_blob_header.get_view();
break;
case FileFormat::BlobHeader::required_int32_datasize:
blob_header_datasize = pbf_blob_header.get_int32();
@@ -143,7 +140,7 @@ namespace osmium {
throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
}
if (strncmp(expected_type, blob_header_type.first, blob_header_type.second)) {
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
}
@@ -41,30 +41,34 @@ DEALINGS IN THE SOFTWARE.
#include <iterator>
#include <memory>
#include <string>
#include <time.h>
#include <utility>
#include <protozero/pbf_builder.hpp>
#include <protozero/pbf_writer.hpp>
#include <protozero/types.hpp>
#include <osmium/handler.hpp>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_table.hpp>
#include <osmium/io/detail/zlib.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/util/cast.hpp>
@@ -101,6 +105,9 @@ namespace osmium {
/// Should the visible flag be added to all OSM objects?
bool add_visible_flag;
/// Should node locations be added to ways?
bool locations_on_ways;
};
/**
@@ -483,6 +490,7 @@ namespace osmium {
m_options.add_metadata = file.is_not_false("pbf_add_metadata") && file.is_not_false("add_metadata");
m_options.add_historical_information_flag = file.has_multiple_object_versions();
m_options.add_visible_flag = file.has_multiple_object_versions();
m_options.locations_on_ways = file.is_true("locations_on_ways");
}
PBFOutputFormat(const PBFOutputFormat&) = delete;
@@ -514,20 +522,24 @@ namespace osmium {
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation");
}
if (m_options.locations_on_ways) {
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_optional_features, "LocationsOnWays");
}
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
if (!osmosis_replication_timestamp.empty()) {
osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
}
std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
if (!osmosis_replication_sequence_number.empty()) {
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
}
std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
if (!osmosis_replication_base_url.empty()) {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
}
@@ -571,15 +583,30 @@ namespace osmium {
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
add_meta(way, pbf_way);
static auto map_node_ref = [](osmium::NodeRefList::const_iterator node_ref) noexcept -> osmium::object_id_type {
return node_ref->ref();
};
typedef osmium::util::DeltaEncodeIterator<osmium::NodeRefList::const_iterator, decltype(map_node_ref), osmium::object_id_type> it_type;
{
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_refs)};
for (const auto& node_ref : way.nodes()) {
field.add_element(delta_id.update(node_ref.ref()));
}
}
const auto& nodes = way.nodes();
it_type first { nodes.cbegin(), nodes.cend(), map_node_ref };
it_type last { nodes.cend(), nodes.cend(), map_node_ref };
pbf_way.add_packed_sint64(OSMFormat::Way::packed_sint64_refs, first, last);
if (m_options.locations_on_ways) {
{
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lon)};
for (const auto& node_ref : way.nodes()) {
field.add_element(delta_id.update(lonlat2int(node_ref.location().lon_without_check())));
}
}
{
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lat)};
for (const auto& node_ref : way.nodes()) {
field.add_element(delta_id.update(lonlat2int(node_ref.location().lat_without_check())));
}
}
}
}
void relation(const osmium::Relation& relation) {
@@ -596,14 +623,13 @@ namespace osmium {
}
}
static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type {
return member->ref();
};
typedef osmium::util::DeltaEncodeIterator<osmium::RelationMemberList::const_iterator, decltype(map_member_ref), osmium::object_id_type> it_type;
const auto& members = relation.members();
it_type first { members.cbegin(), members.cend(), map_member_ref };
it_type last { members.cend(), members.cend(), map_member_ref };
pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last);
{
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
protozero::packed_field_sint64 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_sint64_memids)};
for (const auto& member : relation.members()) {
field.add_element(delta_id.update(member.ref()));
}
}
{
protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_MemberType_types)};
@@ -146,7 +146,9 @@ namespace osmium {
packed_uint32_keys = 2,
packed_uint32_vals = 3,
optional_Info_info = 4,
packed_sint64_refs = 8
packed_sint64_refs = 8,
packed_sint64_lat = 9,
packed_sint64_lon = 10
};
enum class Relation : protozero::pbf_tag_type {
@@ -47,6 +47,9 @@ namespace osmium {
namespace detail {
template <typename T>
using future_queue_type = osmium::thread::Queue<std::future<T>>;
/**
* This type of queue contains buffers with OSM data in them.
* The "end of file" is marked by an invalid Buffer.
@@ -54,7 +57,7 @@ namespace osmium {
* transport exceptions. The future also helps with keeping the
* data in order.
*/
using future_buffer_queue_type = osmium::thread::Queue<std::future<osmium::memory::Buffer>>;
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
/**
* This type of queue contains OSM file data in the form it is
@@ -71,24 +74,24 @@ namespace osmium {
* transport exceptions. The future also helps with keeping the
* data in order.
*/
using future_string_queue_type = osmium::thread::Queue<std::future<std::string>>;
using future_string_queue_type = future_queue_type<std::string>;
template <typename T>
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, T&& data) {
inline void add_to_queue(future_queue_type<T>& queue, T&& data) {
std::promise<T> promise;
queue.push(promise.get_future());
promise.set_value(std::forward<T>(data));
}
template <typename T>
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, std::exception_ptr&& exception) {
inline void add_to_queue(future_queue_type<T>& queue, std::exception_ptr&& exception) {
std::promise<T> promise;
queue.push(promise.get_future());
promise.set_exception(std::move(exception));
}
template <typename T>
inline void add_end_of_data_to_queue(osmium::thread::Queue<std::future<T>>& queue) {
inline void add_end_of_data_to_queue(future_queue_type<T>& queue) {
add_to_queue<T>(queue, T{});
}
@@ -103,14 +106,12 @@ namespace osmium {
template <typename T>
class queue_wrapper {
using queue_type = osmium::thread::Queue<std::future<T>>;
queue_type& m_queue;
future_queue_type<T>& m_queue;
bool m_has_reached_end_of_data;
public:
explicit queue_wrapper(queue_type& queue) :
explicit queue_wrapper(future_queue_type<T>& queue) :
m_queue(queue),
m_has_reached_end_of_data(false) {
}
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cerrno>
#include <cstddef>
#include <errno.h>
#include <fcntl.h>
#include <string>
#include <system_error>
@@ -84,7 +83,7 @@ namespace osmium {
#ifdef _WIN32
flags |= O_BINARY;
#endif
int fd = ::open(filename.c_str(), flags, 0666);
const int fd = ::open(filename.c_str(), flags, 0666);
if (fd < 0) {
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
}
@@ -108,7 +107,7 @@ namespace osmium {
#ifdef _WIN32
flags |= O_BINARY;
#endif
int fd = ::open(filename.c_str(), flags);
const int fd = ::open(filename.c_str(), flags);
if (fd < 0) {
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
}
@@ -133,7 +132,7 @@ namespace osmium {
if (write_count > max_write) {
write_count = max_write;
}
auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
if (length < 0) {
throw std::system_error(errno, std::system_category(), "Write failed");
}
@@ -34,13 +34,14 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <list>
#include <map>
#include <string>
#include <unordered_map>
#include <utility>
#include <osmium/io/detail/pbf.hpp>
@@ -69,8 +70,8 @@ namespace osmium {
std::list<std::string> m_chunks;
void add_chunk() {
m_chunks.push_front(std::string());
m_chunks.front().reserve(m_chunk_size);
m_chunks.emplace_back();
m_chunks.back().reserve(m_chunk_size);
}
public:
@@ -82,6 +83,7 @@ namespace osmium {
}
void clear() noexcept {
assert(!m_chunks.empty());
m_chunks.erase(std::next(m_chunks.begin()), m_chunks.end());
m_chunks.front().clear();
}
@@ -93,31 +95,38 @@ namespace osmium {
* allocated.
*/
const char* add(const char* string) {
size_t len = std::strlen(string) + 1;
const size_t len = std::strlen(string) + 1;
assert(len <= m_chunk_size);
size_t chunk_len = m_chunks.front().size();
if (chunk_len + len > m_chunks.front().capacity()) {
size_t chunk_len = m_chunks.back().size();
if (chunk_len + len > m_chunks.back().capacity()) {
add_chunk();
chunk_len = 0;
}
m_chunks.front().append(string);
m_chunks.front().append(1, '\0');
m_chunks.back().append(string);
m_chunks.back().append(1, '\0');
return m_chunks.front().c_str() + chunk_len;
return m_chunks.back().c_str() + chunk_len;
}
class const_iterator : public std::iterator<std::forward_iterator_tag, const char*> {
class const_iterator {
using it_type = std::list<std::string>::const_iterator;
typedef std::list<std::string>::const_iterator it_type;
it_type m_it;
const it_type m_last;
const char* m_pos;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = const char*;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
const_iterator(it_type it, it_type last) :
m_it(it),
m_last(last),
@@ -126,7 +135,7 @@ namespace osmium {
const_iterator& operator++() {
assert(m_it != m_last);
auto last_pos = m_it->c_str() + m_it->size();
const auto last_pos = m_it->c_str() + m_it->size();
while (m_pos != last_pos && *m_pos) ++m_pos;
if (m_pos != last_pos) ++m_pos;
if (m_pos == last_pos) {
@@ -184,18 +193,33 @@ namespace osmium {
}
size_t get_used_bytes_in_last_chunk() const noexcept {
return m_chunks.front().size();
return m_chunks.back().size();
}
}; // class StringStore
struct StrComp {
struct str_equal {
bool operator()(const char* lhs, const char* rhs) const {
return strcmp(lhs, rhs) < 0;
bool operator()(const char* lhs, const char* rhs) const noexcept {
return lhs == rhs || std::strcmp(lhs, rhs) == 0;
}
}; // struct StrComp
}; // struct str_equal
struct djb2_hash {
size_t operator()(const char* str) const noexcept {
size_t hash = 5381;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
}; // struct djb2_hash
class StringTable {
@@ -206,14 +230,23 @@ namespace osmium {
// Blob.
static constexpr const uint32_t max_entries = max_uncompressed_blob_size;
// There is one string table per PBF primitive block. Most of
// them are really small, because most blocks are full of nodes
// with no tags. But string tables can get really large for
// ways with many tags or for large relations.
// The chosen size is enough so that 99% of all string tables
// in typical OSM files will only need a single memory
// allocation.
static constexpr const size_t default_stringtable_chunk_size = 100 * 1024;
StringStore m_strings;
std::map<const char*, size_t, StrComp> m_index;
std::unordered_map<const char*, size_t, djb2_hash, str_equal> m_index;
uint32_t m_size;
public:
StringTable() :
m_strings(1024 * 1024),
explicit StringTable(size_t size = default_stringtable_chunk_size) :
m_strings(size),
m_index(),
m_size(0) {
m_strings.add("");
@@ -231,7 +264,7 @@ namespace osmium {
}
uint32_t add(const char* s) {
auto f = m_index.find(s);
const auto f = m_index.find(s);
if (f != m_index.end()) {
return uint32_t(f->second);
}
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <string>
#include <utility>
@@ -100,36 +101,57 @@ namespace osmium {
static const size_t max_size = 0;
#endif
size_t old_size = out.size();
const size_t old_size = out.size();
int len = string_snprintf(out,
old_size,
max_size,
format,
std::forward<TArgs>(args)...);
const int len = string_snprintf(out,
old_size,
max_size,
format,
std::forward<TArgs>(args)...);
assert(len > 0);
if (size_t(len) >= max_size) {
#ifndef NDEBUG
int len2 =
const int len2 =
#endif
string_snprintf(out,
old_size,
size_t(len) + 1,
format,
std::forward<TArgs>(args)...);
string_snprintf(out,
old_size,
size_t(len) + 1,
format,
std::forward<TArgs>(args)...);
assert(len2 == len);
}
out.resize(old_size + size_t(len));
}
// Write out the value with exactly two hex digits.
inline void append_2_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
out += hex_digits[(value >> 4) & 0xf];
out += hex_digits[ value & 0xf];
}
// Write out the value with four or more hex digits.
inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
auto
v = value & 0xf0000000; if (v) out += hex_digits[v >> 28];
v = value & 0x0f000000; if (v) out += hex_digits[v >> 24];
v = value & 0x00f00000; if (v) out += hex_digits[v >> 20];
v = value & 0x000f0000; if (v) out += hex_digits[v >> 16];
out += hex_digits[(value >> 12) & 0xf];
out += hex_digits[(value >> 8) & 0xf];
out += hex_digits[(value >> 4) & 0xf];
out += hex_digits[ value & 0xf];
}
inline void append_utf8_encoded_string(std::string& out, const char* data) {
static const char* lookup_hex = "0123456789abcdef";
const char* end = data + std::strlen(data);
while (data != end) {
const char* last = data;
uint32_t c = utf8::next(data, end);
const uint32_t c = utf8::next(data, end);
// This is a list of Unicode code points that we let
// through instead of escaping them. It is incomplete
@@ -148,9 +170,9 @@ namespace osmium {
} else {
out += '%';
if (c <= 0xff) {
append_printf_formatted_string(out, "%02x", c);
append_2_hex_digits(out, c, lookup_hex);
} else {
append_printf_formatted_string(out, "%04x", c);
append_min_4_hex_digits(out, c, lookup_hex);
}
out += '%';
}
@@ -174,6 +196,7 @@ namespace osmium {
}
inline void append_debug_encoded_string(std::string& out, const char* data, const char* prefix, const char* suffix) {
static const char* lookup_hex = "0123456789ABCDEF";
const char* end = data + std::strlen(data);
while (data != end) {
@@ -194,7 +217,9 @@ namespace osmium {
out.append(last, data);
} else {
out.append(prefix);
append_printf_formatted_string(out, "<U+%04X>", c);
out.append("<U+");
append_min_4_hex_digits(out, c, lookup_hex);
out.append(">");
out.append(suffix);
}
}
@@ -36,6 +36,7 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <exception>
#include <future>
#include <memory>
#include <string>
#include <osmium/io/compression.hpp>
@@ -34,10 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <future>
#include <memory>
#include <string>
@@ -53,15 +50,19 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/types_from_string.hpp>
#include <osmium/thread/queue.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/cast.hpp>
@@ -192,6 +193,17 @@ namespace osmium {
static_cast<XMLParser*>(data)->characters(text, len);
}
// This handler is called when there are any XML entities
// declared in the OSM file. Entities are normally not used,
// but they can be misused. See
// https://en.wikipedia.org/wiki/Billion_laughs
// The handler will just throw an error.
static void entity_declaration_handler(void*,
const XML_Char*, int, const XML_Char*, int, const XML_Char*,
const XML_Char*, const XML_Char*, const XML_Char*) {
throw osmium::xml_error("XML entities are not supported");
}
public:
explicit ExpatXMLParser(T* callback_object) :
@@ -202,6 +214,7 @@ namespace osmium {
XML_SetUserData(m_parser, callback_object);
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
XML_SetCharacterDataHandler(m_parser, character_data_wrapper);
XML_SetEntityDeclHandler(m_parser, entity_declaration_handler);
}
ExpatXMLParser(const ExpatXMLParser&) = delete;
@@ -240,11 +253,11 @@ namespace osmium {
osmium::Location location;
check_attributes(attrs, [&location, &user, &object](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "lon")) {
location.set_lon(std::atof(value)); // XXX doesn't detect garbage after the number
} else if (!strcmp(name, "lat")) {
location.set_lat(std::atof(value)); // XXX doesn't detect garbage after the number
} else if (!strcmp(name, "user")) {
if (!std::strcmp(name, "lon")) {
location.set_lon(value);
} else if (!std::strcmp(name, "lat")) {
location.set_lat(value);
} else if (!std::strcmp(name, "user")) {
user = value;
} else {
object.set_attribute(name, value);
@@ -265,15 +278,15 @@ namespace osmium {
osmium::Location min;
osmium::Location max;
check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "min_lon")) {
min.set_lon(atof(value));
} else if (!strcmp(name, "min_lat")) {
min.set_lat(atof(value));
} else if (!strcmp(name, "max_lon")) {
max.set_lon(atof(value));
} else if (!strcmp(name, "max_lat")) {
max.set_lat(atof(value));
} else if (!strcmp(name, "user")) {
if (!std::strcmp(name, "min_lon")) {
min.set_lon(value);
} else if (!std::strcmp(name, "min_lat")) {
min.set_lat(value);
} else if (!std::strcmp(name, "max_lon")) {
max.set_lon(value);
} else if (!std::strcmp(name, "max_lat")) {
max.set_lat(value);
} else if (!std::strcmp(name, "user")) {
user = value;
} else {
new_changeset.set_attribute(name, value);
@@ -309,17 +322,17 @@ namespace osmium {
void start_element(const XML_Char* element, const XML_Char** attrs) {
switch (m_context) {
case context::root:
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
if (!strcmp(element, "osmChange")) {
if (!std::strcmp(element, "osm") || !std::strcmp(element, "osmChange")) {
if (!std::strcmp(element, "osmChange")) {
m_header.set_has_multiple_object_versions(true);
}
check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "version")) {
if (!std::strcmp(name, "version")) {
m_header.set("version", value);
if (strcmp(value, "0.6")) {
if (std::strcmp(value, "0.6")) {
throw osmium::format_version_error(value);
}
} else if (!strcmp(name, "generator")) {
} else if (!std::strcmp(name, "generator")) {
m_header.set("generator", value);
}
});
@@ -333,7 +346,7 @@ namespace osmium {
break;
case context::top:
assert(!m_tl_builder);
if (!strcmp(element, "node")) {
if (!std::strcmp(element, "node")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) {
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
@@ -342,7 +355,7 @@ namespace osmium {
} else {
m_context = context::ignored_node;
}
} else if (!strcmp(element, "way")) {
} else if (!std::strcmp(element, "way")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) {
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
@@ -351,7 +364,7 @@ namespace osmium {
} else {
m_context = context::ignored_way;
}
} else if (!strcmp(element, "relation")) {
} else if (!std::strcmp(element, "relation")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) {
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
@@ -360,7 +373,7 @@ namespace osmium {
} else {
m_context = context::ignored_relation;
}
} else if (!strcmp(element, "changeset")) {
} else if (!std::strcmp(element, "changeset")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::changeset) {
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
@@ -369,50 +382,56 @@ namespace osmium {
} else {
m_context = context::ignored_changeset;
}
} else if (!strcmp(element, "bounds")) {
} else if (!std::strcmp(element, "bounds")) {
osmium::Location min;
osmium::Location max;
check_attributes(attrs, [&min, &max](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "minlon")) {
min.set_lon(atof(value));
} else if (!strcmp(name, "minlat")) {
min.set_lat(atof(value));
} else if (!strcmp(name, "maxlon")) {
max.set_lon(atof(value));
} else if (!strcmp(name, "maxlat")) {
max.set_lat(atof(value));
if (!std::strcmp(name, "minlon")) {
min.set_lon(value);
} else if (!std::strcmp(name, "minlat")) {
min.set_lat(value);
} else if (!std::strcmp(name, "maxlon")) {
max.set_lon(value);
} else if (!std::strcmp(name, "maxlat")) {
max.set_lat(value);
}
});
osmium::Box box;
box.extend(min).extend(max);
m_header.add_box(box);
} else if (!strcmp(element, "delete")) {
} else if (!std::strcmp(element, "delete")) {
m_in_delete_section = true;
}
break;
case context::node:
m_last_context = context::node;
m_context = context::in_object;
if (!strcmp(element, "tag")) {
if (!std::strcmp(element, "tag")) {
get_tag(m_node_builder.get(), attrs);
}
break;
case context::way:
m_last_context = context::way;
m_context = context::in_object;
if (!strcmp(element, "nd")) {
if (!std::strcmp(element, "nd")) {
m_tl_builder.reset();
if (!m_wnl_builder) {
m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
}
check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "ref")) {
m_wnl_builder->add_node_ref(osmium::string_to_object_id(value));
NodeRef nr;
check_attributes(attrs, [this, &nr](const XML_Char* name, const XML_Char* value) {
if (!std::strcmp(name, "ref")) {
nr.set_ref(osmium::string_to_object_id(value));
} else if (!std::strcmp(name, "lon")) {
nr.location().set_lon(value);
} else if (!std::strcmp(name, "lat")) {
nr.location().set_lat(value);
}
});
} else if (!strcmp(element, "tag")) {
m_wnl_builder->add_node_ref(nr);
} else if (!std::strcmp(element, "tag")) {
m_wnl_builder.reset();
get_tag(m_way_builder.get(), attrs);
}
@@ -420,7 +439,7 @@ namespace osmium {
case context::relation:
m_last_context = context::relation;
m_context = context::in_object;
if (!strcmp(element, "member")) {
if (!std::strcmp(element, "member")) {
m_tl_builder.reset();
if (!m_rml_builder) {
@@ -431,11 +450,11 @@ namespace osmium {
object_id_type ref = 0;
const char* role = "";
check_attributes(attrs, [&type, &ref, &role](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "type")) {
if (!std::strcmp(name, "type")) {
type = char_to_item_type(value[0]);
} else if (!strcmp(name, "ref")) {
} else if (!std::strcmp(name, "ref")) {
ref = osmium::string_to_object_id(value);
} else if (!strcmp(name, "role")) {
} else if (!std::strcmp(name, "role")) {
role = static_cast<const char*>(value);
}
});
@@ -446,37 +465,37 @@ namespace osmium {
throw osmium::xml_error("Missing ref on relation member");
}
m_rml_builder->add_member(type, ref, role);
} else if (!strcmp(element, "tag")) {
} else if (!std::strcmp(element, "tag")) {
m_rml_builder.reset();
get_tag(m_relation_builder.get(), attrs);
}
break;
case context::changeset:
m_last_context = context::changeset;
if (!strcmp(element, "discussion")) {
if (!std::strcmp(element, "discussion")) {
m_context = context::discussion;
m_tl_builder.reset();
if (!m_changeset_discussion_builder) {
m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
}
} else if (!strcmp(element, "tag")) {
} else if (!std::strcmp(element, "tag")) {
m_context = context::in_object;
m_changeset_discussion_builder.reset();
get_tag(m_changeset_builder.get(), attrs);
}
break;
case context::discussion:
if (!strcmp(element, "comment")) {
if (!std::strcmp(element, "comment")) {
m_context = context::comment;
osmium::Timestamp date;
osmium::user_id_type uid = 0;
const char* user = "";
check_attributes(attrs, [&date, &uid, &user](const XML_Char* name, const XML_Char* value) {
if (!strcmp(name, "date")) {
if (!std::strcmp(name, "date")) {
date = osmium::Timestamp(value);
} else if (!strcmp(name, "uid")) {
} else if (!std::strcmp(name, "uid")) {
uid = osmium::string_to_user_id(value);
} else if (!strcmp(name, "user")) {
} else if (!std::strcmp(name, "user")) {
user = static_cast<const char*>(value);
}
});
@@ -484,7 +503,7 @@ namespace osmium {
}
break;
case context::comment:
if (!strcmp(element, "text")) {
if (!std::strcmp(element, "text")) {
m_context = context::comment_text;
}
break;
@@ -510,15 +529,15 @@ namespace osmium {
assert(false); // should never be here
break;
case context::top:
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
if (!std::strcmp(element, "osm") || !std::strcmp(element, "osmChange")) {
mark_header_as_done();
m_context = context::root;
} else if (!strcmp(element, "delete")) {
} else if (!std::strcmp(element, "delete")) {
m_in_delete_section = false;
}
break;
case context::node:
assert(!strcmp(element, "node"));
assert(!std::strcmp(element, "node"));
m_tl_builder.reset();
m_node_builder.reset();
m_buffer.commit();
@@ -526,7 +545,7 @@ namespace osmium {
flush_buffer();
break;
case context::way:
assert(!strcmp(element, "way"));
assert(!std::strcmp(element, "way"));
m_tl_builder.reset();
m_wnl_builder.reset();
m_way_builder.reset();
@@ -535,7 +554,7 @@ namespace osmium {
flush_buffer();
break;
case context::relation:
assert(!strcmp(element, "relation"));
assert(!std::strcmp(element, "relation"));
m_tl_builder.reset();
m_rml_builder.reset();
m_relation_builder.reset();
@@ -544,7 +563,7 @@ namespace osmium {
flush_buffer();
break;
case context::changeset:
assert(!strcmp(element, "changeset"));
assert(!std::strcmp(element, "changeset"));
m_tl_builder.reset();
m_changeset_discussion_builder.reset();
m_changeset_builder.reset();
@@ -553,15 +572,15 @@ namespace osmium {
flush_buffer();
break;
case context::discussion:
assert(!strcmp(element, "discussion"));
assert(!std::strcmp(element, "discussion"));
m_context = context::changeset;
break;
case context::comment:
assert(!strcmp(element, "comment"));
assert(!std::strcmp(element, "comment"));
m_context = context::discussion;
break;
case context::comment_text:
assert(!strcmp(element, "text"));
assert(!std::strcmp(element, "text"));
m_context = context::comment;
m_changeset_discussion_builder->add_comment_text(m_comment_text);
break;
@@ -569,22 +588,22 @@ namespace osmium {
m_context = m_last_context;
break;
case context::ignored_node:
if (!strcmp(element, "node")) {
if (!std::strcmp(element, "node")) {
m_context = context::top;
}
break;
case context::ignored_way:
if (!strcmp(element, "way")) {
if (!std::strcmp(element, "way")) {
m_context = context::top;
}
break;
case context::ignored_relation:
if (!strcmp(element, "relation")) {
if (!std::strcmp(element, "relation")) {
m_context = context::top;
}
break;
case context::ignored_changeset:
if (!strcmp(element, "changeset")) {
if (!std::strcmp(element, "changeset")) {
m_context = context::top;
}
break;
@@ -34,27 +34,26 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <cstdio>
#include <future>
#include <iterator>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <osmium/handler.hpp>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_util.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
@@ -86,8 +85,26 @@ namespace osmium {
*/
bool use_change_ops;
/// Should node locations be added to ways?
bool locations_on_ways;
};
namespace detail {
inline void append_lat_lon_attributes(std::string& out, const char* lat, const char* lon, const osmium::Location& location) {
out += ' ';
out += lat;
out += "=\"";
osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.y());
out += "\" ";
out += lon;
out += "=\"";
osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.x());
out += "\"";
}
} // namespace detail
class XMLOutputBlock : public OutputBlock {
// operation (create, modify, delete) for osc files
@@ -116,12 +133,21 @@ namespace osmium {
write_spaces(prefix_spaces());
}
template <typename T>
void write_attribute(const char* name, T value) {
*m_out += ' ';
*m_out += name;
*m_out += "=\"";
output_int(value);
*m_out += '"';
}
void write_meta(const osmium::OSMObject& object) {
output_formatted(" id=\"%" PRId64 "\"", object.id());
write_attribute("id", object.id());
if (m_options.add_metadata) {
if (object.version()) {
output_formatted(" version=\"%d\"", object.version());
write_attribute("version", object.version());
}
if (object.timestamp()) {
@@ -131,13 +157,14 @@ namespace osmium {
}
if (!object.user_is_anonymous()) {
output_formatted(" uid=\"%d\" user=\"", object.uid());
write_attribute("uid", object.uid());
*m_out += " user=\"";
append_xml_encoded_string(*m_out, object.user());
*m_out += "\"";
}
if (object.changeset()) {
output_formatted(" changeset=\"%d\"", object.changeset());
write_attribute("changeset", object.changeset());
}
if (m_options.add_visible_flag) {
@@ -162,8 +189,11 @@ namespace osmium {
}
void write_discussion(const osmium::ChangesetDiscussion& comments) {
*m_out += " <discussion>\n";
for (const auto& comment : comments) {
output_formatted(" <comment uid=\"%d\" user=\"", comment.uid());
*m_out += " <comment";
write_attribute("uid", comment.uid());
*m_out += " user=\"";
append_xml_encoded_string(*m_out, comment.user());
*m_out += "\" date=\"";
*m_out += comment.date().to_iso();
@@ -251,11 +281,7 @@ namespace osmium {
write_meta(node);
if (node.location()) {
*m_out += " lat=\"";
osmium::util::double2string(std::back_inserter(*m_out), node.location().lat_without_check(), 7);
*m_out += "\" lon=\"";
osmium::util::double2string(std::back_inserter(*m_out), node.location().lon_without_check(), 7);
*m_out += "\"";
detail::append_lat_lon_attributes(*m_out, "lat", "lon", node.location());
}
if (node.tags().empty()) {
@@ -287,9 +313,23 @@ namespace osmium {
*m_out += ">\n";
for (const auto& node_ref : way.nodes()) {
write_prefix();
output_formatted(" <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
if (m_options.locations_on_ways) {
for (const auto& node_ref : way.nodes()) {
write_prefix();
*m_out += " <nd";
write_attribute("ref", node_ref.ref());
if (node_ref.location()) {
detail::append_lat_lon_attributes(*m_out, "lat", "lon", node_ref.location());
}
*m_out += "/>\n";
}
} else {
for (const auto& node_ref : way.nodes()) {
write_prefix();
*m_out += " <nd";
write_attribute("ref", node_ref.ref());
*m_out += "/>\n";
}
}
write_tags(way.tags(), prefix_spaces());
@@ -318,7 +358,9 @@ namespace osmium {
write_prefix();
*m_out += " <member type=\"";
*m_out += item_type_to_name(member.type());
output_formatted("\" ref=\"%" PRId64 "\" role=\"", member.ref());
*m_out += '"';
write_attribute("ref", member.ref());
*m_out += " role=\"";
append_xml_encoded_string(*m_out, member.role());
*m_out += "\"/>\n";
}
@@ -332,7 +374,7 @@ namespace osmium {
void changeset(const osmium::Changeset& changeset) {
*m_out += " <changeset";
output_formatted(" id=\"%" PRId32 "\"", changeset.id());
write_attribute("id", changeset.id());
if (changeset.created_at()) {
*m_out += " created_at=\"";
@@ -351,22 +393,21 @@ namespace osmium {
if (!changeset.user_is_anonymous()) {
*m_out += " user=\"";
append_xml_encoded_string(*m_out, changeset.user());
output_formatted("\" uid=\"%d\"", changeset.uid());
*m_out += '"';
write_attribute("uid", changeset.uid());
}
if (changeset.bounds()) {
output_formatted(" min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
output_formatted(" min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
output_formatted(" max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
output_formatted(" max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left());
detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right());
}
output_formatted(" num_changes=\"%" PRId32 "\"", changeset.num_changes());
output_formatted(" comments_count=\"%" PRId32 "\"", changeset.num_comments());
write_attribute("num_changes", changeset.num_changes());
write_attribute("comments_count", changeset.num_comments());
// If there are no tags and no comments, we can close the
// tag right here and are done.
if (changeset.tags().empty() && changeset.num_comments() == 0) {
if (changeset.tags().empty() && changeset.discussion().empty()) {
*m_out += "/>\n";
return;
}
@@ -375,8 +416,7 @@ namespace osmium {
write_tags(changeset.tags(), 0);
if (changeset.num_comments() > 0) {
*m_out += " <discussion>\n";
if (!changeset.discussion().empty()) {
write_discussion(changeset.discussion());
}
@@ -394,9 +434,10 @@ namespace osmium {
XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_change_ops = file.is_true("xml_change_format");
m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops;
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_change_ops = file.is_true("xml_change_format");
m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops;
m_options.locations_on_ways = file.is_true("locations_on_ways");
}
XMLOutputFormat(const XMLOutputFormat&) = delete;
@@ -425,10 +466,9 @@ namespace osmium {
for (const auto& box : header.boxes()) {
out += " <bounds";
append_printf_formatted_string(out, " minlon=\"%.7f\"", box.bottom_left().lon());
append_printf_formatted_string(out, " minlat=\"%.7f\"", box.bottom_left().lat());
append_printf_formatted_string(out, " maxlon=\"%.7f\"", box.top_right().lon());
append_printf_formatted_string(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
detail::append_lat_lon_attributes(out, "minlat", "minlon", box.bottom_left());
detail::append_lat_lon_attributes(out, "maxlat", "maxlon", box.top_right());
out += "/>\n";
}
send_to_output_queue(std::move(out));
+6 -6
View File
@@ -33,12 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <memory>
#include <stdexcept>
#include <string>
#include <zlib.h>
#include <protozero/types.hpp>
#include <osmium/io/error.hpp>
#include <osmium/util/cast.hpp>
@@ -62,7 +62,7 @@ namespace osmium {
std::string output(output_size, '\0');
auto result = ::compress(
const auto result = ::compress(
reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
&output_size,
reinterpret_cast<const unsigned char*>(input.data()),
@@ -89,10 +89,10 @@ namespace osmium {
* @param output Uncompressed result data.
* @returns Pointer and size to incompressed data.
*/
inline std::pair<const char*, size_t> zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
inline protozero::data_view zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
output.resize(raw_size);
auto result = ::uncompress(
const auto result = ::uncompress(
reinterpret_cast<unsigned char*>(&*output.begin()),
&raw_size,
reinterpret_cast<const unsigned char*>(input),
@@ -103,7 +103,7 @@ namespace osmium {
throw io_error(std::string("failed to uncompress data: ") + zError(result));
}
return std::make_pair(output.data(), output.size());
return protozero::data_view{output.data(), output.size()};
}
} // namespace detail
+2 -4
View File
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
@@ -43,7 +42,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/util/options.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -115,7 +113,7 @@ namespace osmium {
}
// if filename is a URL, default to XML format
std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
const std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
if (protocol == "http" || protocol == "https") {
m_file_format = file_format::xml;
}
@@ -174,7 +172,7 @@ namespace osmium {
}
for (auto& option : options) {
size_t pos = option.find_first_of('=');
const size_t pos = option.find_first_of('=');
if (pos == std::string::npos) {
set(option, true);
} else {
@@ -42,15 +42,20 @@ DEALINGS IN THE SOFTWARE.
* @attention If you include this file, you'll need to link with `libz`.
*/
#include <stdexcept>
#include <cstddef>
#include <string>
#ifndef _MSC_VER
# include <unistd.h>
#endif
#include <errno.h>
#include <zlib.h>
#include <osmium/io/compression.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/io/detail/read_write.hpp>
#include <osmium/io/writer_options.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
@@ -102,7 +107,7 @@ namespace osmium {
explicit GzipCompressor(int fd, fsync sync) :
Compressor(sync),
m_fd(dup(fd)),
m_fd(::dup(fd)),
m_gzfile(::gzdopen(fd, "w")) {
if (!m_gzfile) {
detail::throw_gzip_error(m_gzfile, "write initialization failed");
@@ -171,6 +176,9 @@ namespace osmium {
detail::throw_gzip_error(m_gzfile, "read failed");
}
buffer.resize(static_cast<std::string::size_type>(nread));
#if ZLIB_VERNUM >= 0x1240
set_offset(size_t(::gzoffset(m_gzfile)));
#endif
return buffer;
}
+10 -11
View File
@@ -41,7 +41,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -57,7 +56,7 @@ namespace osmium {
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
using item_iterator = typename osmium::memory::Buffer::t_iterator<TItem>;
TSource* m_source;
std::shared_ptr<osmium::memory::Buffer> m_buffer;
@@ -69,20 +68,20 @@ namespace osmium {
if (!m_buffer || !*m_buffer) { // end of input
m_source = nullptr;
m_buffer.reset();
m_iter = item_iterator();
m_iter = item_iterator{};
return;
}
m_iter = m_buffer->begin<TItem>();
} while (m_iter == m_buffer->end<TItem>());
m_iter = m_buffer->select<TItem>().begin();
} while (m_iter == m_buffer->select<TItem>().end());
}
public:
typedef std::input_iterator_tag iterator_category;
typedef TItem value_type;
typedef ptrdiff_t difference_type;
typedef TItem* pointer;
typedef TItem& reference;
using iterator_category = std::input_iterator_tag;
using value_type = TItem;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
explicit InputIterator(TSource& source) :
m_source(&source) {
@@ -99,7 +98,7 @@ namespace osmium {
assert(m_buffer);
assert(m_iter);
++m_iter;
if (m_iter == m_buffer->end<TItem>()) {
if (m_iter == m_buffer->select<TItem>().end()) {
update_buffer();
}
return *this;
+46
View File
@@ -0,0 +1,46 @@
#ifndef OSMIUM_IO_OPL_INPUT_HPP
#define OSMIUM_IO_OPL_INPUT_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/**
* @file
*
* Include this file if you want to read OSM OPL files.
*
*/
#include <osmium/io/reader.hpp> // IWYU pragma: export
#include <osmium/io/detail/opl_input_format.hpp> // IWYU pragma: export
#endif // OSMIUM_IO_OPL_INPUT_HPP
@@ -35,10 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iterator>
#include <memory>
#include <utility>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/diff_object.hpp>
#include <osmium/util/compatibility.hpp>
@@ -51,12 +48,18 @@ namespace osmium {
namespace io {
template <typename TDest>
class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
class OutputIterator {
TDest* m_destination;
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
explicit OutputIterator(TDest& destination) :
m_destination(&destination) {
}
+1 -1
View File
@@ -34,6 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#pragma message("Including overwrite.hpp is deprecated, #include <osmium/io/writer_options.hpp> instead.")
#include <osmium/io/writer_options.hpp>
#include <osmium/io/writer_options.hpp> // IWYU pragma: keep
#endif // OSMIUM_IO_OVERWRITE_HPP
+51 -10
View File
@@ -62,11 +62,26 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
namespace osmium {
namespace io {
namespace detail {
inline size_t get_input_queue_size() noexcept {
const size_t n = osmium::config::get_max_queue_size("INPUT", 20);
return n > 2 ? n : 2;
}
inline size_t get_osmdata_queue_size() noexcept {
const size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
return n > 2 ? n : 2;
}
} // namespace detail
/**
* This is the user-facing interface for reading OSM files. Instantiate
* an object of this class with a file name or osmium::io::File object
@@ -75,9 +90,6 @@ namespace osmium {
*/
class Reader {
static constexpr size_t max_input_queue_size = 20; // XXX
static constexpr size_t max_osmdata_queue_size = 20; // XXX
osmium::io::File m_file;
osmium::osm_entity_bits::type m_read_which_entities;
@@ -104,6 +116,8 @@ namespace osmium {
osmium::thread::thread_handler m_thread;
size_t m_file_size;
// This function will run in a separate thread.
static void parser_thread(const osmium::io::File& file,
detail::future_string_queue_type& input_queue,
@@ -111,8 +125,8 @@ namespace osmium {
std::promise<osmium::io::Header>&& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
std::promise<osmium::io::Header> promise = std::move(header_promise);
auto creator = detail::ParserFactory::instance().get_creator_function(file);
auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
const auto creator = detail::ParserFactory::instance().get_creator_function(file);
const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
parser->parse();
}
@@ -133,7 +147,7 @@ namespace osmium {
if (pipe(pipefd) < 0) {
throw std::system_error(errno, std::system_category(), "opening pipe failed");
}
pid_t pid = fork();
const pid_t pid = fork();
if (pid < 0) {
throw std::system_error(errno, std::system_category(), "fork failed");
}
@@ -202,16 +216,17 @@ namespace osmium {
m_read_which_entities(read_which_entities),
m_status(status::okay),
m_childpid(0),
m_input_queue(max_input_queue_size, "raw_input"),
m_input_queue(detail::get_input_queue_size(), "raw_input"),
m_decompressor(m_file.buffer() ?
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
m_read_thread_manager(*m_decompressor, m_input_queue),
m_osmdata_queue(max_osmdata_queue_size, "parser_results"),
m_osmdata_queue(detail::get_osmdata_queue_size(), "parser_results"),
m_osmdata_queue_wrapper(m_osmdata_queue),
m_header_future(),
m_header(),
m_thread() {
m_thread(),
m_file_size(m_decompressor->file_size()) {
std::promise<osmium::io::Header> header_promise;
m_header_future = header_promise.get_future();
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
@@ -263,7 +278,7 @@ namespace osmium {
#ifndef _WIN32
if (m_childpid) {
int status;
pid_t pid = ::waitpid(m_childpid, &status, 0);
const pid_t pid = ::waitpid(m_childpid, &status, 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
@@ -350,6 +365,32 @@ namespace osmium {
return m_status == status::eof || m_status == status::closed;
}
/**
* Get the size of the input file. Returns 0 if the file size
* is not available (for instance when reading from stdin).
*/
size_t file_size() const noexcept {
return m_file_size;
}
/**
* Returns the current offset into the input file. Returns 0 if
* the offset is not available (for instance when reading from
* stdin).
*
* The offset can be used together with the result of file_size()
* to estimate how much of the file has been read. Note that due
* to buffering inside Osmium, this value will be larger than
* the amount of data actually available to the application.
*
* Do not call this function too often, certainly not for every
* object you are reading. Depending on the file type it might
* do an expensive system call.
*/
size_t offset() const noexcept {
return m_decompressor->offset();
}
}; // class Reader
/**
+20 -4
View File
@@ -34,11 +34,13 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <exception>
#include <functional>
#include <future>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <string>
#include <thread>
#include <utility>
#include <osmium/io/compression.hpp>
@@ -52,11 +54,25 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/writer_options.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
namespace osmium {
namespace memory {
class Item;
} //namespace memory
namespace io {
namespace detail {
inline size_t get_output_queue_size() noexcept {
size_t n = osmium::config::get_max_queue_size("OUTPUT", 20);
return n > 2 ? n : 2;
}
} // namespace detail
/**
* This is the user-facing interface for writing OSM files. Instantiate
* an object of this class with a file name or osmium::io::File object
@@ -194,7 +210,7 @@ namespace osmium {
template <typename... TArgs>
explicit Writer(const osmium::io::File& file, TArgs&&... args) :
m_file(file.check()),
m_output_queue(20, "raw_output"), // XXX
m_output_queue(detail::get_output_queue_size(), "raw_output"),
m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
m_buffer(),
m_buffer_size(default_buffer_size),
@@ -304,7 +320,7 @@ namespace osmium {
}
try {
m_buffer.push_back(item);
} catch (osmium::buffer_is_full&) {
} catch (const osmium::buffer_is_full&) {
do_flush();
m_buffer.push_back(item);
}
+10
View File
@@ -517,6 +517,16 @@ namespace osmium {
*/
using const_iterator = t_const_iterator<osmium::OSMEntity>;
template <typename T>
ItemIteratorRange<T> select() {
return ItemIteratorRange<T>{m_data, m_data + m_committed};
}
template <typename T>
ItemIteratorRange<const T> select() const {
return ItemIteratorRange<const T>{m_data, m_data + m_committed};
}
/**
* Get iterator for iterating over all items of type T in the
* buffer.
+11 -5
View File
@@ -44,17 +44,23 @@ namespace osmium {
namespace memory {
template <typename TMember>
class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
class CollectionIterator {
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
// on whether TMember is const. This allows this class to be used as an iterator and
// as a const_iterator.
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
data_type m_data;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = TMember;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
CollectionIterator() noexcept :
m_data(nullptr) {
}
@@ -112,9 +118,9 @@ namespace osmium {
public:
typedef CollectionIterator<TMember> iterator;
typedef CollectionIterator<const TMember> const_iterator;
typedef TMember value_type;
using iterator = CollectionIterator<TMember>;
using const_iterator = CollectionIterator<const TMember>;
using value_type = TMember;
static constexpr osmium::item_type itemtype = TCollectionItemType;
+29 -7
View File
@@ -33,8 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <osmium/util/cast.hpp>
namespace osmium {
@@ -45,16 +47,21 @@ namespace osmium {
class Builder;
} // namespace builder
enum class diff_indicator_type {
none = 0,
left = 1,
right = 2,
both = 3
}; // diff_indicator_type
namespace memory {
typedef uint32_t item_size_type;
using item_size_type = uint32_t;
// align datastructures to this many bytes
constexpr item_size_type align_bytes = 8;
template <typename T>
inline T padded_length(T length) noexcept {
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
inline std::size_t padded_length(std::size_t length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1);
}
@@ -100,7 +107,8 @@ namespace osmium {
item_size_type m_size;
item_type m_type;
uint16_t m_removed : 1;
uint16_t m_padding : 15;
uint16_t m_diff : 2;
uint16_t m_padding : 13;
template <typename TMember>
friend class CollectionIterator;
@@ -121,6 +129,7 @@ namespace osmium {
m_size(size),
m_type(type),
m_removed(false),
m_diff(0),
m_padding(0) {
}
@@ -150,7 +159,7 @@ namespace osmium {
}
item_size_type padded_size() const {
return padded_length(m_size);
return static_cast_with_assert<item_size_type>(padded_length(m_size));
}
item_type type() const noexcept {
@@ -165,6 +174,19 @@ namespace osmium {
m_removed = removed;
}
diff_indicator_type diff() const noexcept {
return diff_indicator_type(m_diff);
}
char diff_as_char() const noexcept {
static constexpr const char* diff_chars = "*-+ ";
return diff_chars[m_diff];
}
void set_diff(diff_indicator_type diff) noexcept {
m_diff = uint16_t(diff);
}
}; // class Item
static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
+110 -15
View File
@@ -34,16 +34,29 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <cstddef>
#include <iterator>
#include <iosfwd>
#include <type_traits>
#include <osmium/fwd.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp>
namespace osmium {
class Area;
class Changeset;
class InnerRing;
class Node;
class OSMEntity;
class OSMObject;
class OuterRing;
class Relation;
class RelationMemberList;
class TagList;
class Way;
class WayNodeList;
namespace memory {
namespace detail {
@@ -116,19 +129,19 @@ namespace osmium {
} // namespace detail
template <typename TMember>
class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
class ItemIterator {
static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
// on whether TMember is const. This allows this class to be used as an iterator and
// as a const_iterator.
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
data_type m_data;
data_type m_end;
void advance_to_next_item_of_right_type() {
void advance_to_next_item_of_right_type() noexcept {
while (m_data != m_end &&
!detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
m_data = reinterpret_cast<TMember*>(m_data)->next();
@@ -137,23 +150,29 @@ namespace osmium {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = TMember;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
ItemIterator() noexcept :
m_data(nullptr),
m_end(nullptr) {
}
ItemIterator(data_type data, data_type end) :
ItemIterator(data_type data, data_type end) noexcept :
m_data(data),
m_end(end) {
advance_to_next_item_of_right_type();
}
template <typename T>
ItemIterator<T> cast() const {
ItemIterator<T> cast() const noexcept {
return ItemIterator<T>(m_data, m_end);
}
ItemIterator<TMember>& operator++() {
ItemIterator<TMember>& operator++() noexcept {
assert(m_data);
assert(m_data != m_end);
m_data = reinterpret_cast<TMember*>(m_data)->next();
@@ -166,45 +185,50 @@ namespace osmium {
* types. Do not use this unless you know what you are
* doing.
*/
ItemIterator<TMember>& advance_once() {
ItemIterator<TMember>& advance_once() noexcept {
assert(m_data);
assert(m_data != m_end);
m_data = reinterpret_cast<TMember*>(m_data)->next();
return *static_cast<ItemIterator<TMember>*>(this);
}
ItemIterator<TMember> operator++(int) {
ItemIterator<TMember> operator++(int) noexcept {
ItemIterator<TMember> tmp(*this);
operator++();
return tmp;
}
bool operator==(const ItemIterator<TMember>& rhs) const {
bool operator==(const ItemIterator<TMember>& rhs) const noexcept {
return m_data == rhs.m_data && m_end == rhs.m_end;
}
bool operator!=(const ItemIterator<TMember>& rhs) const {
bool operator!=(const ItemIterator<TMember>& rhs) const noexcept {
return !(*this == rhs);
}
unsigned char* data() const {
data_type data() noexcept {
assert(m_data);
return m_data;
}
TMember& operator*() const {
const unsigned char* data() const noexcept {
assert(m_data);
return m_data;
}
TMember& operator*() const noexcept {
assert(m_data);
assert(m_data != m_end);
return *reinterpret_cast<TMember*>(m_data);
}
TMember* operator->() const {
TMember* operator->() const noexcept {
assert(m_data);
assert(m_data != m_end);
return reinterpret_cast<TMember*>(m_data);
}
explicit operator bool() const {
explicit operator bool() const noexcept {
return (m_data != nullptr) && (m_data != m_end);
}
@@ -221,6 +245,77 @@ namespace osmium {
return out;
}
template <typename T>
class ItemIteratorRange {
static_assert(std::is_base_of<osmium::memory::Item, T>::value, "Template parameter must derive from osmium::memory::Item");
// This data_type is either 'unsigned char*' or
// 'const unsigned char*' depending on whether T is const.
using data_type = typename std::conditional<std::is_const<T>::value, const unsigned char*, unsigned char*>::type;
data_type m_begin;
data_type m_end;
public:
using iterator = ItemIterator<T>;
using const_iterator = ItemIterator<const T>;
ItemIteratorRange(data_type first, data_type last) noexcept :
m_begin(first),
m_end(last) {
}
iterator begin() noexcept {
return iterator{m_begin, m_end};
}
iterator end() noexcept {
return iterator{m_end, m_end};
}
const_iterator cbegin() const noexcept {
return const_iterator{m_begin, m_end};
}
const_iterator cend() const noexcept {
return const_iterator{m_end, m_end};
}
const_iterator begin() const noexcept {
return cbegin();
}
const_iterator end() const noexcept {
return cend();
}
/**
* Return the number of items in this range.
*
* Note that this methods has worst-case complexity O(n) with n
* being the number of items in the underlying range.
*/
size_t size() const {
if (m_begin == m_end) {
return 0;
}
return std::distance(cbegin(), cend());
}
/**
* Is this range empty?
*
* Note that this methods has worst-case complexity O(n) with n
* being the number of items in the underlying range.
*/
bool empty() const {
return size() == 0;
}
}; // class ItemIteratorRange
} // namespace memory
} // namespace osmium
@@ -40,11 +40,9 @@ DEALINGS IN THE SOFTWARE.
#include <boost/iterator/indirect_iterator.hpp>
#include <osmium/handler.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/object.hpp>
// IWYU pragma: no_forward_declare osmium::OSMObject
// IWYU pragma: no_forward_declare osmium::memory::Item
namespace osmium {
@@ -70,8 +68,8 @@ namespace osmium {
public:
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
using iterator = boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject>;
using const_iterator = boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject>;
ObjectPointerCollection() noexcept :
m_objects() {
+67
View File
@@ -0,0 +1,67 @@
#ifndef OSMIUM_OPL_HPP
#define OSMIUM_OPL_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <osmium/memory/buffer.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp>
namespace osmium {
/**
* Parses one line in OPL format. The line must not have a newline
* character at the end. Buffer.commit() is called automatically if the
* write succeeded.
*
* @param data Line must be in this zero-delimited string.
* @param buffer Result will be written to this buffer.
*
* @returns true if an entity was parsed, false otherwise (for instance
* when the line is empty).
* @throws osmium::opl_error If the parsing fails.
*/
inline bool opl_parse(const char* data, osmium::memory::Buffer& buffer) {
try {
const bool wrote_something = osmium::io::detail::opl_parse_line(0, data, buffer);
buffer.commit();
return wrote_something;
} catch (const osmium::opl_error&) {
buffer.rollback();
throw;
}
}
} // namespace osmium
#endif // OSMIUM_OPL_HPP
+12 -3
View File
@@ -33,11 +33,20 @@ DEALINGS IN THE SOFTWARE.
*/
#include <osmium/osm/node.hpp> // IWYU pragma: export
#include <osmium/osm/way.hpp> // IWYU pragma: export
#include <osmium/osm/relation.hpp> // IWYU pragma: export
#include <osmium/osm/area.hpp> // IWYU pragma: export
#include <osmium/osm/changeset.hpp> // IWYU pragma: export
#include <osmium/osm/entity.hpp> // IWYU pragma: export
#include <osmium/osm/entity_bits.hpp> // IWYU pragma: export
#include <osmium/osm/item_type.hpp> // IWYU pragma: export
#include <osmium/osm/location.hpp> // IWYU pragma: export
#include <osmium/osm/node.hpp> // IWYU pragma: export
#include <osmium/osm/node_ref.hpp> // IWYU pragma: export
#include <osmium/osm/node_ref_list.hpp> // IWYU pragma: export
#include <osmium/osm/object.hpp> // IWYU pragma: export
#include <osmium/osm/relation.hpp> // IWYU pragma: export
#include <osmium/osm/timestamp.hpp> // IWYU pragma: export
#include <osmium/osm/types.hpp> // IWYU pragma: export
#include <osmium/osm/way.hpp> // IWYU pragma: export
/**
* @brief Namespace for everything in the Osmium library.
+31 -4
View File
@@ -35,14 +35,17 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cstdlib>
#include <iterator>
#include <utility>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/node_ref_list.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -144,8 +147,8 @@ namespace osmium {
*
* @returns Pair (number outer rings, number inner rings)
*/
std::pair<int, int> num_rings() const {
std::pair<int, int> counter { 0, 0 };
std::pair<size_t, size_t> num_rings() const {
std::pair<size_t, size_t> counter { 0, 0 };
for (auto it = cbegin(); it != cend(); ++it) {
switch (it->type()) {
@@ -185,27 +188,51 @@ namespace osmium {
}
/**
* @deprecated Use inner_rings() instead.
*
* Get iterator for iterating over all inner rings in a specified outer
* ring.
*
* @param it Iterator specifying outer ring.
* @returns Iterator to first inner ring in specified outer ring.
*/
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
OSMIUM_DEPRECATED osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return it.cast<const osmium::InnerRing>();
}
/**
* @deprecated Use inner_rings() instead.
*
* Get iterator for iterating over all inner rings in a specified outer
* ring.
*
* @param it Iterator specifying outer ring.
* @returns Iterator one past last inner ring in specified outer ring.
*/
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
OSMIUM_DEPRECATED osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return std::next(it).cast<const osmium::InnerRing>();
}
/**
* Return an iterator range for all outer rings.
* You can use the usual begin() and end() functions to iterate over
* all outer rings.
*/
osmium::memory::ItemIteratorRange<const osmium::OuterRing> outer_rings() const {
return subitems<const osmium::OuterRing>();
}
/**
* Return an iterator range for all inner rings in the given outer
* ring.
* You can use the usual begin() and end() functions to iterate over
* all outer rings.
*/
osmium::memory::ItemIteratorRange<const osmium::InnerRing> inner_rings(const osmium::OuterRing& outer) const {
osmium::memory::ItemIteratorRange<const osmium::OuterRing> outer_range{outer.data(), next()};
return osmium::memory::ItemIteratorRange<const osmium::InnerRing>{outer_range.cbegin().data(), std::next(outer_range.cbegin()).data()};
}
}; // class Area
static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");
-1
View File
@@ -36,7 +36,6 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <iosfwd>
#include <osmium/util/compatibility.hpp>
#include <osmium/osm/location.hpp>
namespace osmium {
+16 -9
View File
@@ -33,7 +33,9 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
#include <cstring>
#include <iterator>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
@@ -131,7 +133,7 @@ namespace osmium {
public:
typedef size_t size_type;
using size_type = size_t;
ChangesetDiscussion() :
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
@@ -185,6 +187,11 @@ namespace osmium {
public:
// Dummy to avoid warning because of unused private fields. Do not use.
int32_t do_not_use() const noexcept {
return m_padding1 + m_padding2;
}
/// Get ID of this changeset
changeset_id_type id() const noexcept {
return m_id;
@@ -369,23 +376,23 @@ namespace osmium {
* @param value Value of the attribute
*/
void set_attribute(const char* attr, const char* value) {
if (!strcmp(attr, "id")) {
if (!std::strcmp(attr, "id")) {
set_id(value);
} else if (!strcmp(attr, "num_changes")) {
} else if (!std::strcmp(attr, "num_changes")) {
set_num_changes(value);
} else if (!strcmp(attr, "comments_count")) {
} else if (!std::strcmp(attr, "comments_count")) {
set_num_comments(value);
} else if (!strcmp(attr, "created_at")) {
} else if (!std::strcmp(attr, "created_at")) {
set_created_at(osmium::Timestamp(value));
} else if (!strcmp(attr, "closed_at")) {
} else if (!std::strcmp(attr, "closed_at")) {
set_closed_at(osmium::Timestamp(value));
} else if (!strcmp(attr, "uid")) {
} else if (!std::strcmp(attr, "uid")) {
set_uid(value);
}
}
typedef osmium::memory::CollectionIterator<Item> iterator;
typedef osmium::memory::CollectionIterator<const Item> const_iterator;
using iterator = osmium::memory::CollectionIterator<Item>;
using const_iterator = osmium::memory::CollectionIterator<const Item>;
iterator begin() {
return iterator(subitems_position());
+18 -11
View File
@@ -36,11 +36,17 @@ DEALINGS IN THE SOFTWARE.
#include <cstdint>
#include <osmium/osm/area.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/util/endian.hpp>
@@ -71,8 +77,8 @@ namespace osmium {
# if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(value);
# else
uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
uint64_t val2 = byte_swap_32(value >> 32);
const uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
const uint64_t val2 = byte_swap_32(value >> 32);
return (val1 << 32) | val2;
# endif
}
@@ -86,11 +92,11 @@ namespace osmium {
public:
TCRC& operator()() {
TCRC& operator()() noexcept {
return m_crc;
}
const TCRC& operator()() const {
const TCRC& operator()() const noexcept {
return m_crc;
}
@@ -106,7 +112,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint16_t));
#else
uint16_t v = osmium::util::byte_swap_16(value);
const uint16_t v = osmium::util::byte_swap_16(value);
m_crc.process_bytes(&v, sizeof(uint16_t));
#endif
}
@@ -115,7 +121,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint32_t));
#else
uint32_t v = osmium::util::byte_swap_32(value);
const uint32_t v = osmium::util::byte_swap_32(value);
m_crc.process_bytes(&v, sizeof(uint32_t));
#endif
}
@@ -124,7 +130,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint64_t));
#else
uint64_t v = osmium::util::byte_swap_64(value);
const uint64_t v = osmium::util::byte_swap_64(value);
m_crc.process_bytes(&v, sizeof(uint64_t));
#endif
}
@@ -151,6 +157,7 @@ namespace osmium {
void update(const NodeRef& node_ref) {
update_int64(node_ref.ref());
update(node_ref.location());
}
void update(const NodeRefList& node_refs) {
@@ -205,10 +212,10 @@ namespace osmium {
void update(const osmium::Area& area) {
update(static_cast<const osmium::OSMObject&>(area));
for (auto it = area.cbegin(); it != area.cend(); ++it) {
if (it->type() == osmium::item_type::outer_ring ||
it->type() == osmium::item_type::inner_ring) {
update(static_cast<const osmium::NodeRefList&>(*it));
for (const auto& subitem : area) {
if (subitem.type() == osmium::item_type::outer_ring ||
subitem.type() == osmium::item_type::inner_ring) {
update(static_cast<const osmium::NodeRefList&>(subitem));
}
}
}
+4 -1
View File
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <osmium/fwd.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/timestamp.hpp>
@@ -43,6 +42,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
class Node;
class Way;
class Relation;
/**
* A DiffObject holds pointers to three OSMObjects, the current object,
* the previous, and the next. They always have the same type (Node, Way,
+16 -2
View File
@@ -33,12 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
#include <type_traits>
#include <osmium/osm/item_type.hpp>
namespace osmium {
/**
* @brief Bitfield for OSM entity types.
* @brief Bit field for OSM entity types.
*/
namespace osm_entity_bits {
@@ -94,8 +97,19 @@ namespace osmium {
return lhs;
}
/**
* Get entity_bits from item_type.
*
* @pre item_type must be undefined, node, way, relation, area, or
* changeset.
*/
inline type from_item_type(osmium::item_type item_type) noexcept {
return static_cast<osmium::osm_entity_bits::type>(0x1 << (static_cast<uint16_t>(item_type) - 1));
auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
assert(ut <= 0x05);
if (ut == 0) {
return nothing;
}
return static_cast<osmium::osm_entity_bits::type>(0x1 << (ut - 1));
}
} // namespace osm_entity_bits
+267 -17
View File
@@ -35,15 +35,14 @@ DEALINGS IN THE SOFTWARE.
#include <cmath>
#include <cstdint>
#include <cstring>
#include <functional>
#include <iosfwd>
#include <iterator>
#include <limits>
#include <stdexcept>
#include <string>
#include <iostream>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/double.hpp>
namespace osmium {
/**
@@ -62,6 +61,184 @@ namespace osmium {
}; // struct invalid_location
namespace detail {
constexpr const int coordinate_precision = 10000000;
// Convert string with a floating point number into integer suitable
// for use as coordinate in a Location.
inline int32_t string_to_location_coordinate(const char** data) {
const char* str = *data;
const char* full = str;
int64_t result = 0;
int sign = 1;
// one more than significant digits to allow rounding
int64_t scale = 8;
// paranoia check for maximum number of digits
int max_digits = 10;
// optional minus sign
if (*str == '-') {
sign = -1;
++str;
}
// there has to be at least one digit
if (*str >= '0' && *str <= '9') {
result = *str - '0';
++str;
} else {
goto error;
}
// optional additional digits before decimal point
while (*str >= '0' && *str <= '9' && max_digits > 0) {
result = result * 10 + (*str - '0');
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
}
// optional decimal point
if (*str == '.') {
++str;
// read significant digits
for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
result = result * 10 + (*str - '0');
}
// ignore non-significant digits
max_digits = 20;
while (*str >= '0' && *str <= '9' && max_digits > 0) {
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
}
}
// optional exponent in scientific notation
if (*str == 'e' || *str == 'E') {
++str;
int esign = 1;
// optional minus sign
if (*str == '-') {
esign = -1;
++str;
}
int64_t eresult = 0;
// there has to be at least one digit in exponent
if (*str >= '0' && *str <= '9') {
eresult = *str - '0';
++str;
} else {
goto error;
}
// optional additional digits in exponent
max_digits = 5;
while (*str >= '0' && *str <= '9' && max_digits > 0) {
eresult = eresult * 10 + (*str - '0');
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
}
scale += eresult * esign;
}
if (scale < 0) {
result = 0;
} else {
for (; scale > 0; --scale) {
result *= 10;
}
result = (result + 5) / 10 * sign;
if (result > std::numeric_limits<int32_t>::max() ||
result < std::numeric_limits<int32_t>::min()) {
goto error;
}
}
*data = str;
return static_cast<int32_t>(result);
error:
throw invalid_location{std::string{"wrong format for coordinate: '"} + full + "'"};
}
// Convert integer as used by location for coordinates into a string.
template <typename T>
inline T append_location_coordinate_to_string(T iterator, int32_t value) {
// handle negative values
if (value < 0) {
*iterator++ = '-';
value = -value;
}
// write digits into temporary buffer
int32_t v = value;
char temp[10];
char* t = temp;
do {
*t++ = char(v % 10) + '0';
v /= 10;
} while (v != 0);
while (t-temp < 7) {
*t++ = '0';
}
// write out digits before decimal point
if (value >= coordinate_precision) {
if (value >= 10 * coordinate_precision) {
if (value >= 100 * coordinate_precision) {
*iterator++ = *--t;
}
*iterator++ = *--t;
}
*iterator++ = *--t;
} else {
*iterator++ = '0';
}
// remove trailing zeros
const char* tn = temp;
while (tn < t && *tn == '0') {
++tn;
}
// decimal point
if (t != tn) {
*iterator++ = '.';
while (t != tn) {
*iterator++ = *--t;
}
}
return iterator;
}
} // namespace detail
/**
* Locations define a place on earth.
*
@@ -89,14 +266,12 @@ namespace osmium {
// static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
static constexpr int32_t undefined_coordinate = 2147483647;
static constexpr int coordinate_precision = 10000000;
static int32_t double_to_fix(const double c) noexcept {
return static_cast<int32_t>(std::round(c * coordinate_precision));
return static_cast<int32_t>(std::round(c * detail::coordinate_precision));
}
static constexpr double fix_to_double(const int32_t c) noexcept {
return static_cast<double>(c) / coordinate_precision;
return static_cast<double>(c) / detail::coordinate_precision;
}
/**
@@ -154,10 +329,10 @@ namespace osmium {
* usual bounds (-180<=lon<=180, -90<=lat<=90).
*/
constexpr bool valid() const noexcept {
return m_x >= -180 * coordinate_precision
&& m_x <= 180 * coordinate_precision
&& m_y >= -90 * coordinate_precision
&& m_y <= 90 * coordinate_precision;
return m_x >= -180 * detail::coordinate_precision
&& m_x <= 180 * detail::coordinate_precision
&& m_y >= -90 * detail::coordinate_precision
&& m_y <= 90 * detail::coordinate_precision;
}
constexpr int32_t x() const noexcept {
@@ -226,11 +401,47 @@ namespace osmium {
return *this;
}
Location& set_lon(const char* str) {
const char** data = &str;
m_x = detail::string_to_location_coordinate(data);
if (**data != '\0') {
throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
}
return *this;
}
Location& set_lat(const char* str) {
const char** data = &str;
m_y = detail::string_to_location_coordinate(data);
if (**data != '\0') {
throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
}
return *this;
}
Location& set_lon_partial(const char** str) {
m_x = detail::string_to_location_coordinate(str);
return *this;
}
Location& set_lat_partial(const char** str) {
m_y = detail::string_to_location_coordinate(str);
return *this;
}
template <typename T>
T as_string(T iterator, const char separator) const {
iterator = osmium::util::double2string(iterator, lon(), 7);
T as_string_without_check(T iterator, const char separator = ',') const {
iterator = detail::append_location_coordinate_to_string(iterator, x());
*iterator++ = separator;
return osmium::util::double2string(iterator, lat(), 7);
return detail::append_location_coordinate_to_string(iterator, y());
}
template <typename T>
T as_string(T iterator, const char separator = ',') const {
if (!valid()) {
throw osmium::invalid_location("invalid location");
}
return as_string_without_check(iterator, separator);
}
}; // class Location
@@ -273,13 +484,52 @@ namespace osmium {
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
if (location) {
out << '(' << location.lon() << ',' << location.lat() << ')';
out << '(';
location.as_string(std::ostream_iterator<char>(out), ',');
out << ')';
} else {
out << "(undefined,undefined)";
}
return out;
}
namespace detail {
template <int N>
inline size_t hash(const osmium::Location& location) noexcept {
return location.x() ^ location.y();
}
template <>
inline size_t hash<8>(const osmium::Location& location) noexcept {
size_t h = location.x();
h <<= 32;
return h ^ location.y();
}
} // namespace detail
} // namespace osmium
namespace std {
// This pragma is a workaround for a bug in an old libc implementation
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
template <>
struct hash<osmium::Location> {
using argument_type = osmium::Location;
using result_type = size_t;
size_t operator()(const osmium::Location& location) const noexcept {
return osmium::detail::hash<sizeof(size_t)>(location);
}
};
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} // namespace std
#endif // OSMIUM_OSM_LOCATION_HPP
+2 -1
View File
@@ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
namespace osmium {
@@ -66,7 +67,7 @@ namespace osmium {
* Returns the number of NodeRefs in the collection.
*/
size_t size() const noexcept {
auto size_node_refs = byte_size() - sizeof(NodeRefList);
const auto size_node_refs = byte_size() - sizeof(NodeRefList);
assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef);
}
+67 -24
View File
@@ -33,11 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <tuple>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
@@ -49,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/types_from_string.hpp>
#include <osmium/util/misc.hpp>
namespace osmium {
@@ -172,9 +172,9 @@ namespace osmium {
* @returns Reference to object to make calls chainable.
*/
OSMObject& set_visible(const char* visible) {
if (!strcmp("true", visible)) {
if (!std::strcmp("true", visible)) {
set_visible(true);
} else if (!strcmp("false", visible)) {
} else if (!std::strcmp("false", visible)) {
set_visible(false);
} else {
throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
@@ -286,6 +286,20 @@ namespace osmium {
return *this;
}
/**
* Set the timestamp when this object last changed.
*
* @param timestamp Timestamp in ISO format.
* @returns Reference to object to make calls chainable.
*/
OSMObject& set_timestamp(const char* timestamp) {
m_timestamp = detail::parse_timestamp(timestamp);
if (timestamp[20] != '\0') {
throw std::invalid_argument{"can not parse timestamp"};
}
return *this;
}
/// Get user name for this object.
const char* user() const noexcept {
return reinterpret_cast<const char*>(data() + sizeof_object());
@@ -311,25 +325,28 @@ namespace osmium {
*
* @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
* @param value Value of the attribute
* @returns Reference to object to make calls chainable.
*/
void set_attribute(const char* attr, const char* value) {
if (!strcmp(attr, "id")) {
OSMObject& set_attribute(const char* attr, const char* value) {
if (!std::strcmp(attr, "id")) {
set_id(value);
} else if (!strcmp(attr, "version")) {
} else if (!std::strcmp(attr, "version")) {
set_version(value);
} else if (!strcmp(attr, "changeset")) {
} else if (!std::strcmp(attr, "changeset")) {
set_changeset(value);
} else if (!strcmp(attr, "timestamp")) {
set_timestamp(osmium::Timestamp(value));
} else if (!strcmp(attr, "uid")) {
} else if (!std::strcmp(attr, "timestamp")) {
set_timestamp(value);
} else if (!std::strcmp(attr, "uid")) {
set_uid(value);
} else if (!strcmp(attr, "visible")) {
} else if (!std::strcmp(attr, "visible")) {
set_visible(value);
}
return *this;
}
typedef osmium::memory::CollectionIterator<Item> iterator;
typedef osmium::memory::CollectionIterator<const Item> const_iterator;
using iterator = osmium::memory::CollectionIterator<Item>;
using const_iterator = osmium::memory::CollectionIterator<const Item>;
iterator begin() {
return iterator(subitems_position());
@@ -355,6 +372,26 @@ namespace osmium {
return cend();
}
/**
* Get a range of subitems of a specific type.
*
* @tparam The type (must be derived from osmium::memory::Item.
*/
template <typename T>
osmium::memory::ItemIteratorRange<T> subitems() {
return osmium::memory::ItemIteratorRange<T>{subitems_position(), next()};
}
/**
* Get a range of subitems of a specific type.
*
* @tparam The type (must be derived from osmium::memory::Item.
*/
template <typename T>
osmium::memory::ItemIteratorRange<const T> subitems() const {
return osmium::memory::ItemIteratorRange<const T>{subitems_position(), next()};
}
template <typename T>
using t_iterator = osmium::memory::ItemIterator<T>;
@@ -399,8 +436,8 @@ namespace osmium {
* OSMObjects are equal if their type, id, and version are equal.
*/
inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return lhs.type() == rhs.type() &&
lhs.id() == rhs.id() &&
return lhs.type() == rhs.type() &&
lhs.id() == rhs.id() &&
lhs.version() == rhs.version();
}
@@ -409,16 +446,22 @@ namespace osmium {
}
/**
* OSMObjects can be ordered by type, id and version.
* Note that we use the absolute value of the id for a
* better ordering of objects with negative id.
* OSMObjects can be ordered by type, id, version, and timestamp. Usually
* ordering by timestamp is not necessary as there shouldn't be two
* objects with the same type, id, and version. But this can happen when
* creating diff files from extracts, so we take the timestamp into
* account here.
*
* Note that we use the absolute value of the id for a better ordering
* of objects with negative id. If the IDs have the same absolute value,
* the positive ID comes first.
*
* See object_order_type_id_reverse_version if you need a different
* ordering.
*/
inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
if (lhs.type() != rhs.type()) {
return lhs.type() < rhs.type();
}
return (lhs.id() == rhs.id() && lhs.version() < rhs.version()) ||
lhs.positive_id() < rhs.positive_id();
return const_tie(lhs.type(), lhs.positive_id(), lhs.id() < 0, lhs.version(), lhs.timestamp()) <
const_tie(rhs.type(), rhs.positive_id(), rhs.id() < 0, rhs.version(), rhs.timestamp());
}
inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
@@ -33,12 +33,17 @@ DEALINGS IN THE SOFTWARE.
*/
#include <tuple>
#include <osmium/osm/object.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/util/misc.hpp>
namespace osmium {
/**
* Function object class for comparing OSM objects for equality by type, id, and version.
* Function object class for comparing OSM objects for equality by type,
* id, and version.
*/
struct object_equal_type_id_version {
@@ -53,8 +58,8 @@ namespace osmium {
}; // struct object_equal_type_id_version
/**
* Function object class for comparing OSM objects for equality by type and id,
* ignoring the version.
* Function object class for comparing OSM objects for equality by type
* and id, ignoring the version.
*/
struct object_equal_type_id {
@@ -70,7 +75,8 @@ namespace osmium {
}; // struct object_equal_type_id
/**
* Function object class for ordering OSM objects by type, id, and version.
* Function object class for ordering OSM objects by type, id, version,
* and timestamp.
*/
struct object_order_type_id_version {
@@ -85,18 +91,17 @@ namespace osmium {
}; // struct object_order_type_id_version
/**
* Function object class for ordering OSM objects by type, id, and reverse version,
* ie objects are ordered by type and id, but later versions of an object are
* ordered before earlier versions of the same object.
* Function object class for ordering OSM objects by type, id, and
* reverse version, timestamp. So objects are ordered by type and id, but
* later versions of an object are ordered before earlier versions of the
* same object. This is useful when the last version of an object needs
* to be used.
*/
struct object_order_type_id_reverse_version {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
if (lhs.type() != rhs.type()) {
return lhs.type() < rhs.type();
}
return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
lhs.positive_id() < rhs.positive_id();
return const_tie(lhs.type(), lhs.id() < 0, lhs.positive_id(), rhs.version(), rhs.timestamp()) <
const_tie(rhs.type(), rhs.id() < 0, rhs.positive_id(), lhs.version(), lhs.timestamp());
}
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+2 -2
View File
@@ -33,13 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <osmium/memory/collection.hpp> // IWYU pragma: keep
#include <osmium/memory/item.hpp>
#include <osmium/osm/entity.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
@@ -149,7 +149,7 @@ namespace osmium {
public:
typedef size_t size_type;
using size_type = size_t;
RelationMemberList() :
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
-1
View File
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <osmium/osm/location.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
+50 -10
View File
@@ -34,7 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cstddef>
#include <cassert>
#include <cstring>
#include <iosfwd>
#include <iterator>
@@ -87,7 +87,7 @@ namespace osmium {
}; // class Tag
inline bool operator==(const Tag& a, const Tag& b) {
return !std::strcmp(a.key(), b.key()) && !strcmp(a.value(), b.value());
return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value());
}
inline bool operator<(const Tag& a, const Tag& b) {
@@ -104,32 +104,72 @@ namespace osmium {
class TagList : public osmium::memory::Collection<Tag, osmium::item_type::tag_list> {
const_iterator find_key(const char* key) const noexcept {
return std::find_if(cbegin(), cend(), [key](const Tag& tag) {
return !std::strcmp(tag.key(), key);
});
}
public:
typedef size_t size_type;
using size_type = size_t;
TagList() :
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
}
/**
* Returns the number of tags in this tag list.
*/
size_type size() const noexcept {
return static_cast<size_type>(std::distance(begin(), end()));
}
/**
* Get tag value for the given tag key. If the key is not set, returns
* the default_value.
*
* @pre @code key != nullptr @endcode
*/
const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
auto result = std::find_if(cbegin(), cend(), [key](const Tag& tag) {
return !strcmp(tag.key(), key);
});
if (result == cend()) {
return default_value;
}
return result->value();
assert(key);
const auto result = find_key(key);
return result == cend() ? default_value : result->value();
}
/**
* Get tag value for the given tag key. If the key is not set, returns
* nullptr.
*
* @pre @code key != nullptr @endcode
*/
const char* operator[](const char* key) const noexcept {
return get_value_by_key(key);
}
/**
* Returns true if the tag with the given key is in the tag list.
*
* @pre @code key != nullptr @endcode
*/
bool has_key(const char* key) const noexcept {
assert(key);
return find_key(key) != cend();
}
/**
* Returns true if the tag with the given key and value is in the
* tag list.
*
* @pre @code key != nullptr && value != nullptr @endcode
*/
bool has_tag(const char* key, const char* value) const noexcept {
assert(key);
assert(value);
const auto result = find_key(key);
return result != cend() && !std::strcmp(result->value(), value);
}
}; // class TagList
static_assert(sizeof(TagList) % osmium::memory::align_bytes == 0, "Class osmium::TagList has wrong size to be aligned properly!");
+61 -22
View File
@@ -40,12 +40,71 @@ DEALINGS IN THE SOFTWARE.
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/minmax.hpp> // IWYU pragma: keep
namespace osmium {
namespace detail {
inline time_t parse_timestamp(const char* str) {
static const int mon_lengths[] = {
31, 29, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
if (str[ 0] >= '0' && str[ 0] <= '9' &&
str[ 1] >= '0' && str[ 1] <= '9' &&
str[ 2] >= '0' && str[ 2] <= '9' &&
str[ 3] >= '0' && str[ 3] <= '9' &&
str[ 4] == '-' &&
str[ 5] >= '0' && str[ 5] <= '9' &&
str[ 6] >= '0' && str[ 6] <= '9' &&
str[ 7] == '-' &&
str[ 8] >= '0' && str[ 8] <= '9' &&
str[ 9] >= '0' && str[ 9] <= '9' &&
str[10] == 'T' &&
str[11] >= '0' && str[11] <= '9' &&
str[12] >= '0' && str[12] <= '9' &&
str[13] == ':' &&
str[14] >= '0' && str[14] <= '9' &&
str[15] >= '0' && str[15] <= '9' &&
str[16] == ':' &&
str[17] >= '0' && str[17] <= '9' &&
str[18] >= '0' && str[18] <= '9' &&
str[19] == 'Z') {
struct tm tm;
tm.tm_year = (str[ 0] - '0') * 1000 +
(str[ 1] - '0') * 100 +
(str[ 2] - '0') * 10 +
(str[ 3] - '0') - 1900;
tm.tm_mon = (str[ 5] - '0') * 10 + (str[ 6] - '0') - 1;
tm.tm_mday = (str[ 8] - '0') * 10 + (str[ 9] - '0');
tm.tm_hour = (str[11] - '0') * 10 + (str[12] - '0');
tm.tm_min = (str[14] - '0') * 10 + (str[15] - '0');
tm.tm_sec = (str[17] - '0') * 10 + (str[18] - '0');
tm.tm_wday = 0;
tm.tm_yday = 0;
tm.tm_isdst = 0;
if (tm.tm_year >= 0 &&
tm.tm_mon >= 0 && tm.tm_mon <= 11 &&
tm.tm_mday >= 1 && tm.tm_mday <= mon_lengths[tm.tm_mon] &&
tm.tm_hour >= 0 && tm.tm_hour <= 23 &&
tm.tm_min >= 0 && tm.tm_min <= 59 &&
tm.tm_sec >= 0 && tm.tm_sec <= 60) {
#ifndef _WIN32
return timegm(&tm);
#else
return _mkgmtime(&tm);
#endif
}
}
throw std::invalid_argument{"can not parse timestamp"};
}
} // namespace detail
/**
* A timestamp. Internal representation is an unsigned 32bit integer
* holding seconds since epoch (1970-01-01T00:00:00Z), so this will
@@ -56,7 +115,7 @@ namespace osmium {
class Timestamp {
// length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
static constexpr int timestamp_length = 20 + 1;
static constexpr const int timestamp_length = 20 + 1;
// The timestamp format for OSM timestamps in strftime(3) format.
// This is the ISO-Format "yyyy-mm-ddThh:mm:ssZ".
@@ -97,27 +156,7 @@ namespace osmium {
* @throws std::invalid_argument if the timestamp can not be parsed.
*/
explicit Timestamp(const char* timestamp) {
#ifndef _WIN32
struct tm tm {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
throw std::invalid_argument("can't parse timestamp");
}
m_timestamp = static_cast<uint32_t>(timegm(&tm));
#else
struct tm tm;
int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (n != 6) {
throw std::invalid_argument("can't parse timestamp");
}
tm.tm_year -= 1900;
tm.tm_mon--;
tm.tm_wday = 0;
tm.tm_yday = 0;
tm.tm_isdst = 0;
m_timestamp = static_cast<uint32_t>(_mkgmtime(&tm));
#endif
m_timestamp = static_cast<uint32_t>(detail::parse_timestamp(timestamp));
}
/**
+10 -10
View File
@@ -38,25 +38,25 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
/*
* The following typedefs are chosen so that they can represent all needed
* The following types are chosen so that they can represent all needed
* numbers and still be reasonably space efficient. As the OSM database
* needs 64 bit IDs for nodes, this size is used for all object IDs.
*/
typedef int64_t object_id_type; ///< Type for OSM object (node, way, or relation) IDs.
typedef uint64_t unsigned_object_id_type; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
typedef uint32_t object_version_type; ///< Type for OSM object version number.
typedef uint32_t changeset_id_type; ///< Type for OSM changeset IDs.
typedef uint32_t user_id_type; ///< Type for OSM user IDs.
typedef int32_t signed_user_id_type; ///< Type for signed OSM user IDs.
typedef uint32_t num_changes_type; ///< Type for changeset num_changes.
typedef uint32_t num_comments_type; ///< Type for changeset num_comments.
using object_id_type = int64_t; ///< Type for OSM object (node, way, or relation) IDs.
using unsigned_object_id_type = uint64_t; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
using object_version_type = uint32_t; ///< Type for OSM object version number.
using changeset_id_type = uint32_t; ///< Type for OSM changeset IDs.
using user_id_type = uint32_t; ///< Type for OSM user IDs.
using signed_user_id_type = int32_t; ///< Type for signed OSM user IDs.
using num_changes_type = uint32_t; ///< Type for changeset num_changes.
using num_comments_type = uint32_t; ///< Type for changeset num_comments.
/**
* Size for strings in OSM data such as user names, tag keys, roles, etc.
* In Osmium they can be up to 2^16 bytes long, but OSM usually has lower
* defined limits.
*/
typedef uint16_t string_size_type;
using string_size_type = uint16_t;
// maximum of 256 characters of max 4 bytes each (in UTF-8 encoding)
constexpr const int max_osm_string_length = 256 * 4;

Some files were not shown because too many files have changed in this diff Show More