pull in latest osmcode/libosmium changes

This commit is contained in:
Dennis Luxen 2015-04-13 15:44:38 +02:00
commit 9cc68b26e2
69 changed files with 1906 additions and 1528 deletions

View File

@ -1,4 +1,2 @@
core
*.swp *.swp
build*
.ycm_extra_conf.pyc .ycm_extra_conf.pyc

View File

@ -6,6 +6,10 @@
# #
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
from os.path import realpath, dirname
basedir = dirname(realpath(__file__))
# some default flags # some default flags
# for more information install clang-3.2-doc package and # for more information install clang-3.2-doc package and
# check UsersManual.html # check UsersManual.html
@ -26,9 +30,9 @@ flags = [
'c++', 'c++',
# libosmium include dirs # libosmium include dirs
'-Iinclude', '-I%s/include' % basedir,
'-Itest/include', '-I%s/test/include' % basedir,
'-Itest/data-test/include', '-I%s/test/data-test/include' % basedir,
# include third party libraries # include third party libraries
'-I/usr/include/gdal', '-I/usr/include/gdal',

31
third_party/libosmium/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,31 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] -
## [2.1.0] - 2015-03-31
### Added
- When writing PBF files, sorting the PBF stringtables is now optional.
- More tests and documentation.
### Changed
- Some functions are now declared `noexcept`.
- XML parser fails now if the top-level element is not `osm` or `osmChange`.
### Fixed
- Race condition in PBF reader.
- Multipolygon collector was accessing non-existent NodeRef.
- Doxygen documentation wan't showing all classes/functions due to a bug in
Doxygen (up to version 1.8.8). This version contains a workaround to fix
this.
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.1.0...HEAD
[2.1.0]: https://github.com/osmcode/libosmium/compare/v2.0.0...v2.1.0

View File

@ -9,6 +9,8 @@
cmake_minimum_required(VERSION 2.8 FATAL_ERROR) cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# #
@ -23,9 +25,9 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev"
project(libosmium) project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 0) set(LIBOSMIUM_VERSION_MAJOR 2)
set(LIBOSMIUM_VERSION_MINOR 0) set(LIBOSMIUM_VERSION_MINOR 1)
set(LIBOSMIUM_VERSION_PATCH 1) set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION set(LIBOSMIUM_VERSION
${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}) ${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH})

View File

@ -66,11 +66,12 @@ build_script:
- mkdir build - mkdir build
- cd build - cd build
- echo %config% - echo %config%
- cmake .. -LA -G "Visual Studio 14 Win64" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_DIR=%LODEPSDIR%\protobuf\include -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include -DBZIP2_LIBRARIES=%LIBBZIP2% -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include - cmake .. -LA -G "Visual Studio 14 Win64" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBUILD_BENCHMARKS=OFF -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_DIR=%LODEPSDIR%\protobuf\include -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include -DBZIP2_LIBRARIES=%LIBBZIP2% -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include
- msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140 - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140
#- cmake .. -LA -G "NMake Makefiles" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_DIR=%LODEPSDIR%\protobuf\include -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include -DBZIP2_LIBRARIES=%LIBBZIP2% -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include #- cmake .. -LA -G "NMake Makefiles" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_DIR=%LODEPSDIR%\protobuf\include -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include -DBZIP2_LIBRARIES=%LIBBZIP2% -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include
#- nmake #- nmake
test_script: test_script:
- ctest --output-on-failure -C %config% # -LE fails_on_windows exempts tests we know will fail
- ctest --output-on-failure -C %config% -LE fails_on_windows

View File

@ -226,7 +226,6 @@ if(Osmium_USE_SPARSEHASH)
if(SPARSEHASH_INCLUDE_DIR) if(SPARSEHASH_INCLUDE_DIR)
# Find size of sparsetable::size_type. This does not work on older # Find size of sparsetable::size_type. This does not work on older
# CMake versions because they can do this check only in C, not in C++. # CMake versions because they can do this check only in C, not in C++.
# Until we find a better way, we'll live with that.
include(CheckTypeSize) include(CheckTypeSize)
set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
@ -234,14 +233,19 @@ if(Osmium_USE_SPARSEHASH)
set(CMAKE_EXTRA_INCLUDE_FILES) set(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_INCLUDES)
# Falling back to checking size_t if google::sparsetable<int>::size_type
# could not be checked.
if(SPARSETABLE_SIZE_TYPE STREQUAL "")
check_type_size("void*" VOID_PTR_SIZE)
set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE})
endif()
# Sparsetable::size_type must be at least 8 bytes (64bit), otherwise # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise
# OSM object IDs will not fit. # OSM object IDs will not fit.
if(SPARSETABLE_SIZE_TYPE GREATER 7) if(SPARSETABLE_SIZE_TYPE GREATER 7)
set(SPARSEHASH_FOUND 1) set(SPARSEHASH_FOUND 1)
add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND}) add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND})
list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR}) list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR})
elseif(SPARSETABLE_SIZE_TYPE STREQUAL "")
message(WARNING "Osmium: Disabled Google SparseHash library because we can't detect whether we are on a 64bit system.")
else() else()
message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).")
endif() endif()

View File

@ -694,7 +694,7 @@ CITE_BIB_FILES =
# messages are off. # messages are off.
# The default value is: NO. # The default value is: NO.
QUIET = NO QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are # The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
@ -860,7 +860,7 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # or removed, the anchors will not be placed correctly.
INPUT_FILTER = INPUT_FILTER = "grep -v static_assert"
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the # basis. Doxygen will compare the file name with each pattern and apply the
@ -876,7 +876,7 @@ FILTER_PATTERNS =
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO. # The default value is: NO.
FILTER_SOURCE_FILES = NO FILTER_SOURCE_FILES = YES
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
@ -1080,7 +1080,7 @@ HTML_STYLESHEET =
# see the documentation. # see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = doc/osmium.css HTML_EXTRA_STYLESHEET = "@PROJECT_SOURCE_DIR@/doc/osmium.css"
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note # other source files which should be copied to the HTML output directory. Note

View File

@ -142,7 +142,7 @@ namespace osmium {
* Overwritten from the base class. * Overwritten from the base class.
*/ */
void way_not_in_any_relation(const osmium::Way& way) { void way_not_in_any_relation(const osmium::Way& way) {
if (way.ends_have_same_location() && way.nodes().size() > 3) { if (way.nodes().size() > 3 && way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon // way is closed and has enough nodes, build simple multipolygon
try { try {
TAssembler assembler(m_assembler_config); TAssembler assembler(m_assembler_config);

View File

@ -171,8 +171,7 @@ namespace osmium {
template <class TItem> template <class TItem>
class ObjectBuilder : public Builder { class ObjectBuilder : public Builder {
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item");
"ObjectBuilder can only build objects derived from osmium::memory::Item");
public: public:

View File

@ -63,11 +63,9 @@ namespace osmium {
template <class TStoragePosIDs, class TStorageNegIDs = dummy_type> template <class TStoragePosIDs, class TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler { class NodeLocationsForWays : public osmium::handler::Handler {
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
"Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
"Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
public: public:

View File

@ -84,8 +84,7 @@ namespace osmium {
template <typename TId, typename TValue> template <typename TId, typename TValue>
class Map { class Map {
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Map must be unsigned integral type");
"TId template parameter for class Map must be unsigned integral type");
Map(const Map&) = delete; Map(const Map&) = delete;
Map& operator=(const Map&) = delete; Map& operator=(const Map&) = delete;

View File

@ -50,8 +50,7 @@ namespace osmium {
template <typename TId, typename TValue> template <typename TId, typename TValue>
class Multimap { class Multimap {
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
"TId template parameter for class Multimap must be unsigned integral type");
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;

View File

@ -84,8 +84,9 @@ namespace osmium {
class PBFInputFormat : public osmium::io::detail::InputFormat { class PBFInputFormat : public osmium::io::detail::InputFormat {
bool m_use_thread_pool; bool m_use_thread_pool;
bool m_eof { false };
queue_type m_queue; queue_type m_queue;
std::atomic<bool> m_done; std::atomic<bool> m_quit_input_thread;
std::thread m_reader; std::thread m_reader;
osmium::thread::Queue<std::string>& m_input_queue; osmium::thread::Queue<std::string>& m_input_queue;
std::string m_input_buffer; std::string m_input_buffer;
@ -164,11 +165,20 @@ namespace osmium {
} }
++n; ++n;
if (m_done) { if (m_quit_input_thread) {
return; return;
} }
} }
m_done = true;
// Send an empty buffer to signal the reader that we are
// done.
std::promise<osmium::memory::Buffer> promise;
m_queue.push(promise.get_future());
promise.set_value(osmium::memory::Buffer{});
}
void signal_input_thread_to_quit() {
m_quit_input_thread = true;
} }
public: public:
@ -184,7 +194,7 @@ namespace osmium {
osmium::io::detail::InputFormat(file, read_which_entities), osmium::io::detail::InputFormat(file, read_which_entities),
m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()), m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()),
m_queue(20, "pbf_parser_results"), // XXX m_queue(20, "pbf_parser_results"), // XXX
m_done(false), m_quit_input_thread(false),
m_input_queue(input_queue), m_input_queue(input_queue),
m_input_buffer() { m_input_buffer() {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
@ -199,30 +209,37 @@ namespace osmium {
} }
~PBFInputFormat() { ~PBFInputFormat() {
m_done = true; signal_input_thread_to_quit();
if (m_reader.joinable()) { if (m_reader.joinable()) {
m_reader.join(); m_reader.join();
} }
} }
/** /**
* Returns the next buffer with OSM data read from the PBF file. * Returns the next buffer with OSM data read from the PBF
* Blocks if data is not available yet. * file. Blocks if data is not available yet.
* Returns an empty buffer at end of input. * Returns an empty buffer at end of input.
*/ */
osmium::memory::Buffer read() override { osmium::memory::Buffer read() override {
if (!m_done || !m_queue.empty()) { osmium::memory::Buffer buffer;
std::future<osmium::memory::Buffer> buffer_future; if (m_eof) {
m_queue.wait_and_pop(buffer_future); return buffer;
try {
return buffer_future.get();
} catch (...) {
m_done = true;
throw;
}
} }
return osmium::memory::Buffer(); std::future<osmium::memory::Buffer> buffer_future;
m_queue.wait_and_pop(buffer_future);
try {
buffer = std::move(buffer_future.get());
if (!buffer) {
m_eof = true;
}
return buffer;
} catch (...) {
m_eof = true;
signal_input_thread_to_quit();
throw;
}
} }
}; // class PBFInputFormat }; // class PBFInputFormat

View File

@ -294,6 +294,14 @@ namespace osmium {
*/ */
bool m_use_compression {true}; bool m_use_compression {true};
/**
* Should the string tables in the data blocks be sorted?
*
* Not sorting the string tables makes writing PBF files
* slightly faster.
*/
bool m_sort_stringtables { true };
/** /**
* While the .osm.pbf-format is able to carry all meta information, it is * While the .osm.pbf-format is able to carry all meta information, it is
* also able to omit this information to reduce size. * also able to omit this information to reduce size.
@ -340,6 +348,21 @@ namespace osmium {
///// Blob writing ///// ///// Blob writing /////
void delta_encode_string_ids() {
if (pbf_nodes && pbf_nodes->has_dense()) {
OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
if (dense->has_denseinfo()) {
OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
for (int i = 0, l=denseinfo->user_sid_size(); i<l; ++i) {
auto user_sid = denseinfo->user_sid(i);
denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
}
}
}
}
/** /**
* Before a PrimitiveBlock gets serialized, all interim StringTable-ids needs to be * Before a PrimitiveBlock gets serialized, all interim StringTable-ids needs to be
* mapped to the associated real StringTable ids. This is done in this function. * mapped to the associated real StringTable ids. This is done in this function.
@ -518,11 +541,13 @@ namespace osmium {
pbf_primitive_block.set_granularity(location_granularity()); pbf_primitive_block.set_granularity(location_granularity());
pbf_primitive_block.set_date_granularity(date_granularity()); pbf_primitive_block.set_date_granularity(date_granularity());
// store the interim StringTable into the protobuf object string_table.store_stringtable(pbf_primitive_block.mutable_stringtable(), m_sort_stringtables);
string_table.store_stringtable(pbf_primitive_block.mutable_stringtable());
// map all interim string ids to real ids if (m_sort_stringtables) {
map_string_ids(); map_string_ids();
} else {
delta_encode_string_ids();
}
std::promise<std::string> promise; std::promise<std::string> promise;
m_output_queue.push(promise.get_future()); m_output_queue.push(promise.get_future());
@ -743,6 +768,9 @@ namespace osmium {
if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") { if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") {
m_use_compression = false; m_use_compression = false;
} }
if (file.get("pbf_sort_stringtables") == "false") {
m_sort_stringtables = false;
}
if (file.get("pbf_add_metadata") == "false") { if (file.get("pbf_add_metadata") == "false") {
m_should_add_metadata = false; m_should_add_metadata = false;
} }

View File

@ -145,12 +145,13 @@ namespace osmium {
* implementation) is that the string table is sorted first by reverse count (ie descending) * implementation) is that the string table is sorted first by reverse count (ie descending)
* and then by reverse lexicographic order. * and then by reverse lexicographic order.
*/ */
void store_stringtable(OSMPBF::StringTable* st) { void store_stringtable(OSMPBF::StringTable* st, bool sort) {
// add empty StringTable entry at index 0 // add empty StringTable entry at index 0
// StringTable index 0 is reserved as delimiter in the densenodes key/value list // StringTable index 0 is reserved as delimiter in the densenodes key/value list
// this line also ensures that there's always a valid StringTable // this line also ensures that there's always a valid StringTable
st->add_s(""); st->add_s("");
if (sort) {
std::multimap<string_info, std::string> sortedbycount; std::multimap<string_info, std::string> sortedbycount;
m_id2id_map.resize(m_size+1); m_id2id_map.resize(m_size+1);
@ -170,6 +171,19 @@ namespace osmium {
// store the mapping from the interim-id to the real id // store the mapping from the interim-id to the real id
m_id2id_map[mapping.first.interim_id] = ++n; m_id2id_map[mapping.first.interim_id] = ++n;
} }
} else {
std::vector<std::pair<string_id_type, const char*>> sortedbyid;
sortedbyid.reserve(m_strings.size());
for (const auto& p : m_strings) {
sortedbyid.emplace_back(p.second.interim_id, p.first.c_str());
}
std::sort(sortedbyid.begin(), sortedbyid.end());
for (const auto& mapping : sortedbyid) {
st->add_s(mapping.second);
}
}
} }
/** /**

View File

@ -74,8 +74,8 @@ namespace osmium {
/** /**
* Exception thrown when the XML parser failed. The exception contains * Exception thrown when the XML parser failed. The exception contains
* information about the place where the error happened and the type of * (if available) information about the place where the error happened
* error. * and the type of error.
*/ */
struct xml_error : public io_error { struct xml_error : public io_error {
@ -84,7 +84,7 @@ namespace osmium {
XML_Error error_code; XML_Error error_code;
std::string error_string; std::string error_string;
xml_error(XML_Parser parser) : explicit xml_error(XML_Parser parser) :
io_error(std::string("XML parsing error at line ") io_error(std::string("XML parsing error at line ")
+ std::to_string(XML_GetCurrentLineNumber(parser)) + std::to_string(XML_GetCurrentLineNumber(parser))
+ ", column " + ", column "
@ -97,8 +97,20 @@ namespace osmium {
error_string(XML_ErrorString(error_code)) { error_string(XML_ErrorString(error_code)) {
} }
explicit xml_error(const std::string& message) :
io_error(message),
line(0),
column(0),
error_code(),
error_string(message) {
}
}; // struct xml_error }; // struct xml_error
/**
* Exception thrown when an OSM XML files contains no version attribute
* on the 'osm' element or if the version is unknown.
*/
struct format_version_error : public io_error { struct format_version_error : public io_error {
std::string version; std::string version;
@ -434,6 +446,8 @@ namespace osmium {
if (m_header.get("version") == "") { if (m_header.get("version") == "") {
throw osmium::format_version_error(); throw osmium::format_version_error();
} }
} else {
throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
} }
m_context = context::top; m_context = context::top;
break; break;

View File

@ -260,7 +260,7 @@ namespace osmium {
// m_input->read() can return an invalid buffer to signal EOF, // m_input->read() can return an invalid buffer to signal EOF,
// or a valid buffer with or without data. A valid buffer // or a valid buffer with or without data. A valid buffer
// without data is not an error, it just means we have to get // without data is not an error, it just means we have to
// keep getting the next buffer until there is one with data. // keep getting the next buffer until there is one with data.
while (true) { while (true) {
osmium::memory::Buffer buffer = m_input->read(); osmium::memory::Buffer buffer = m_input->read();

View File

@ -55,8 +55,7 @@ namespace osmium {
template <typename T> template <typename T>
inline T padded_length(T length) noexcept { inline T padded_length(T length) noexcept {
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
"Template parameter must be unsigned integral type");
return (length + align_bytes - 1) & ~(align_bytes - 1); return (length + align_bytes - 1) & ~(align_bytes - 1);
} }

View File

@ -53,12 +53,14 @@ namespace osmium {
/** /**
* An outer ring of an Area. * An outer ring of an Area.
*/ */
class OuterRing : public NodeRefList<osmium::item_type::outer_ring> { class OuterRing : public NodeRefList {
public: public:
static constexpr osmium::item_type itemtype = osmium::item_type::outer_ring;
OuterRing(): OuterRing():
NodeRefList<osmium::item_type::outer_ring>() { NodeRefList(itemtype) {
} }
}; // class OuterRing }; // class OuterRing
@ -68,12 +70,14 @@ namespace osmium {
/** /**
* An inner ring of an Area. * An inner ring of an Area.
*/ */
class InnerRing : public NodeRefList<osmium::item_type::inner_ring> { class InnerRing : public NodeRefList {
public: public:
static constexpr osmium::item_type itemtype = osmium::item_type::inner_ring;
InnerRing(): InnerRing():
NodeRefList<osmium::item_type::inner_ring>() { NodeRefList(itemtype) {
} }
}; // class InnerRing }; // class InnerRing
@ -87,7 +91,7 @@ namespace osmium {
* @param type Type of object (way or relation) * @param type Type of object (way or relation)
* @returns Area id * @returns Area id
*/ */
inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) { inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) noexcept {
osmium::object_id_type area_id = std::abs(id) * 2; osmium::object_id_type area_id = std::abs(id) * 2;
if (type == osmium::item_type::relation) { if (type == osmium::item_type::relation) {
++area_id; ++area_id;
@ -101,7 +105,7 @@ namespace osmium {
* @param id Area id * @param id Area id
* @returns Way or Relation id. * @returns Way or Relation id.
*/ */
inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) { inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) noexcept {
return id / 2; return id / 2;
} }
@ -131,15 +135,17 @@ namespace osmium {
/** /**
* Return the Id of the way or relation this area was created from. * Return the Id of the way or relation this area was created from.
*/ */
osmium::object_id_type orig_id() const { osmium::object_id_type orig_id() const noexcept {
return osmium::area_id_to_object_id(id()); return osmium::area_id_to_object_id(id());
} }
/** /**
* Count the number of outer and inner rings of this area. * Count the number of outer and inner rings of this area.
*
* @returns Pair (number outer rings, number inner rings)
*/ */
std::pair<int, int> num_rings() const { std::pair<int, int> num_rings() const {
std::pair<int, int> counter; std::pair<int, int> counter { 0, 0 };
for (auto it = cbegin(); it != cend(); ++it) { for (auto it = cbegin(); it != cend(); ++it) {
switch (it->type()) { switch (it->type()) {
@ -170,16 +176,31 @@ namespace osmium {
} }
/** /**
* Is this area a multipolygon, ie. has it more than one outer ring? * Check whether this area is a multipolygon, ie. whether it has more
* than one outer ring?
*/ */
bool is_multipolygon() const { bool is_multipolygon() const {
return num_rings().first > 1; return num_rings().first > 1;
} }
/**
* 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::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return it.cast<const osmium::InnerRing>(); return it.cast<const osmium::InnerRing>();
} }
/**
* 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::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 std::next(it).cast<const osmium::InnerRing>();
} }

View File

@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert>
#include <iosfwd> #include <iosfwd>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
@ -41,7 +42,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/** /**
* Bounding box. * Bounding box. A box is defined by two locations (bottom left location
* and top right location) or, alternatively by four coordinates (minx,
* miny, maxx, and maxy). If both locations are undefined, the box is
* undefined, too.
*/ */
class Box { class Box {
@ -59,14 +63,33 @@ namespace osmium {
m_top_right() { m_top_right() {
} }
/**
* Create box from minimum and maximum coordinates.
*
* @pre @code minx <= maxx && miny <= maxy @endcode
*/
Box(double minx, double miny, double maxx, double maxy) : Box(double minx, double miny, double maxx, double maxy) :
m_bottom_left(minx, miny), m_bottom_left(minx, miny),
m_top_right(maxx, maxy) { m_top_right(maxx, maxy) {
assert(minx <= maxx && miny <= maxy);
} }
/**
* Create box from bottom left and top right locations.
*
* @pre Either both locations must be defined or neither.
* @pre If both locations are defined, the
* bottom left location must actually be to the left and below
* the top right location. Same coordinates for bottom/top or
* left/right are also okay.
*/
Box(const osmium::Location& bottom_left, const osmium::Location& top_right) : Box(const osmium::Location& bottom_left, const osmium::Location& top_right) :
m_bottom_left(bottom_left), m_bottom_left(bottom_left),
m_top_right(top_right) { m_top_right(top_right) {
assert(
(!!bottom_left && !!top_right) ||
(bottom_left.x() <= top_right.x() && bottom_left.y() <= top_right.y())
);
} }
Box(const Box&) = default; Box(const Box&) = default;
@ -76,8 +99,13 @@ namespace osmium {
~Box() = default; ~Box() = default;
/** /**
* Extend this bounding box by the given location. If the * Extend this bounding box by the specified location. If the
* location is undefined, the bounding box is unchanged. * location is undefined, the bounding box is unchanged. If
* the box is undefined it will only contain the location after
* this call.
*
* @param location The location we want to extend the box by.
* @returns A reference to this box.
*/ */
Box& extend(const Location& location) noexcept { Box& extend(const Location& location) noexcept {
if (location) { if (location) {
@ -103,8 +131,11 @@ namespace osmium {
} }
/** /**
* Extend this bounding box by the given box. If the * Extend this bounding box by the specified box. If the
* box is undefined, the bounding box is unchanged. * specified box is undefined, the bounding box is unchanged.
*
* @param box The box to extend by.
* @returns A reference to this box.
*/ */
Box& extend(const Box& box) noexcept { Box& extend(const Box& box) noexcept {
extend(box.bottom_left()); extend(box.bottom_left());
@ -113,14 +144,14 @@ namespace osmium {
} }
/** /**
* Box are defined, ie. contains defined coordinates. * Box is defined, ie. contains defined locations.
*/ */
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {
return static_cast<bool>(m_bottom_left); return static_cast<bool>(m_bottom_left);
} }
/** /**
* Box are valid, ie. defined and inside usual bounds * Box is valid, ie. defined and inside usual bounds
* (-180<=lon<=180, -90<=lat<=90). * (-180<=lon<=180, -90<=lat<=90).
*/ */
OSMIUM_CONSTEXPR bool valid() const noexcept { OSMIUM_CONSTEXPR bool valid() const noexcept {
@ -128,37 +159,43 @@ namespace osmium {
} }
/** /**
* Bottom-left location. * Access bottom-left location.
*/ */
OSMIUM_CONSTEXPR Location bottom_left() const noexcept { OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
return m_bottom_left; return m_bottom_left;
} }
/** /**
* Bottom-left location. * Access bottom-left location.
*/ */
Location& bottom_left() noexcept { Location& bottom_left() noexcept {
return m_bottom_left; return m_bottom_left;
} }
/** /**
* Top-right location. * Access top-right location.
*/ */
OSMIUM_CONSTEXPR Location top_right() const noexcept { OSMIUM_CONSTEXPR Location top_right() const noexcept {
return m_top_right; return m_top_right;
} }
/** /**
* Top-right location. * Access top-right location.
*/ */
Location& top_right() noexcept { Location& top_right() noexcept {
return m_top_right; return m_top_right;
} }
/** /**
* Is the location inside the box? * Check whether the location is inside the box.
*
* @pre Location must be defined.
* @pre Box must be defined.
*/ */
bool contains(const osmium::Location& location) const { bool contains(const osmium::Location& location) const noexcept {
assert(bottom_left());
assert(top_right());
assert(location);
return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() && return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() &&
location.x() <= top_right().x() && location.y() <= top_right().y(); location.x() <= top_right().x() && location.y() <= top_right().y();
} }
@ -166,7 +203,7 @@ namespace osmium {
/** /**
* Calculate size of the box in square degrees. * Calculate size of the box in square degrees.
* *
* @throws osmium::invalid_location unless all coordinates are valid * @throws osmium::invalid_location unless all coordinates are valid.
*/ */
double size() const { double size() const {
return (m_top_right.lon() - m_bottom_left.lon()) * return (m_top_right.lon() - m_bottom_left.lon()) *
@ -176,14 +213,19 @@ namespace osmium {
}; // class Box }; // class Box
/** /**
* Boxes are equal if both locations are equal. * Boxes are equal if both locations are equal. Undefined boxes will
* compare equal.
*/ */
inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept { inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept {
return lhs.bottom_left() == rhs.bottom_left() && lhs.top_right() == rhs.top_right(); return lhs.bottom_left() == rhs.bottom_left() &&
lhs.top_right() == rhs.top_right();
} }
/** /**
* Output a box to a stream. * Output a box to a stream. The format is "(LON, LAT, LON, LAT)" or
* "(undefined)" if the box is undefined.
*
* @returns Reference to basic_ostream given as first parameter.
*/ */
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) {
@ -202,6 +244,7 @@ namespace osmium {
} }
return out; return out;
} }
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OSM_BOX_HPP #endif // OSMIUM_OSM_BOX_HPP

View File

@ -298,8 +298,7 @@ namespace osmium {
}; // class Changeset }; // class Changeset
static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!");
"Class osmium::Changeset has wrong size to be aligned properly!");
/** /**
* Changesets are equal if their IDs are equal. * Changesets are equal if their IDs are equal.

View File

@ -44,51 +44,92 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/** /**
* A vector of NodeRef objects. Usually this is not instatiated directly, * A vector of NodeRef objects. Usually this is not instantiated directly,
* but one of its subclasses are used. * but one of its subclasses are used.
*/ */
template <osmium::item_type TItemType>
class NodeRefList : public osmium::memory::Item { class NodeRefList : public osmium::memory::Item {
public: public:
static constexpr osmium::item_type itemtype = TItemType; NodeRefList(osmium::item_type itemtype) noexcept :
osmium::memory::Item(sizeof(NodeRefList), itemtype) {
NodeRefList() noexcept :
osmium::memory::Item(sizeof(NodeRefList), TItemType) {
} }
/**
* Checks whether the node list is empty.
*/
bool empty() const noexcept { bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size(); return sizeof(NodeRefList) == byte_size();
} }
/**
* Returns the number of nodes in the list.
*/
size_t size() const noexcept { size_t size() const noexcept {
assert((osmium::memory::Item::byte_size() - sizeof(NodeRefList)) % sizeof(NodeRef) == 0); auto size_node_refs = osmium::memory::Item::byte_size() - sizeof(NodeRefList);
return (osmium::memory::Item::byte_size() - sizeof(NodeRefList)) / sizeof(NodeRef); assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef);
} }
const NodeRef& operator[](size_t n) const { /**
* Access specified element.
*
* @param n Get this element of the list.
* @pre @code n < size() @endcode
*/
const NodeRef& operator[](size_t n) const noexcept {
assert(n < size());
const NodeRef* node_ref = &*(cbegin()); const NodeRef* node_ref = &*(cbegin());
return node_ref[n]; return node_ref[n];
} }
const NodeRef& front() const { /**
* Access the first element.
*
* @pre @code !empty() @endcode
*/
const NodeRef& front() const noexcept {
assert(!empty());
return operator[](0); return operator[](0);
} }
const NodeRef& back() const { /**
* Access the last element.
*
* @pre @code !empty() @endcode
*/
const NodeRef& back() const noexcept {
assert(!empty());
return operator[](size()-1); return operator[](size()-1);
} }
bool is_closed() const { /**
* Checks whether the first and last node in the list have the same ID.
*
* @pre @code !empty() @endcode
*/
bool is_closed() const noexcept {
return front().ref() == back().ref(); return front().ref() == back().ref();
} }
bool ends_have_same_id() const { /**
* Checks whether the first and last node in the list have the same ID.
*
* @pre @code !empty() @endcode
*/
bool ends_have_same_id() const noexcept {
return front().ref() == back().ref(); return front().ref() == back().ref();
} }
/**
* Checks whether the first and last node in the list have the same
* location. The ID is not checked.
*
* @pre @code !empty() @endcode
* @pre @code front().location() && back().location() @endcode
*/
bool ends_have_same_location() const { bool ends_have_same_location() const {
assert(front().location() && back().location());
return front().location() == back().location(); return front().location() == back().location();
} }
@ -96,35 +137,43 @@ namespace osmium {
typedef const NodeRef* const_iterator; typedef const NodeRef* const_iterator;
typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator; typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
iterator begin() { /// Returns an iterator to the beginning.
iterator begin() noexcept {
return iterator(data() + sizeof(NodeRefList)); return iterator(data() + sizeof(NodeRefList));
} }
iterator end() { /// Returns an iterator to the end.
iterator end() noexcept {
return iterator(data() + byte_size()); return iterator(data() + byte_size());
} }
const_iterator cbegin() const { /// Returns an iterator to the beginning.
const_iterator cbegin() const noexcept {
return const_iterator(data() + sizeof(NodeRefList)); return const_iterator(data() + sizeof(NodeRefList));
} }
const_iterator cend() const { /// Returns an iterator to the end.
const_iterator cend() const noexcept {
return const_iterator(data() + byte_size()); return const_iterator(data() + byte_size());
} }
const_iterator begin() const { /// Returns an iterator to the beginning.
const_iterator begin() const noexcept {
return cbegin(); return cbegin();
} }
const_iterator end() const { /// Returns an iterator to the end.
const_iterator end() const noexcept {
return cend(); return cend();
} }
const_reverse_iterator crbegin() const { /// Returns a reverse_iterator to the beginning.
const_reverse_iterator crbegin() const noexcept {
return const_reverse_iterator(cend()); return const_reverse_iterator(cend());
} }
const_reverse_iterator crend() const { /// Returns a reverse_iterator to the end.
const_reverse_iterator crend() const noexcept {
return const_reverse_iterator(cbegin()); return const_reverse_iterator(cbegin());
} }

View File

@ -113,6 +113,10 @@ namespace osmium {
return static_cast<time_t>(m_timestamp); return static_cast<time_t>(m_timestamp);
} }
explicit constexpr operator uint32_t() const noexcept {
return m_timestamp;
}
template <typename T> template <typename T>
void operator+=(T time_difference) noexcept { void operator+=(T time_difference) noexcept {
m_timestamp += time_difference; m_timestamp += time_difference;

View File

@ -49,12 +49,14 @@ namespace osmium {
/** /**
* List of node references (id and location) in a way. * List of node references (id and location) in a way.
*/ */
class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> { class WayNodeList : public NodeRefList {
public: public:
static constexpr osmium::item_type itemtype = osmium::item_type::way_node_list;
WayNodeList(): WayNodeList():
NodeRefList<osmium::item_type::way_node_list>() { NodeRefList(itemtype) {
} }
}; // class WayNodeList }; // class WayNodeList

View File

@ -49,7 +49,7 @@ namespace osmium {
namespace thread { namespace thread {
OSMIUM_CONSTEXPR std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
/** /**
* A thread-safe queue. * A thread-safe queue.

View File

@ -37,6 +37,7 @@ DEALINGS IN THE SOFTWARE.
# include <cassert> # include <cassert>
#endif #endif
#include <cstdint>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
@ -93,7 +94,7 @@ namespace osmium {
template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0> template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0>
inline T static_cast_with_assert(const F value) { inline T static_cast_with_assert(const F value) {
assert(value <= std::numeric_limits<T>::max()); assert(static_cast<int64_t>(value) <= static_cast<int64_t>(std::numeric_limits<T>::max()));
return static_cast<T>(value); return static_cast<T>(value);
} }

View File

@ -8,6 +8,7 @@
message(STATUS "Configuring unit tests") message(STATUS "Configuring unit tests")
include(CMakeParseArguments)
include_directories(include) include_directories(include)
add_library(testlib STATIC test_main.cpp) add_library(testlib STATIC test_main.cpp)
@ -19,40 +20,62 @@ set(ALL_TESTS "")
# #
# Define function for adding tests # Define function for adding tests
# #
# Call with parameters: # add_unit_tests(group name [ENABLE_IF bool] [LIBS libs] [LABELS labels])
# TGROUP - test group (directory) #
# TNAME - name of test # group - test group (directory)
# ARGV2 - flag to enable test (optional) # name - name of test
# ARGV3 - libraries to add (optional) # bool - boolean variable telling whether the test should be run (optional)
# libs - lib or libs that should be used when compiling test (optional)
# labels - additional labels this test should get (optional)
# #
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
function(add_unit_test TGROUP TNAME) function(add_unit_test _tgroup _tname)
set(ALL_TESTS "${ALL_TESTS};${TGROUP}/${TNAME}" PARENT_SCOPE) set(_testid "${_tgroup}_${_tname}")
if((${ARGC} EQUAL 2) OR (${ARGV2})) set(_tpath "${_tgroup}/${_tname}")
set(ALL_TESTS "${ALL_TESTS};${_tpath}" PARENT_SCOPE)
cmake_parse_arguments(_param "" "ENABLE_IF" "LIBS;LABELS" ${ARGN})
if(Osmium_DEBUG) if(Osmium_DEBUG)
message("Adding test ${TGROUP}/${TNAME}") message("${_testid} ENABLE_IF=[${_param_ENABLE_IF}] LIBS=[${_param_LIBS}] LABELS=[${_param_LABELS}]")
endif() endif()
set(TESTNAME "${TGROUP}_${TNAME}")
add_executable(${TESTNAME} t/${TGROUP}/${TNAME}.cpp) if((NOT(DEFINED _param_ENABLE_IF)) OR (_param_ENABLE_IF))
target_link_libraries(${TESTNAME} testlib)
if((${ARGV2}) AND (DEFINED ARGV3))
if(Osmium_DEBUG) if(Osmium_DEBUG)
message(" Adding libs ${ARGV3}") message("Adding test: ${_tpath}")
endif() endif()
target_link_libraries(${TESTNAME} ${ARGV3}) add_executable(${_testid} t/${_tpath}.cpp)
target_link_libraries(${_testid} testlib)
if(DEFINED _param_LIBS)
if(Osmium_DEBUG)
message(" Adding libs: ${_param_LIBS}")
endif() endif()
add_test(NAME ${TESTNAME} target_link_libraries(${_testid} ${_param_LIBS})
endif()
add_test(NAME ${_testid}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${TESTNAME} COMMAND ${_testid}
) )
set_tests_properties(${TESTNAME} PROPERTIES
LABELS "unit;fast;${TGROUP}" set(_labels "unit;fast;${_tgroup}")
if(DEFINED _param_LABELS)
if(Osmium_DEBUG)
message(" Adding labels: ${_param_LABELS}")
endif()
set(_labels "${_labels};${_param_LABELS}")
endif()
set_tests_properties(${_testid} PROPERTIES
LABELS "${_labels}"
ENVIRONMENT "OSMIUM_TEST_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}" ENVIRONMENT "OSMIUM_TEST_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
) )
else() else()
message("Skipped test ${TGROUP}/${TNAME} because a dependency was not found") message("Skipped test ${_tpath} because a dependency was not found")
set(OSMIUM_SKIPPED_TESTS set(OSMIUM_SKIPPED_TESTS
"${OSMIUM_SKIPPED_TESTS} ${TGROUP}/${TNAME}" "${OSMIUM_SKIPPED_TESTS} ${_tpath}"
CACHE STRING "Tests that were skipped because of missing dependecies") CACHE STRING "Tests that were skipped because of missing dependecies")
endif() endif()
endfunction() endfunction()
@ -85,31 +108,32 @@ else()
set(GEOS_AND_PROJ_FOUND FALSE) set(GEOS_AND_PROJ_FOUND FALSE)
endif() endif()
add_unit_test(geom test_factory_with_projection add_unit_test(geom test_factory_with_projection
${GEOS_AND_PROJ_FOUND} ENABLE_IF ${GEOS_AND_PROJ_FOUND}
"${GEOS_LIBRARY};${PROJ_LIBRARY}") LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
add_unit_test(geom test_geojson) add_unit_test(geom test_geojson)
add_unit_test(geom test_geos ${GEOS_FOUND} ${GEOS_LIBRARY}) add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
add_unit_test(geom test_geos_wkb ${GEOS_FOUND} ${GEOS_LIBRARY}) add_unit_test(geom test_geos_wkb ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
add_unit_test(geom test_mercator) add_unit_test(geom test_mercator)
add_unit_test(geom test_ogr ${GDAL_FOUND} ${GDAL_LIBRARY}) add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
add_unit_test(geom test_projection ${PROJ_FOUND} ${PROJ_LIBRARY}) add_unit_test(geom test_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_wkb) add_unit_test(geom test_wkb)
add_unit_test(geom test_wkt) add_unit_test(geom test_wkt)
add_unit_test(index test_id_to_location ${SPARSEHASH_FOUND}) add_unit_test(index test_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
add_unit_test(index test_typed_mmap) add_unit_test(index test_typed_mmap)
add_unit_test(index test_typed_mmap_grow LABELS "fails_on_windows")
add_unit_test(io test_bzip2 ${BZIP2_FOUND} ${BZIP2_LIBRARIES}) add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
add_unit_test(io test_file_formats) add_unit_test(io test_file_formats)
add_unit_test(io test_reader TRUE "${OSMIUM_XML_LIBRARIES}") add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES}")
add_unit_test(io test_output_iterator ${Threads_FOUND} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test(io test_output_iterator ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(tags test_filter) add_unit_test(tags test_filter)
add_unit_test(tags test_operators) add_unit_test(tags test_operators)
add_unit_test(tags test_tag_list) add_unit_test(tags test_tag_list)
add_unit_test(thread test_pool ${Threads_FOUND} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test(thread test_pool ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(util test_cast_with_assert) add_unit_test(util test_cast_with_assert)
add_unit_test(util test_double) add_unit_test(util test_double)

View File

@ -285,7 +285,6 @@ TEST_CASE("Reading OSM XML 121") {
}, osmium::gzip_error); }, osmium::gzip_error);
} }
#if 0
SECTION("Using Reader") { SECTION("Using Reader") {
REQUIRE_THROWS_AS({ REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("121-truncated_gzip_file", "osm.gz")); osmium::io::Reader reader(filename("121-truncated_gzip_file", "osm.gz"));
@ -294,10 +293,105 @@ TEST_CASE("Reading OSM XML 121") {
reader.close(); reader.close();
}, osmium::gzip_error); }, osmium::gzip_error);
} }
#endif
} }
// =============================================
TEST_CASE("Reading OSM XML 122") {
SECTION("Direct") {
REQUIRE_THROWS_AS( {
read_xml("122-no_osm_element");
}, osmium::xml_error);
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
osmium::io::Reader reader(filename("122-no_osm_element"));
osmium::io::Header header = reader.header();
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
}
}
// =============================================
TEST_CASE("Reading OSM XML 140") {
SECTION("Using Reader") {
osmium::io::Reader reader(filename("140-unicode"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
int count = 0;
for (auto it = buffer.begin<osmium::Node>(); it != buffer.end<osmium::Node>(); ++it) {
++count;
REQUIRE(it->id() == count);
const osmium::TagList& t = it->tags();
const char* uc = t["unicode_char"];
auto len = atoi(t["unicode_utf8_length"]);
REQUIRE(len == strlen(uc));
REQUIRE(!strcmp(uc, t["unicode_xml"]));
// workaround for missing support for u8 string literals on Windows
#if !defined(_MSC_VER)
switch (count) {
case 1:
REQUIRE(!strcmp(uc, u8"a"));
break;
case 2:
REQUIRE(!strcmp(uc, u8"\u00e4"));
break;
case 3:
REQUIRE(!strcmp(uc, u8"\u30dc"));
break;
case 4:
REQUIRE(!strcmp(uc, u8"\U0001d11e"));
break;
case 5:
REQUIRE(!strcmp(uc, u8"\U0001f6eb"));
break;
default:
REQUIRE(false); // should not be here
}
#endif
}
REQUIRE(count == 5);
}
}
// =============================================
TEST_CASE("Reading OSM XML 141") {
SECTION("Using Reader") {
osmium::io::Reader reader(filename("141-entities"));
osmium::memory::Buffer buffer = reader.read();
reader.close();
REQUIRE(buffer.committed() > 0);
REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
const osmium::Node& node = buffer.get<osmium::Node>(0);
const osmium::TagList& tags = node.tags();
REQUIRE(!strcmp(tags["less-than"], "<"));
REQUIRE(!strcmp(tags["greater-than"], ">"));
REQUIRE(!strcmp(tags["apostrophe"], "'"));
REQUIRE(!strcmp(tags["ampersand"], "&"));
REQUIRE(!strcmp(tags["quote"], "\""));
}
}
// ============================================= // =============================================
TEST_CASE("Reading OSM XML 200") { TEST_CASE("Reading OSM XML 200") {

View File

@ -25,12 +25,18 @@ SECTION("instantiation_and_extend_with_undefined") {
SECTION("instantiation_and_extend") { SECTION("instantiation_and_extend") {
osmium::Box b; osmium::Box b;
b.extend(osmium::Location(1.2, 3.4)); osmium::Location loc1 { 1.2, 3.4 };
b.extend(loc1);
REQUIRE(!!b); REQUIRE(!!b);
REQUIRE(!!b.bottom_left()); REQUIRE(!!b.bottom_left());
REQUIRE(!!b.top_right()); REQUIRE(!!b.top_right());
b.extend(osmium::Location(3.4, 4.5)); REQUIRE(b.contains(loc1));
b.extend(osmium::Location(5.6, 7.8));
osmium::Location loc2 { 3.4, 4.5 };
osmium::Location loc3 { 5.6, 7.8 };
b.extend(loc2);
b.extend(loc3);
REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4)); REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
REQUIRE(b.top_right() == osmium::Location(5.6, 7.8)); REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
@ -38,6 +44,10 @@ SECTION("instantiation_and_extend") {
b.extend(osmium::Location()); b.extend(osmium::Location());
REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4)); REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
REQUIRE(b.top_right() == osmium::Location(5.6, 7.8)); REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
REQUIRE(b.contains(loc1));
REQUIRE(b.contains(loc2));
REQUIRE(b.contains(loc3));
} }
SECTION("output_defined") { SECTION("output_defined") {

View File

@ -29,6 +29,19 @@ SECTION("can be initialized from string") {
REQUIRE("2000-01-01T00:00:00Z" == t.to_iso()); REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
} }
SECTION("can be implicitly cast to time_t") {
osmium::Timestamp t(4242);
time_t x = t;
REQUIRE(x == 4242);
}
SECTION("uint32_t can be initialized from Timestamp") {
osmium::Timestamp t(4242);
uint32_t x { t };
REQUIRE(x == 4242);
}
SECTION("can be compared") { SECTION("can be compared") {
osmium::Timestamp t1(10); osmium::Timestamp t1(10);
osmium::Timestamp t2(50); osmium::Timestamp t2(50);

View File

@ -73,27 +73,4 @@ SECTION("FileSize") {
REQUIRE(0 == unlink(filename)); REQUIRE(0 == unlink(filename));
} }
SECTION("GrowAndMap") {
const int size = 100;
char filename[] = "test_mmap_grow_and_map_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
uint64_t* data = osmium::detail::typed_mmap<uint64_t>::grow_and_map(size, fd);
REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
data[0] = 1ul;
data[1] = 8ul;
data[99] = 27ul;
REQUIRE(1ul == data[0]);
REQUIRE(8ul == data[1]);
REQUIRE(27ul == data[99]);
osmium::detail::typed_mmap<uint64_t>::unmap(data, size);
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
} }

View File

@ -0,0 +1,34 @@
#include "catch.hpp"
#include <osmium/index/detail/typed_mmap.hpp>
#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32))
#include "win_mkstemp.hpp"
#endif
TEST_CASE("TypedMmapGrow") {
SECTION("GrowAndMap") {
const int size = 100;
char filename[] = "test_mmap_grow_and_map_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
uint64_t* data = osmium::detail::typed_mmap<uint64_t>::grow_and_map(size, fd);
REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
data[0] = 1ul;
data[1] = 8ul;
data[99] = 27ul;
REQUIRE(1ul == data[0]);
REQUIRE(8ul == data[1]);
REQUIRE(27ul == data[99]);
osmium::detail::typed_mmap<uint64_t>::unmap(data, size);
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
}