Merge commit '6eb4f090f98f6b17a23c57768c16b7716b6c9cbd' as 'third_party/libosmium'
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
#ifndef OSMIUM_UTIL_CAST_HPP
|
||||
#define OSMIUM_UTIL_CAST_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef assert
|
||||
# include <cassert>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
// These functions are wrappers around static_cast<>() that call assert()
|
||||
// to check that there is no integer overflow happening before doing the
|
||||
// cast. There are several versions of this templated function here
|
||||
// depending on the types of the input and output. In any case, both input
|
||||
// and output have to be integral types. If the cast can't overflow, no
|
||||
// check is done.
|
||||
|
||||
template <typename A, typename B>
|
||||
struct are_real_integers :
|
||||
std::integral_constant<bool,
|
||||
std::is_integral<A>::value &&
|
||||
std::is_integral<B>::value &&
|
||||
!std::is_same<A, bool>::value &&
|
||||
!std::is_same<B, bool>::value> {
|
||||
};
|
||||
|
||||
template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && std::is_same<T, F>::value, int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
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)), int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && std::is_signed<T>::value == std::is_signed<F>::value && (sizeof(T) == sizeof(F)), int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
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_signed<F>::value, int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
assert(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
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_unsigned<T>::value && std::is_signed<F>::value, int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
assert(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
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_unsigned<T>::value && std::is_unsigned<F>::value, int>::type = 0>
|
||||
inline T static_cast_with_assert(const F value) {
|
||||
assert(value <= std::numeric_limits<T>::max());
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
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) {
|
||||
assert(static_cast<int64_t>(value) <= static_cast<int64_t>(std::numeric_limits<T>::max()));
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_CAST_HPP
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef OSMIUM_UTIL_COMPATIBILITY_HPP
|
||||
#define OSMIUM_UTIL_COMPATIBILITY_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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.
|
||||
|
||||
*/
|
||||
|
||||
// Workarounds for MSVC which doesn't support
|
||||
// * [[noreturn]]
|
||||
#ifdef _MSC_VER
|
||||
# define OSMIUM_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
# define OSMIUM_NORETURN [[noreturn]]
|
||||
#endif
|
||||
|
||||
// [[deprecated]] is only available in C++14, use this for the time being
|
||||
#ifdef __GNUC__
|
||||
# define OSMIUM_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
# define OSMIUM_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
# define OSMIUM_DEPRECATED
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_UTIL_COMPATIBILITY_HPP
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef OSMIUM_UTIL_CONFIG_HPP
|
||||
#define OSMIUM_UTIL_CONFIG_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace config {
|
||||
|
||||
inline int get_pool_threads() noexcept {
|
||||
const char* env = getenv("OSMIUM_POOL_THREADS");
|
||||
if (env) {
|
||||
return std::atoi(env);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool use_pool_threads_for_pbf_parsing() noexcept {
|
||||
const char* env = getenv("OSMIUM_USE_POOL_THREADS_FOR_PBF_PARSING");
|
||||
if (env) {
|
||||
if (!strcasecmp(env, "off") ||
|
||||
!strcasecmp(env, "false") ||
|
||||
!strcasecmp(env, "no") ||
|
||||
!strcasecmp(env, "0")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::size_t get_max_queue_size(const char* queue_name, std::size_t default_value) noexcept {
|
||||
assert(queue_name);
|
||||
std::string name{"OSMIUM_MAX_"};
|
||||
name += queue_name;
|
||||
name += "_QUEUE_SIZE";
|
||||
const char* env = getenv(name.c_str());
|
||||
if (env) {
|
||||
auto value = std::atoi(env);
|
||||
return value == 0 ? default_value : value;
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
} // namespace config
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_CONFIG_HPP
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
#ifndef OSMIUM_UTIL_DELTA_HPP
|
||||
#define OSMIUM_UTIL_DELTA_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/util/cast.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Helper class for delta encoding.
|
||||
*/
|
||||
template <typename TValue, typename TDelta = int64_t>
|
||||
class DeltaEncode {
|
||||
|
||||
static_assert(std::is_integral<TValue>::value,
|
||||
"DeltaEncode value type must be some integer");
|
||||
|
||||
static_assert(std::is_integral<TDelta>::value && std::is_signed<TDelta>::value,
|
||||
"DeltaEncode delta type must be some signed integer");
|
||||
|
||||
TValue m_value;
|
||||
|
||||
public:
|
||||
|
||||
using value_type = TValue;
|
||||
using delta_type = TDelta;
|
||||
|
||||
explicit DeltaEncode(TValue value = 0) :
|
||||
m_value(value) {
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
TValue value() const noexcept {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
TDelta update(TValue new_value) noexcept {
|
||||
using std::swap;
|
||||
swap(m_value, new_value);
|
||||
return static_cast_with_assert<TDelta>(m_value) -
|
||||
static_cast_with_assert<TDelta>(new_value);
|
||||
}
|
||||
|
||||
}; // class DeltaEncode
|
||||
|
||||
/**
|
||||
* Helper class for delta decoding.
|
||||
*/
|
||||
template <typename TValue, typename TDelta = int64_t>
|
||||
class DeltaDecode {
|
||||
|
||||
static_assert(std::is_integral<TValue>::value,
|
||||
"DeltaDecode value type must be some integer");
|
||||
|
||||
static_assert(std::is_integral<TDelta>::value && std::is_signed<TDelta>::value,
|
||||
"DeltaDecode delta type must be some signed integer");
|
||||
|
||||
TValue m_value;
|
||||
|
||||
public:
|
||||
|
||||
using value_type = TValue;
|
||||
using delta_type = TDelta;
|
||||
|
||||
DeltaDecode() :
|
||||
m_value(0) {
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
TValue update(TDelta delta) noexcept {
|
||||
m_value = static_cast_with_assert<TValue>(
|
||||
static_cast_with_assert<TDelta>(m_value) + delta);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
}; // class DeltaDecode
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_DELTA_HPP
|
||||
@@ -0,0 +1,96 @@
|
||||
#ifndef OSMIUM_UTIL_DOUBLE_HPP
|
||||
#define OSMIUM_UTIL_DOUBLE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
constexpr const int max_double_length = 20; // should fit any double
|
||||
|
||||
/**
|
||||
* Write double to iterator, removing superfluous '0' characters at
|
||||
* the end. The decimal dot will also be removed if necessary.
|
||||
*
|
||||
* @tparam T iterator type
|
||||
* @param iterator output iterator
|
||||
* @param value the value that should be written
|
||||
* @param precision max number of digits after the decimal point (must be <= 17)
|
||||
*/
|
||||
template <typename T>
|
||||
inline T double2string(T iterator, double value, int precision) {
|
||||
assert(precision <= 17);
|
||||
|
||||
char buffer[max_double_length];
|
||||
|
||||
#ifndef _MSC_VER
|
||||
int len = snprintf(buffer, max_double_length, "%.*f", precision, value);
|
||||
#else
|
||||
int len = _snprintf(buffer, max_double_length, "%.*f", precision, value);
|
||||
#endif
|
||||
assert(len > 0 && len < max_double_length);
|
||||
|
||||
while (buffer[len - 1] == '0') {
|
||||
--len;
|
||||
}
|
||||
if (buffer[len - 1] == '.') {
|
||||
--len;
|
||||
}
|
||||
|
||||
return std::copy_n(buffer, len, iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write double to string, removing superfluous '0' characters at
|
||||
* the end. The decimal dot will also be removed if necessary.
|
||||
*
|
||||
* @param out string
|
||||
* @param value the value that should be written
|
||||
* @param precision max number of digits after the decimal point
|
||||
*/
|
||||
inline void double2string(std::string& out, double value, int precision) {
|
||||
double2string(std::back_inserter(out), value, precision);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_DOUBLE_HPP
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef OSMIUM_UTIL_ENDIAN_HPP
|
||||
#define OSMIUM_UTIL_ENDIAN_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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.
|
||||
|
||||
*/
|
||||
|
||||
// Windows is only available for little endian architectures
|
||||
// http://stackoverflow.com/questions/6449468/can-i-safely-assume-that-windows-installations-will-always-be-little-endian
|
||||
#if defined(__FreeBSD__)
|
||||
# include <sys/endian.h>
|
||||
#elif !defined(_WIN32) && !defined(__APPLE__)
|
||||
# include <endian.h>
|
||||
#else
|
||||
# define __LITTLE_ENDIAN 1234
|
||||
# define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_UTIL_ENDIAN_HPP
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
#ifndef OSMIUM_UTIL_FILE_HPP
|
||||
#define OSMIUM_UTIL_FILE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN // Prevent winsock.h inclusion; avoid winsock2.h conflict
|
||||
# endif
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
# include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <osmium/util/cast.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace detail {
|
||||
|
||||
// Disable parameter validation on Windows and reenable it
|
||||
// automatically when scope closes.
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation
|
||||
class disable_invalid_parameter_handler {
|
||||
|
||||
static void invalid_parameter_handler(
|
||||
const wchar_t* expression,
|
||||
const wchar_t* function,
|
||||
const wchar_t* file,
|
||||
unsigned int line,
|
||||
uintptr_t pReserved
|
||||
) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
_invalid_parameter_handler old_handler;
|
||||
int old_report_mode;
|
||||
|
||||
public:
|
||||
|
||||
disable_invalid_parameter_handler() :
|
||||
old_handler(_set_thread_local_invalid_parameter_handler(invalid_parameter_handler)),
|
||||
old_report_mode(_CrtSetReportMode(_CRT_ASSERT, 0)) {
|
||||
}
|
||||
|
||||
~disable_invalid_parameter_handler() {
|
||||
_CrtSetReportMode(_CRT_ASSERT, old_report_mode);
|
||||
_set_thread_local_invalid_parameter_handler(old_handler);
|
||||
}
|
||||
|
||||
}; // class disable_invalid_parameter_handler
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get file size.
|
||||
* This is a small wrapper around a system call.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @returns file size
|
||||
* @throws std::system_error If system call failed
|
||||
*/
|
||||
inline std::size_t file_size(int fd) {
|
||||
#ifdef _MSC_VER
|
||||
// Windows implementation
|
||||
detail::disable_invalid_parameter_handler diph;
|
||||
// https://msdn.microsoft.com/en-us/library/dfbc2kec.aspx
|
||||
const auto size = ::_filelengthi64(fd);
|
||||
if (size < 0) {
|
||||
throw std::system_error{errno, std::system_category(), "Could not get file size"};
|
||||
}
|
||||
return static_cast<std::size_t>(size);
|
||||
#else
|
||||
// Unix implementation
|
||||
struct stat s;
|
||||
if (::fstat(fd, &s) != 0) {
|
||||
throw std::system_error{errno, std::system_category(), "Could not get file size"};
|
||||
}
|
||||
return static_cast<std::size_t>(s.st_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size.
|
||||
* This is a small wrapper around a system call.
|
||||
*
|
||||
* @param name File name
|
||||
* @returns file size
|
||||
* @throws std::system_error If system call failed
|
||||
* @pre name must not be nullptr
|
||||
*/
|
||||
inline std::size_t file_size(const char* name) {
|
||||
#ifdef _MSC_VER
|
||||
// Windows implementation
|
||||
// https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
|
||||
struct _stat64 s;
|
||||
if (::_stati64(name, &s) != 0) {
|
||||
throw std::system_error{errno, std::system_category(), std::string{"Could not get file size of file '"} + name + "'"};
|
||||
}
|
||||
#else
|
||||
// Unix implementation
|
||||
struct stat s;
|
||||
if (::stat(name, &s) != 0) {
|
||||
throw std::system_error{errno, std::system_category(), std::string{"Could not get file size of file '"} + name + "'"};
|
||||
}
|
||||
#endif
|
||||
return static_cast<std::size_t>(s.st_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size.
|
||||
* This is a small wrapper around a system call.
|
||||
*
|
||||
* @param name File name
|
||||
* @returns file size
|
||||
* @throws std::system_error If system call failed
|
||||
*/
|
||||
inline std::size_t file_size(const std::string& name) {
|
||||
return file_size(name.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize file.
|
||||
* Small wrapper around ftruncate(2) system call.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @param new_size New size
|
||||
* @throws std::system_error If ftruncate(2) call failed
|
||||
*/
|
||||
inline void resize_file(int fd, std::size_t new_size) {
|
||||
#ifdef _WIN32
|
||||
detail::disable_invalid_parameter_handler diph;
|
||||
// https://msdn.microsoft.com/en-us/library/whx354w1.aspx
|
||||
if (::_chsize_s(fd, static_cast_with_assert<__int64>(new_size)) != 0) {
|
||||
#else
|
||||
if (::ftruncate(fd, static_cast_with_assert<off_t>(new_size)) != 0) {
|
||||
#endif
|
||||
throw std::system_error{errno, std::system_category(), "Could not resize file"};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the page size for this system.
|
||||
*/
|
||||
inline std::size_t get_pagesize() {
|
||||
#ifdef _WIN32
|
||||
// Windows implementation
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
// Unix implementation
|
||||
return static_cast<std::size_t>(::sysconf(_SC_PAGESIZE));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current offset into file.
|
||||
*
|
||||
* @param fd Open file descriptor.
|
||||
* @returns File offset or 0 if it is not available.
|
||||
*/
|
||||
inline std::size_t file_offset(int fd) {
|
||||
#ifdef _MSC_VER
|
||||
detail::disable_invalid_parameter_handler diph;
|
||||
// https://msdn.microsoft.com/en-us/library/1yee101t.aspx
|
||||
const auto offset = _lseeki64(fd, 0, SEEK_CUR);
|
||||
#else
|
||||
const auto offset = ::lseek(fd, 0, SEEK_CUR);
|
||||
#endif
|
||||
if (offset == -1) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<std::size_t>(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the file descriptor refers to a TTY.
|
||||
*/
|
||||
inline bool isatty(int fd) {
|
||||
#ifdef _MSC_VER
|
||||
detail::disable_invalid_parameter_handler diph;
|
||||
// https://msdn.microsoft.com/en-us/library/f4s0ddew.aspx
|
||||
return _isatty(fd) != 0;
|
||||
#else
|
||||
return ::isatty(fd) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_FILE_HPP
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef OSMIUM_UTIL_ITERATOR_HPP
|
||||
#define OSMIUM_UTIL_ITERATOR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
template <typename It, typename P = std::pair<It, It>>
|
||||
struct iterator_range : public P {
|
||||
|
||||
using iterator = It;
|
||||
|
||||
explicit iterator_range(P&& p) noexcept :
|
||||
P(std::forward<P>(p)) {
|
||||
}
|
||||
|
||||
It begin() const noexcept {
|
||||
return this->first;
|
||||
}
|
||||
|
||||
It end() const noexcept {
|
||||
return this->second;
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return begin() == end();
|
||||
}
|
||||
|
||||
}; // struct iterator_range
|
||||
|
||||
/**
|
||||
* Helper function to create iterator_range from std::pair.
|
||||
*/
|
||||
template <typename P, typename It = typename P::first_type>
|
||||
inline iterator_range<It> make_range(P&& p) noexcept {
|
||||
static_assert(std::is_same<P, std::pair<It, It>>::value, "make_range needs pair of iterators as argument");
|
||||
return iterator_range<It>{std::forward<P>(p)};
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_ITERATOR_HPP
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef OSMIUM_UTIL_MEMORY_HPP
|
||||
#define OSMIUM_UTIL_MEMORY_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class MemoryUsage {
|
||||
|
||||
int m_current = 0;
|
||||
int m_peak = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
static int parse_number(const std::string& line) {
|
||||
const auto f = line.find_first_of("0123456789");
|
||||
const auto l = line.find_last_of("0123456789");
|
||||
return std::atoi(line.substr(f, l - f + 1).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* Get the memory usage for the current process. The constructor will
|
||||
* get the memory usage. Use the current() and peak() calls to access
|
||||
* the result.
|
||||
*
|
||||
* This will only work on Linux, on other architectures this will
|
||||
* always return 0.
|
||||
*/
|
||||
MemoryUsage() {
|
||||
#ifdef __linux__
|
||||
static const char* filename = "/proc/self/status";
|
||||
std::ifstream status_file(filename);
|
||||
|
||||
if (status_file.is_open()) {
|
||||
std::string line;
|
||||
while (!status_file.eof()) {
|
||||
std::getline(status_file, line);
|
||||
if (line.substr(0, 6) == "VmPeak") {
|
||||
m_peak = parse_number(line);
|
||||
}
|
||||
if (line.substr(0, 6) == "VmSize") {
|
||||
m_current = parse_number(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return current memory usage in MBytes
|
||||
int current() const {
|
||||
return m_current / 1024;
|
||||
}
|
||||
|
||||
/// Return peak memory usage in MBytes
|
||||
int peak() const {
|
||||
return m_peak / 1024;
|
||||
}
|
||||
|
||||
}; // class MemoryUsage
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_MEMORY_HPP
|
||||
@@ -0,0 +1,787 @@
|
||||
#ifndef OSMIUM_UTIL_MEMORY_MAPPING_HPP
|
||||
#define OSMIUM_UTIL_MEMORY_MAPPING_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/util/file.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Class for wrapping memory mapping system calls.
|
||||
*
|
||||
* Usage for anonymous mapping:
|
||||
* @code
|
||||
* MemoryMapping mapping(1024); // create anonymous mapping with size
|
||||
* auto ptr = mapping.get_addr<char*>(); // get pointer to memory
|
||||
* mapping.unmap(); // release mapping by calling unmap() (or at end of scope)
|
||||
* @endcode
|
||||
*
|
||||
* Or for file-backed mapping:
|
||||
* @code
|
||||
* int fd = ::open(...);
|
||||
* {
|
||||
* MemoryMapping mapping(1024, MemoryMapping::mapping_mode::write_shared, fd, offset);
|
||||
* // use mapping
|
||||
* }
|
||||
* ::close(fd);
|
||||
* @endcode
|
||||
*
|
||||
* If the file backing a file-backed mapping is not large enough, it
|
||||
* will be resized. This works, of course, only for writable files,
|
||||
* so for read-only files you have to make sure they are large enough
|
||||
* for any mapping you want.
|
||||
*
|
||||
* If you ask for a zero-sized mapping, a mapping of the systems page
|
||||
* size will be created instead. For file-backed mapping this will only
|
||||
* work if the file is writable.
|
||||
*
|
||||
* There are different implementations for Unix and Windows systems.
|
||||
* On Unix systems this wraps the mmap(), munmap(), and the mremap()
|
||||
* system calls. On Windows it wraps the CreateFileMapping(),
|
||||
* CloseHandle(), MapViewOfFile(), and UnmapViewOfFile() functions.
|
||||
*
|
||||
* On Windows the file will be set to binary mode before the memory
|
||||
* mapping.
|
||||
*/
|
||||
class MemoryMapping {
|
||||
|
||||
public:
|
||||
|
||||
enum class mapping_mode {
|
||||
readonly = 0,
|
||||
write_private = 1,
|
||||
write_shared = 2
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/// The size of the mapping
|
||||
std::size_t m_size;
|
||||
|
||||
/// Offset into the file
|
||||
off_t m_offset;
|
||||
|
||||
/// File handle we got the mapping from
|
||||
int m_fd;
|
||||
|
||||
/// Mapping mode
|
||||
mapping_mode m_mapping_mode;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE m_handle;
|
||||
#endif
|
||||
|
||||
/// The address where the memory is mapped
|
||||
void* m_addr;
|
||||
|
||||
bool is_valid() const noexcept;
|
||||
|
||||
void make_invalid() noexcept;
|
||||
|
||||
#ifdef _WIN32
|
||||
using flag_type = DWORD;
|
||||
#else
|
||||
using flag_type = int;
|
||||
#endif
|
||||
|
||||
flag_type get_protection() const noexcept;
|
||||
|
||||
flag_type get_flags() const noexcept;
|
||||
|
||||
static std::size_t check_size(std::size_t size) {
|
||||
if (size == 0) {
|
||||
return osmium::util::get_pagesize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE get_handle() const noexcept;
|
||||
HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept;
|
||||
void* osmium::util::MemoryMapping::map_view_of_file() const noexcept;
|
||||
#endif
|
||||
|
||||
int resize_fd(int fd) {
|
||||
// Anonymous mapping doesn't need resizing.
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure the file backing this mapping is large enough.
|
||||
if (osmium::util::file_size(fd) < m_size + m_offset) {
|
||||
osmium::util::resize_file(fd, m_size + m_offset);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create memory mapping of given size.
|
||||
*
|
||||
* If fd is not set (or fd == -1), an anonymous mapping will be
|
||||
* created, otherwise a mapping based on the file descriptor will
|
||||
* be created.
|
||||
*
|
||||
* @pre @code size > 0 @endcode or
|
||||
* @code mode == write_shared || mode == write_private @endcode
|
||||
*
|
||||
* @param size Size of the mapping in bytes
|
||||
* @param mode Mapping mode: readonly, or writable (shared or private)
|
||||
* @param fd Open file descriptor of a file we want to map
|
||||
* @param offset Offset into the file where the mapping should start
|
||||
* @throws std::system_error if the mapping fails
|
||||
*/
|
||||
MemoryMapping(std::size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* For backwards compatibility only. Use the constructor taking
|
||||
* a mapping_mode as second argument instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED MemoryMapping(std::size_t size, bool writable=true, int fd=-1, off_t offset=0) :
|
||||
MemoryMapping(size, writable ? mapping_mode::write_shared : mapping_mode::readonly, fd, offset) {
|
||||
}
|
||||
|
||||
/// You can not copy construct a MemoryMapping.
|
||||
MemoryMapping(const MemoryMapping&) = delete;
|
||||
|
||||
/// You can not copy a MemoryMapping.
|
||||
MemoryMapping& operator=(const MemoryMapping&) = delete;
|
||||
|
||||
/**
|
||||
* Move construct a mapping from another one. The other mapping
|
||||
* will be marked as invalid.
|
||||
*/
|
||||
MemoryMapping(MemoryMapping&& other);
|
||||
|
||||
/**
|
||||
* Move a mapping. The other mapping will be marked as invalid.
|
||||
*/
|
||||
MemoryMapping& operator=(MemoryMapping&& other);
|
||||
|
||||
/**
|
||||
* Releases the mapping by calling unmap(). Will never throw.
|
||||
* Call unmap() instead if you want to be notified of any error.
|
||||
*/
|
||||
~MemoryMapping() noexcept {
|
||||
try {
|
||||
unmap();
|
||||
} catch (const std::system_error&) {
|
||||
// Ignore any exceptions because destructor must not throw.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap a mapping. If the mapping is not valid, it will do
|
||||
* nothing.
|
||||
*
|
||||
* @throws std::system_error if the unmapping fails
|
||||
*/
|
||||
void unmap();
|
||||
|
||||
/**
|
||||
* Resize a mapping to the given new size.
|
||||
*
|
||||
* On Linux systems this will use the mremap() function. On other
|
||||
* systems it will unmap and remap the memory. This can only be
|
||||
* done for file-based mappings, not anonymous mappings!
|
||||
*
|
||||
* @param new_size Number of bytes to resize to (must be > 0).
|
||||
*
|
||||
* @throws std::system_error if the remapping fails.
|
||||
*/
|
||||
void resize(std::size_t new_size);
|
||||
|
||||
/**
|
||||
* In a boolean context a MemoryMapping is true when it is a valid
|
||||
* existing mapping.
|
||||
*/
|
||||
explicit operator bool() const noexcept {
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes mapped. This is the same size you created
|
||||
* the mapping with. The actual mapping will probably be larger
|
||||
* because the system will round it to the page size.
|
||||
*/
|
||||
std::size_t size() const noexcept {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file descriptor this mapping was created from.
|
||||
*
|
||||
* @returns file descriptor, -1 for anonymous mappings
|
||||
*/
|
||||
int fd() const noexcept {
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was this mapping created as a writable mapping?
|
||||
*/
|
||||
bool writable() const noexcept {
|
||||
return m_mapping_mode != mapping_mode::readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of the mapping as any pointer type you like.
|
||||
*
|
||||
* @throws std::runtime_error if the mapping is invalid
|
||||
*/
|
||||
template <typename T = void>
|
||||
T* get_addr() const {
|
||||
if (is_valid()) {
|
||||
return reinterpret_cast<T*>(m_addr);
|
||||
}
|
||||
throw std::runtime_error{"invalid memory mapping"};
|
||||
}
|
||||
|
||||
}; // class MemoryMapping
|
||||
|
||||
/**
|
||||
* Anonymous memory mapping.
|
||||
*
|
||||
* Usage for anonymous mapping:
|
||||
* @code
|
||||
* AnonymousMemoryMapping mapping(1024); // create anonymous mapping with size
|
||||
* auto ptr = mapping.get_addr<char*>(); // get pointer to memory
|
||||
* mapping.unmap(); // release mapping by calling unmap() (or at end of scope)
|
||||
* @endcode
|
||||
*/
|
||||
class AnonymousMemoryMapping : public MemoryMapping {
|
||||
|
||||
public:
|
||||
|
||||
explicit AnonymousMemoryMapping(std::size_t size) :
|
||||
MemoryMapping(size, mapping_mode::write_private) {
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
/**
|
||||
* On systems other than Linux anonymous mappings can not be
|
||||
* resized!
|
||||
*/
|
||||
void resize(std::size_t) = delete;
|
||||
#endif
|
||||
|
||||
}; // class AnonymousMemoryMapping
|
||||
|
||||
/**
|
||||
* A thin wrapper around the MemoryMapping class used when all the
|
||||
* data in the mapped memory is of the same type. Instead of thinking
|
||||
* about the number of bytes mapped, this counts sizes in the number
|
||||
* of objects of that type.
|
||||
*
|
||||
* Note that no effort is made to actually initialize the objects in
|
||||
* this memory. This has to be done by the caller!
|
||||
*/
|
||||
template <typename T>
|
||||
class TypedMemoryMapping {
|
||||
|
||||
MemoryMapping m_mapping;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create anonymous typed memory mapping of given size.
|
||||
*
|
||||
* @param size Number of objects of type T to be mapped
|
||||
* @throws std::system_error if the mapping fails
|
||||
*/
|
||||
explicit TypedMemoryMapping(std::size_t size) :
|
||||
m_mapping(sizeof(T) * size, MemoryMapping::mapping_mode::write_private) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create file-backed memory mapping of given size. The file must
|
||||
* contain at least `sizeof(T) * size` bytes!
|
||||
*
|
||||
* @param size Number of objects of type T to be mapped
|
||||
* @param mode Mapping mode: readonly, or writable (shared or private)
|
||||
* @param fd Open file descriptor of a file we want to map
|
||||
* @param offset Offset into the file where the mapping should start
|
||||
* @throws std::system_error if the mapping fails
|
||||
*/
|
||||
TypedMemoryMapping(std::size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset = 0) :
|
||||
m_mapping(sizeof(T) * size, mode, fd, sizeof(T) * offset) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* For backwards compatibility only. Use the constructor taking
|
||||
* a mapping_mode as second argument instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED TypedMemoryMapping(std::size_t size, bool writable, int fd, off_t offset = 0) :
|
||||
m_mapping(sizeof(T) * size,
|
||||
writable ? MemoryMapping::mapping_mode::write_shared : MemoryMapping::mapping_mode::readonly,
|
||||
fd,
|
||||
sizeof(T) * offset) {
|
||||
}
|
||||
|
||||
/// You can not copy construct a TypedMemoryMapping.
|
||||
TypedMemoryMapping(const TypedMemoryMapping&) = delete;
|
||||
|
||||
/// You can not copy a MemoryMapping.
|
||||
TypedMemoryMapping& operator=(const TypedMemoryMapping&) = delete;
|
||||
|
||||
/**
|
||||
* Move construct a mapping from another one. The other mapping
|
||||
* will be marked as invalid.
|
||||
*/
|
||||
TypedMemoryMapping(TypedMemoryMapping&& other) = default;
|
||||
|
||||
/**
|
||||
* Move a mapping. The other mapping will be marked as invalid.
|
||||
*/
|
||||
TypedMemoryMapping& operator=(TypedMemoryMapping&& other) = default;
|
||||
|
||||
/**
|
||||
* Releases the mapping by calling unmap(). Will never throw.
|
||||
* Call unmap() instead if you want to be notified of any error.
|
||||
*/
|
||||
~TypedMemoryMapping() noexcept = default;
|
||||
|
||||
/**
|
||||
* Unmap a mapping. If the mapping is not valid, it will do
|
||||
* nothing.
|
||||
*
|
||||
* @throws std::system_error if the unmapping fails
|
||||
*/
|
||||
void unmap() {
|
||||
m_mapping.unmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a mapping to the given new size.
|
||||
*
|
||||
* On Linux systems this will use the mremap() function. On other
|
||||
* systems it will unmap and remap the memory. This can only be
|
||||
* done for file-based mappings, not anonymous mappings!
|
||||
*
|
||||
* @param new_size Number of objects of type T to resize to
|
||||
* @throws std::system_error if the remapping fails
|
||||
*/
|
||||
void resize(std::size_t new_size) {
|
||||
m_mapping.resize(sizeof(T) * new_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* In a boolean context a TypedMemoryMapping is true when it is
|
||||
* a valid existing mapping.
|
||||
*/
|
||||
explicit operator bool() const noexcept {
|
||||
return !!m_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of objects of class T mapped. This is the same size
|
||||
* you created the mapping with. The actual mapping will probably
|
||||
* be larger because the system will round it to the page size.
|
||||
*/
|
||||
std::size_t size() const noexcept {
|
||||
assert(m_mapping.size() % sizeof(T) == 0);
|
||||
return m_mapping.size() / sizeof(T);
|
||||
}
|
||||
|
||||
/**
|
||||
* The file descriptor this mapping was created from.
|
||||
*
|
||||
* @returns file descriptor, -1 for anonymous mappings
|
||||
*/
|
||||
int fd() const noexcept {
|
||||
return m_mapping.fd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Was this mapping created as a writable mapping?
|
||||
*/
|
||||
bool writable() const noexcept {
|
||||
return m_mapping.writable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of the beginning of the mapping.
|
||||
*
|
||||
* @throws std::runtime_error if the mapping is invalid
|
||||
*/
|
||||
T* begin() {
|
||||
return m_mapping.get_addr<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address one past the end of the mapping.
|
||||
*
|
||||
* @throws std::runtime_error if the mapping is invalid
|
||||
*/
|
||||
T* end() {
|
||||
return m_mapping.get_addr<T>() + size();
|
||||
}
|
||||
|
||||
const T* cbegin() const {
|
||||
return m_mapping.get_addr<T>();
|
||||
}
|
||||
|
||||
const T* cend() const {
|
||||
return m_mapping.get_addr<T>() + size();
|
||||
}
|
||||
|
||||
const T* begin() const {
|
||||
return m_mapping.get_addr<T>();
|
||||
}
|
||||
|
||||
const T* end() const {
|
||||
return m_mapping.get_addr<T>() + size();
|
||||
}
|
||||
|
||||
}; // class TypedMemoryMapping
|
||||
|
||||
template <typename T>
|
||||
class AnonymousTypedMemoryMapping : public TypedMemoryMapping<T> {
|
||||
|
||||
public:
|
||||
|
||||
explicit AnonymousTypedMemoryMapping(std::size_t size) :
|
||||
TypedMemoryMapping<T>(size) {
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
/**
|
||||
* On systems other than Linux anonymous mappings can not be
|
||||
* resized!
|
||||
*/
|
||||
void resize(std::size_t) = delete;
|
||||
#endif
|
||||
|
||||
}; // class AnonymousTypedMemoryMapping
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// =========== Unix implementation =============
|
||||
|
||||
// MAP_FAILED is often a macro containing an old style cast
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
|
||||
inline bool osmium::util::MemoryMapping::is_valid() const noexcept {
|
||||
return m_addr != MAP_FAILED;
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::make_invalid() noexcept {
|
||||
m_addr = MAP_FAILED;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// for BSD systems
|
||||
#ifndef MAP_ANONYMOUS
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
inline int osmium::util::MemoryMapping::get_protection() const noexcept {
|
||||
if (m_mapping_mode == mapping_mode::readonly) {
|
||||
return PROT_READ;
|
||||
}
|
||||
return PROT_READ | PROT_WRITE;
|
||||
}
|
||||
|
||||
inline int osmium::util::MemoryMapping::get_flags() const noexcept {
|
||||
if (m_fd == -1) {
|
||||
return MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
}
|
||||
if (m_mapping_mode == mapping_mode::write_shared) {
|
||||
return MAP_SHARED;
|
||||
}
|
||||
return MAP_PRIVATE;
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping::MemoryMapping(std::size_t size, mapping_mode mode, int fd, off_t offset) :
|
||||
m_size(check_size(size)),
|
||||
m_offset(offset),
|
||||
m_fd(resize_fd(fd)),
|
||||
m_mapping_mode(mode),
|
||||
m_addr(::mmap(nullptr, m_size, get_protection(), get_flags(), m_fd, m_offset)) {
|
||||
assert(!(fd == -1 && mode == mapping_mode::readonly));
|
||||
if (!is_valid()) {
|
||||
throw std::system_error{errno, std::system_category(), "mmap failed"};
|
||||
}
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping::MemoryMapping(MemoryMapping&& other) :
|
||||
m_size(other.m_size),
|
||||
m_offset(other.m_offset),
|
||||
m_fd(other.m_fd),
|
||||
m_mapping_mode(other.m_mapping_mode),
|
||||
m_addr(other.m_addr) {
|
||||
other.make_invalid();
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmium::util::MemoryMapping&& other) {
|
||||
unmap();
|
||||
m_size = other.m_size;
|
||||
m_offset = other.m_offset;
|
||||
m_fd = other.m_fd;
|
||||
m_mapping_mode = other.m_mapping_mode;
|
||||
m_addr = other.m_addr;
|
||||
other.make_invalid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::unmap() {
|
||||
if (is_valid()) {
|
||||
if (::munmap(m_addr, m_size) != 0) {
|
||||
throw std::system_error{errno, std::system_category(), "munmap failed"};
|
||||
}
|
||||
make_invalid();
|
||||
}
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::resize(std::size_t new_size) {
|
||||
assert(new_size > 0 && "can not resize to zero size");
|
||||
if (m_fd == -1) { // anonymous mapping
|
||||
#ifdef __linux__
|
||||
m_addr = ::mremap(m_addr, m_size, new_size, MREMAP_MAYMOVE);
|
||||
if (!is_valid()) {
|
||||
throw std::system_error{errno, std::system_category(), "mremap failed"};
|
||||
}
|
||||
m_size = new_size;
|
||||
#else
|
||||
assert(false && "can't resize anonymous mappings on non-linux systems");
|
||||
#endif
|
||||
} else { // file-based mapping
|
||||
unmap();
|
||||
m_size = new_size;
|
||||
resize_fd(m_fd);
|
||||
m_addr = ::mmap(nullptr, new_size, get_protection(), get_flags(), m_fd, m_offset);
|
||||
if (!is_valid()) {
|
||||
throw std::system_error{errno, std::system_category(), "mmap (remap) failed"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// =========== Windows implementation =============
|
||||
|
||||
/* References:
|
||||
* CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
|
||||
* CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
|
||||
* MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
|
||||
* UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
|
||||
*/
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
inline DWORD dword_hi(uint64_t x) {
|
||||
return static_cast<DWORD>(x >> 32);
|
||||
}
|
||||
|
||||
inline DWORD dword_lo(uint64_t x) {
|
||||
return static_cast<DWORD>(x & 0xffffffff);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
inline DWORD osmium::util::MemoryMapping::get_protection() const noexcept {
|
||||
switch (m_mapping_mode) {
|
||||
case mapping_mode::readonly:
|
||||
return PAGE_READONLY;
|
||||
case mapping_mode::write_private:
|
||||
return PAGE_WRITECOPY;
|
||||
default: // mapping_mode::write_shared
|
||||
break;
|
||||
}
|
||||
return PAGE_READWRITE;
|
||||
}
|
||||
|
||||
inline DWORD osmium::util::MemoryMapping::get_flags() const noexcept {
|
||||
switch (m_mapping_mode) {
|
||||
case mapping_mode::readonly:
|
||||
return FILE_MAP_READ;
|
||||
case mapping_mode::write_private:
|
||||
return FILE_MAP_COPY;
|
||||
default: // mapping_mode::write_shared
|
||||
break;
|
||||
}
|
||||
return FILE_MAP_WRITE;
|
||||
}
|
||||
|
||||
inline HANDLE osmium::util::MemoryMapping::get_handle() const noexcept {
|
||||
if (m_fd == -1) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return reinterpret_cast<HANDLE>(_get_osfhandle(m_fd));
|
||||
}
|
||||
|
||||
inline HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept {
|
||||
if (m_fd != -1) {
|
||||
_setmode(m_fd, _O_BINARY);
|
||||
}
|
||||
return CreateFileMapping(get_handle(),
|
||||
nullptr,
|
||||
get_protection(),
|
||||
osmium::util::dword_hi(static_cast<uint64_t>(m_size) + m_offset),
|
||||
osmium::util::dword_lo(static_cast<uint64_t>(m_size) + m_offset),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
inline void* osmium::util::MemoryMapping::map_view_of_file() const noexcept {
|
||||
return MapViewOfFile(m_handle,
|
||||
get_flags(),
|
||||
osmium::util::dword_hi(m_offset),
|
||||
osmium::util::dword_lo(m_offset),
|
||||
m_size);
|
||||
}
|
||||
|
||||
inline bool osmium::util::MemoryMapping::is_valid() const noexcept {
|
||||
return m_addr != nullptr;
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::make_invalid() noexcept {
|
||||
m_addr = nullptr;
|
||||
}
|
||||
|
||||
// GetLastError() returns a DWORD (A 32-bit unsigned integer), but the error
|
||||
// code for std::system_error is an int. So we convert this here and hope
|
||||
// it all works.
|
||||
inline int last_error() noexcept {
|
||||
return static_cast<int>(GetLastError());
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping::MemoryMapping(std::size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset) :
|
||||
m_size(check_size(size)),
|
||||
m_offset(offset),
|
||||
m_fd(resize_fd(fd)),
|
||||
m_mapping_mode(mode),
|
||||
m_handle(create_file_mapping()),
|
||||
m_addr(nullptr) {
|
||||
|
||||
if (!m_handle) {
|
||||
throw std::system_error{last_error(), std::system_category(), "CreateFileMapping failed"};
|
||||
}
|
||||
|
||||
m_addr = map_view_of_file();
|
||||
if (!is_valid()) {
|
||||
throw std::system_error{last_error(), std::system_category(), "MapViewOfFile failed"};
|
||||
}
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping::MemoryMapping(MemoryMapping&& other) :
|
||||
m_size(other.m_size),
|
||||
m_offset(other.m_offset),
|
||||
m_fd(other.m_fd),
|
||||
m_mapping_mode(other.m_mapping_mode),
|
||||
m_handle(std::move(other.m_handle)),
|
||||
m_addr(other.m_addr) {
|
||||
other.make_invalid();
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmium::util::MemoryMapping&& other) {
|
||||
unmap();
|
||||
m_size = other.m_size;
|
||||
m_offset = other.m_offset;
|
||||
m_fd = other.m_fd;
|
||||
m_mapping_mode = other.m_mapping_mode;
|
||||
m_handle = std::move(other.m_handle);
|
||||
m_addr = other.m_addr;
|
||||
other.make_invalid();
|
||||
other.m_handle = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::unmap() {
|
||||
if (is_valid()) {
|
||||
if (!UnmapViewOfFile(m_addr)) {
|
||||
throw std::system_error{last_error(), std::system_category(), "UnmapViewOfFile failed"};
|
||||
}
|
||||
make_invalid();
|
||||
}
|
||||
|
||||
if (m_handle) {
|
||||
if (!CloseHandle(m_handle)) {
|
||||
throw std::system_error{last_error(), std::system_category(), "CloseHandle failed"};
|
||||
}
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::resize(std::size_t new_size) {
|
||||
unmap();
|
||||
|
||||
m_size = new_size;
|
||||
resize_fd(m_fd);
|
||||
|
||||
m_handle = create_file_mapping();
|
||||
if (!m_handle) {
|
||||
throw std::system_error{last_error(), std::system_category(), "CreateFileMapping failed"};
|
||||
}
|
||||
|
||||
m_addr = map_view_of_file();
|
||||
if (!is_valid()) {
|
||||
throw std::system_error{last_error(), std::system_category(), "MapViewOfFile failed"};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_UTIL_MEMORY_MAPPING_HPP
|
||||
@@ -0,0 +1,120 @@
|
||||
#ifndef OSMIUM_UTIL_MINMAX_HPP
|
||||
#define OSMIUM_UTIL_MINMAX_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <limits>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
template <typename T>
|
||||
inline T min_op_start_value() {
|
||||
return std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for calculating the minimum of a bunch of values.
|
||||
* Works with any numeric type.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* min_op<int> x;
|
||||
* x.update(27);
|
||||
* x.update(12);
|
||||
* auto min = x.get(); // 12
|
||||
*/
|
||||
template <typename T>
|
||||
class min_op {
|
||||
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
|
||||
explicit min_op(T start_value = min_op_start_value<T>()) :
|
||||
m_value(start_value) {
|
||||
}
|
||||
|
||||
void update(T value) noexcept {
|
||||
if (value < m_value) {
|
||||
m_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
T operator()() const noexcept {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T max_op_start_value() {
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for calculating the maximum of a bunch of values.
|
||||
* Works with any numeric type.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* max_op<int> x;
|
||||
* x.update(27);
|
||||
* x.update(12);
|
||||
* auto max = x.get(); // 27
|
||||
*/
|
||||
template <typename T>
|
||||
class max_op {
|
||||
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
|
||||
explicit max_op(T start_value = max_op_start_value<T>()) :
|
||||
m_value(start_value) {
|
||||
}
|
||||
|
||||
void update(T value) noexcept {
|
||||
if (value > m_value) {
|
||||
m_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
T operator()() const noexcept {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_MINMAX_HPP
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef OSMIUM_UTIL_MISC_HPP
|
||||
#define OSMIUM_UTIL_MISC_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <tuple>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Like std::tie(), but takes its arguments as const references. Used
|
||||
* as a helper function when sorting.
|
||||
*/
|
||||
template <typename... Ts>
|
||||
inline std::tuple<const Ts&...>
|
||||
const_tie(const Ts&... args) noexcept {
|
||||
return std::tuple<const Ts&...>(args...);
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_MISC_HPP
|
||||
@@ -0,0 +1,205 @@
|
||||
#ifndef OSMIUM_UTIL_OPTIONS_HPP
|
||||
#define OSMIUM_UTIL_OPTIONS_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Stores key=value type options. This class can be used stand-alone or
|
||||
* as a base class. Options are stored and retrieved by key using the
|
||||
* different set() and get() methods.
|
||||
*
|
||||
* Both keys and values are stored as strings. The values "true",
|
||||
* "yes", "false", and "no" are interpreted as boolean values in some
|
||||
* functions.
|
||||
*
|
||||
* You can iterate over all set options. Dereferencing an iterator
|
||||
* yields a std::pair of the key and value strings.
|
||||
*/
|
||||
class Options {
|
||||
|
||||
using option_map = std::map<std::string, std::string>;
|
||||
option_map m_options;
|
||||
|
||||
public:
|
||||
|
||||
using iterator = option_map::iterator;
|
||||
using const_iterator = option_map::const_iterator;
|
||||
using value_type = option_map::value_type;
|
||||
|
||||
/**
|
||||
* Construct empty option set.
|
||||
*/
|
||||
Options() = default;
|
||||
|
||||
/**
|
||||
* Construct option set from initializer list:
|
||||
* @code
|
||||
* Options options{ { "foo", "true" }, { "bar", "17" } };
|
||||
* @endcode
|
||||
*/
|
||||
explicit Options(const std::initializer_list<value_type>& values) :
|
||||
m_options(values) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set option 'key' to 'value'.
|
||||
*/
|
||||
void set(const std::string& key, const std::string& value) {
|
||||
m_options[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set option 'key' to 'value'.
|
||||
*/
|
||||
void set(const std::string& key, const char* value) {
|
||||
m_options[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set option 'key' to 'value'.
|
||||
*/
|
||||
void set(const std::string& key, bool value) {
|
||||
m_options[key] = value ? "true" : "false";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set option from string in the form 'key=value'. If the string
|
||||
* contains no equal sign, the whole string is the key and it will
|
||||
* be set to "true".
|
||||
*/
|
||||
void set(const std::string& data) {
|
||||
const std::size_t pos = data.find_first_of('=');
|
||||
if (pos == std::string::npos) {
|
||||
m_options[data] = "true";
|
||||
} else {
|
||||
const std::string value{data.substr(pos+1)};
|
||||
set(data.substr(0, pos), value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of "key" option. If not set, the default_value (or
|
||||
* empty string) is returned.
|
||||
*/
|
||||
std::string get(const std::string& key, const std::string& default_value = "") const noexcept {
|
||||
const auto it = m_options.find(key);
|
||||
if (it == m_options.end()) {
|
||||
return default_value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this option set to a true value ("true" or "yes")?
|
||||
* Will return false if the value is unset.
|
||||
*/
|
||||
bool is_true(const std::string& key) const noexcept {
|
||||
const std::string value{get(key)};
|
||||
return (value == "true" || value == "yes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this option not set to a false value ("false" or "no")?
|
||||
* Will return true if the value is unset.
|
||||
*/
|
||||
bool is_not_false(const std::string& key) const noexcept {
|
||||
const std::string value{get(key)};
|
||||
return !(value == "false" || value == "no");
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of options set.
|
||||
*/
|
||||
std::size_t size() const noexcept {
|
||||
return m_options.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the beginning.
|
||||
*/
|
||||
iterator begin() noexcept {
|
||||
return m_options.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the end.
|
||||
*/
|
||||
iterator end() noexcept {
|
||||
return m_options.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the beginning.
|
||||
*/
|
||||
const_iterator begin() const noexcept {
|
||||
return m_options.cbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the end.
|
||||
*/
|
||||
const_iterator end() const noexcept {
|
||||
return m_options.cend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the beginning.
|
||||
*/
|
||||
const_iterator cbegin() const noexcept {
|
||||
return m_options.cbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a iterator to the end.
|
||||
*/
|
||||
const_iterator cend() const noexcept {
|
||||
return m_options.cend();
|
||||
}
|
||||
|
||||
}; // class Options
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_OPTIONS_HPP
|
||||
@@ -0,0 +1,192 @@
|
||||
#ifndef OSMIUM_UTIL_PROGRESS_BAR_HPP
|
||||
#define OSMIUM_UTIL_PROGRESS_BAR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <iostream>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Displays a progress bar on STDERR. Can be used together with the
|
||||
* osmium::io::Reader class for instance.
|
||||
*/
|
||||
class ProgressBar {
|
||||
|
||||
static const char* bar() noexcept {
|
||||
return "======================================================================";
|
||||
}
|
||||
|
||||
static const char* spc() noexcept {
|
||||
return " ";
|
||||
}
|
||||
|
||||
static constexpr const std::size_t length = 70;
|
||||
|
||||
// The max size is the file size if there is a single file and the
|
||||
// sum of all file sizes if there are multiple files. It corresponds
|
||||
// to 100%.
|
||||
std::size_t m_max_size;
|
||||
|
||||
// The sum of the file sizes already done.
|
||||
std::size_t m_done_size = 0;
|
||||
|
||||
// The currently read size in the current file.
|
||||
std::size_t m_current_size = 0;
|
||||
|
||||
// The percentage calculated when it was last displayed. Used to decide
|
||||
// whether we need to update the display. Start setting is one that
|
||||
// will always be different from any legal setting.
|
||||
std::size_t m_prev_percent = 100 + 1;
|
||||
|
||||
// Is the progress bar enabled at all?
|
||||
bool m_enable;
|
||||
|
||||
// Used to make sure we do cleanup in the destructor if it was not
|
||||
// already done.
|
||||
bool m_do_cleanup = true;
|
||||
|
||||
void display() {
|
||||
const std::size_t percent = 100 * (m_done_size + m_current_size) / m_max_size;
|
||||
if (m_prev_percent == percent) {
|
||||
return;
|
||||
}
|
||||
m_prev_percent = percent;
|
||||
|
||||
const auto num = static_cast<std::size_t>(percent * (length / 100.0));
|
||||
std::cerr << '[';
|
||||
if (num >= length) {
|
||||
std::cerr << bar();
|
||||
} else {
|
||||
std::cerr << (bar() + length - num) << '>' << (spc() + num);
|
||||
}
|
||||
std::cerr << "] ";
|
||||
if (percent < 10) {
|
||||
std::cerr << ' ';
|
||||
}
|
||||
if (percent < 100) {
|
||||
std::cerr << ' ';
|
||||
}
|
||||
std::cerr << percent << "% \r";
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Initializes the progress bar. No output yet.
|
||||
*
|
||||
* @param max_size Max size equivalent to 100%.
|
||||
* @param enable Set to false to disable (for instance if stderr is
|
||||
* not a TTY).
|
||||
*/
|
||||
ProgressBar(std::size_t max_size, bool enable) noexcept :
|
||||
m_max_size(max_size),
|
||||
m_enable(max_size > 0 && enable) {
|
||||
}
|
||||
|
||||
~ProgressBar() {
|
||||
if (m_do_cleanup) {
|
||||
try {
|
||||
done();
|
||||
} catch (...) {
|
||||
// Swallow any exceptions, because a destructor should
|
||||
// not throw.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to update the progress bar. Actual update will
|
||||
* only happen if the percentage changed from the last time this
|
||||
* function was called.
|
||||
*
|
||||
* @param current_size Current size. Used together with the max_size
|
||||
* from constructor to calculate the percentage.
|
||||
*/
|
||||
void update(std::size_t current_size) {
|
||||
if (!m_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_current_size = current_size;
|
||||
|
||||
display();
|
||||
}
|
||||
|
||||
/**
|
||||
* If you are reading multiple files, call this function after each
|
||||
* file is finished.
|
||||
*
|
||||
* @param file_size The size of the file just finished.
|
||||
*/
|
||||
void file_done(std::size_t file_size) {
|
||||
if (m_enable) {
|
||||
m_done_size += file_size;
|
||||
m_current_size = 0;
|
||||
display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this at the end. Will update the progress bar to 100% and
|
||||
* print a final line feed. If this is not called explicitly the
|
||||
* destructor will also call this.
|
||||
*/
|
||||
void done() {
|
||||
m_do_cleanup = false;
|
||||
if (m_enable) {
|
||||
m_done_size = m_max_size;
|
||||
m_current_size = 0;
|
||||
display();
|
||||
std::cerr << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the progress bar. Call this before doing any other output.
|
||||
* The next time update() is called, the progress bar will be visible
|
||||
* again.
|
||||
*/
|
||||
void remove() {
|
||||
if (m_enable) {
|
||||
std::cerr << spc() << " \r";
|
||||
m_prev_percent = 100 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
}; // class ProgressBar
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_PROGRESS_BAR_HPP
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef OSMIUM_UTIL_STRING_HPP
|
||||
#define OSMIUM_UTIL_STRING_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Split string on the separator character.
|
||||
*
|
||||
* @param str The string to be split.
|
||||
* @param sep The separator character.
|
||||
* @param compact Set this to true to remove empty strings from result.
|
||||
* @returns Vector with the parts of the string split up.
|
||||
*/
|
||||
inline std::vector<std::string> split_string(const std::string& str, const char sep, bool compact = false) {
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
if (!str.empty()) {
|
||||
std::size_t pos = 0;
|
||||
std::size_t nextpos = str.find_first_of(sep);
|
||||
while (nextpos != std::string::npos) {
|
||||
if (!compact || (nextpos - pos != 0)) {
|
||||
tokens.push_back(str.substr(pos, nextpos-pos));
|
||||
}
|
||||
pos = nextpos + 1;
|
||||
nextpos = str.find_first_of(sep, pos);
|
||||
}
|
||||
if (!compact || pos != str.size()) {
|
||||
tokens.push_back(str.substr(pos));
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string on any of the separator characters.
|
||||
*
|
||||
* @param str The string to be split.
|
||||
* @param sep The separator character(s).
|
||||
* @param compact Set this to true to remove empty strings from result.
|
||||
* @returns Vector with the parts of the string split up.
|
||||
*/
|
||||
inline std::vector<std::string> split_string(const std::string& str, const char* sep, bool compact = false) {
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
if (!str.empty()) {
|
||||
std::size_t pos = 0;
|
||||
std::size_t nextpos = str.find_first_of(sep);
|
||||
while (nextpos != std::string::npos) {
|
||||
if (!compact || (nextpos - pos != 0)) {
|
||||
tokens.push_back(str.substr(pos, nextpos-pos));
|
||||
}
|
||||
pos = nextpos + 1;
|
||||
nextpos = str.find_first_of(sep, pos);
|
||||
}
|
||||
if (!compact || pos != str.size()) {
|
||||
tokens.push_back(str.substr(pos));
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_STRING_HPP
|
||||
@@ -0,0 +1,429 @@
|
||||
#ifndef OSMIUM_UTIL_STRING_MATCHER_HPP
|
||||
#define OSMIUM_UTIL_STRING_MATCHER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstring>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <regex>
|
||||
|
||||
// std::regex isn't implemented properly in glibc++ (before the version
|
||||
// delivered with GCC 4.9) and libc++ before the version 3.6, so the use is
|
||||
// disabled by these checks. Checks for GLIBC were based on
|
||||
// http://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions
|
||||
// Checks for libc++ are simply based on compiler defines. This is probably
|
||||
// not optimal but seems to work for now.
|
||||
#if defined(__GLIBCXX__)
|
||||
# if ((__cplusplus >= 201402L) || \
|
||||
defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \
|
||||
defined(_GLIBCXX_REGEX_STATE_LIMIT))
|
||||
# define OSMIUM_WITH_REGEX
|
||||
# else
|
||||
# pragma message("Disabling regex functionality. See source code for info.")
|
||||
# endif
|
||||
#elif defined(__clang__)
|
||||
# if ((__clang_major__ > 3) || \
|
||||
(__clang_minor__ == 3 && __clang_minor__ > 5))
|
||||
# define OSMIUM_WITH_REGEX
|
||||
# else
|
||||
# pragma message("Disabling regex functionality")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Implements various string matching functions.
|
||||
*/
|
||||
class StringMatcher {
|
||||
|
||||
public:
|
||||
|
||||
// Parent class for all matcher classes. Used for enable_if check.
|
||||
class matcher {
|
||||
};
|
||||
|
||||
/**
|
||||
* Never matches.
|
||||
*/
|
||||
class always_false : public matcher {
|
||||
|
||||
public:
|
||||
|
||||
bool match(const char* /*test_string*/) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "always_false";
|
||||
}
|
||||
|
||||
}; // class always_false
|
||||
|
||||
/**
|
||||
* Always matches.
|
||||
*/
|
||||
class always_true : public matcher {
|
||||
|
||||
public:
|
||||
|
||||
bool match(const char* /*test_string*/) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "always_true";
|
||||
}
|
||||
|
||||
}; // class always_true
|
||||
|
||||
/**
|
||||
* Matches if the test string is equal to the stored string.
|
||||
*/
|
||||
class equal : public matcher {
|
||||
|
||||
std::string m_str;
|
||||
|
||||
public:
|
||||
|
||||
explicit equal(const std::string& str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
explicit equal(const char* str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
bool match(const char* test_string) const noexcept {
|
||||
return !std::strcmp(m_str.c_str(), test_string);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "equal[" << m_str << ']';
|
||||
}
|
||||
|
||||
}; // class equal
|
||||
|
||||
/**
|
||||
* Matches if the test string starts with the stored string.
|
||||
*/
|
||||
class prefix : public matcher {
|
||||
|
||||
std::string m_str;
|
||||
|
||||
public:
|
||||
|
||||
explicit prefix(const std::string& str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
explicit prefix(const char* str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
bool match(const char* test_string) const noexcept {
|
||||
return m_str.compare(0, std::string::npos, test_string, 0, m_str.size()) == 0;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "prefix[" << m_str << ']';
|
||||
}
|
||||
|
||||
}; // class prefix
|
||||
|
||||
/**
|
||||
* Matches if the test string is a substring of the stored string.
|
||||
*/
|
||||
class substring : public matcher {
|
||||
|
||||
std::string m_str;
|
||||
|
||||
public:
|
||||
|
||||
explicit substring(const std::string& str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
explicit substring(const char* str) :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
bool match(const char* test_string) const noexcept {
|
||||
return std::strstr(test_string, m_str.c_str()) != nullptr;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "substring[" << m_str << ']';
|
||||
}
|
||||
|
||||
}; // class substring
|
||||
|
||||
#ifdef OSMIUM_WITH_REGEX
|
||||
/**
|
||||
* Matches if the test string matches the regular expression.
|
||||
*/
|
||||
class regex : public matcher {
|
||||
|
||||
std::regex m_regex;
|
||||
|
||||
public:
|
||||
|
||||
explicit regex(const std::regex& regex) :
|
||||
m_regex(regex) {
|
||||
}
|
||||
|
||||
bool match(const char* test_string) const noexcept {
|
||||
return std::regex_search(test_string, m_regex);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "regex";
|
||||
}
|
||||
|
||||
}; // class regex
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Matches if the test string is equal to any of the stored strings.
|
||||
*/
|
||||
class list : public matcher {
|
||||
|
||||
std::vector<std::string> m_strings;
|
||||
|
||||
public:
|
||||
|
||||
explicit list() :
|
||||
m_strings() {
|
||||
}
|
||||
|
||||
explicit list(const std::vector<std::string>& strings) :
|
||||
m_strings(strings) {
|
||||
}
|
||||
|
||||
list& add_string(const char* str) {
|
||||
m_strings.push_back(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
list& add_string(const std::string& str) {
|
||||
m_strings.push_back(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool match(const char* test_string) const noexcept {
|
||||
for (const auto& s : m_strings) {
|
||||
if (!std::strcmp(s.c_str(), test_string)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
out << "list[";
|
||||
for (const auto& s : m_strings) {
|
||||
out << '[' << s << ']';
|
||||
}
|
||||
out << ']';
|
||||
}
|
||||
|
||||
}; // class list
|
||||
|
||||
private:
|
||||
|
||||
using matcher_type = boost::variant<always_false,
|
||||
always_true,
|
||||
equal,
|
||||
prefix,
|
||||
substring,
|
||||
#ifdef OSMIUM_WITH_REGEX
|
||||
regex,
|
||||
#endif
|
||||
list>;
|
||||
|
||||
matcher_type m_matcher;
|
||||
|
||||
class match_visitor : public boost::static_visitor<bool> {
|
||||
|
||||
const char* m_str;
|
||||
|
||||
public:
|
||||
|
||||
match_visitor(const char* str) noexcept :
|
||||
m_str(str) {
|
||||
}
|
||||
|
||||
template <typename TMatcher>
|
||||
bool operator()(const TMatcher& t) const noexcept {
|
||||
return t.match(m_str);
|
||||
}
|
||||
|
||||
}; // class match_visitor
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
class print_visitor : public boost::static_visitor<void> {
|
||||
|
||||
std::basic_ostream<TChar, TTraits>* m_out;
|
||||
|
||||
public:
|
||||
|
||||
print_visitor(std::basic_ostream<TChar, TTraits>& out) :
|
||||
m_out(&out) {
|
||||
}
|
||||
|
||||
template <typename TMatcher>
|
||||
void operator()(const TMatcher& t) const noexcept {
|
||||
t.print(*m_out);
|
||||
}
|
||||
|
||||
}; // class print_visitor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a string matcher that will never match.
|
||||
*/
|
||||
StringMatcher() :
|
||||
m_matcher(always_false{}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string matcher that will always or never match based on
|
||||
* the argument.
|
||||
* Shortcut for
|
||||
* @code StringMatcher{StringMatcher::always_true}; @endcode
|
||||
* or
|
||||
* @code StringMatcher{StringMatcher::always_false}; @endcode
|
||||
*/
|
||||
StringMatcher(bool result) :
|
||||
m_matcher(always_false{}) {
|
||||
if (result) {
|
||||
m_matcher = always_true{};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string matcher that will match the specified string.
|
||||
* Shortcut for
|
||||
* @code StringMatcher{StringMatcher::equal{str}}; @endcode
|
||||
*/
|
||||
StringMatcher(const char* str) :
|
||||
m_matcher(equal{str}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string matcher that will match the specified string.
|
||||
* Shortcut for
|
||||
* @code StringMatcher{StringMatcher::equal{str}}; @endcode
|
||||
*/
|
||||
StringMatcher(const std::string& str) :
|
||||
m_matcher(equal{str}) {
|
||||
}
|
||||
|
||||
#ifdef OSMIUM_WITH_REGEX
|
||||
/**
|
||||
* Create a string matcher that will match the specified regex.
|
||||
* Shortcut for
|
||||
* @code StringMatcher{StringMatcher::regex{aregex}}; @endcode
|
||||
*/
|
||||
StringMatcher(const std::regex& aregex) :
|
||||
m_matcher(regex{aregex}) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create a string matcher that will match if any of the strings
|
||||
* match.
|
||||
* Shortcut for
|
||||
* @code StringMatcher{StringMatcher::list{strings}}; @endcode
|
||||
*/
|
||||
StringMatcher(const std::vector<std::string>& strings) :
|
||||
m_matcher(list{strings}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string matcher.
|
||||
*
|
||||
* @tparam TMatcher Must be one of the matcher classes
|
||||
* osmium::StringMatcher::always_false, always_true,
|
||||
* equal, prefix, substring, regex or list.
|
||||
*/
|
||||
template <typename TMatcher, typename std::enable_if<
|
||||
std::is_base_of<matcher, TMatcher>::value, int>::type = 0>
|
||||
StringMatcher(TMatcher&& matcher) :
|
||||
m_matcher(std::forward<TMatcher>(matcher)) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the specified string.
|
||||
*/
|
||||
bool operator()(const char* str) const noexcept {
|
||||
return boost::apply_visitor(match_visitor{str}, m_matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the specified string.
|
||||
*/
|
||||
bool operator()(const std::string& str) const noexcept {
|
||||
return operator()(str.c_str());
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
void print(std::basic_ostream<TChar, TTraits>& out) const {
|
||||
boost::apply_visitor(print_visitor<TChar, TTraits>{out}, m_matcher);
|
||||
}
|
||||
|
||||
}; // class StringMatcher
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const StringMatcher& matcher) {
|
||||
matcher.print(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_STRING_MATCHER_HPP
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef OSMIUM_UTIL_TIMER_HPP
|
||||
#define OSMIUM_UTIL_TIMER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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>
|
||||
|
||||
#ifdef OSMIUM_WITH_TIMER
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Timer {
|
||||
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
std::chrono::time_point<clock> m_start;
|
||||
std::chrono::time_point<clock> m_stop;
|
||||
|
||||
public:
|
||||
|
||||
Timer() :
|
||||
m_start(clock::now()) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
m_start = clock::now();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
m_stop = clock::now();
|
||||
}
|
||||
|
||||
int64_t elapsed_microseconds() const {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(m_stop - m_start).count();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#else
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Timer {
|
||||
|
||||
public:
|
||||
|
||||
Timer() = default;
|
||||
|
||||
void start() {
|
||||
}
|
||||
|
||||
void stop() {
|
||||
}
|
||||
|
||||
int64_t elapsed_microseconds() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_UTIL_TIMER_HPP
|
||||
@@ -0,0 +1,144 @@
|
||||
#ifndef OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
|
||||
#define OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* @brief Helpful utility classes and functions not strictly OSM related
|
||||
*/
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Osmium programs often run for a long time because of the amount of
|
||||
* OSM data processed. This class helps with keeping the user up to
|
||||
* date by offering an easy way for programs to optionally output
|
||||
* verbose information about what's going on.
|
||||
*
|
||||
* Use an object of this class instead of std::cerr as an output
|
||||
* stream. Nothing is actually written if the object is not set to
|
||||
* verbose mode. If it is set to verbose mode, each line is prepended
|
||||
* with the running time, ie the time since the VerboseOutput object
|
||||
* was created.
|
||||
*/
|
||||
class VerboseOutput {
|
||||
|
||||
/// all time output will be relative to this start time
|
||||
time_t m_start;
|
||||
|
||||
/// is verbose mode enabled?
|
||||
bool m_verbose;
|
||||
|
||||
/// a newline was written, start next output with runtime
|
||||
bool m_newline;
|
||||
|
||||
/**
|
||||
* If we remember that a newline was written as the last thing
|
||||
* write out the time elapsed and reset the newline flag.
|
||||
*/
|
||||
void start_line() {
|
||||
if (m_newline) {
|
||||
const time_t elapsed = runtime();
|
||||
|
||||
const char old_fill = std::cerr.fill();
|
||||
std::cerr << '[' << std::setw(2) << (elapsed / 60) << ':' << std::setw(2) << std::setfill('0') << (elapsed % 60) << "] ";
|
||||
std::cerr.fill(old_fill);
|
||||
|
||||
m_newline = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit VerboseOutput(bool verbose = false) noexcept :
|
||||
m_start(time(nullptr)),
|
||||
m_verbose(verbose),
|
||||
m_newline(true) {
|
||||
}
|
||||
|
||||
~VerboseOutput() = default;
|
||||
|
||||
VerboseOutput(const VerboseOutput&) = default;
|
||||
VerboseOutput& operator=(const VerboseOutput&) = default;
|
||||
VerboseOutput(VerboseOutput&&) = default;
|
||||
VerboseOutput& operator=(VerboseOutput&&) = default;
|
||||
|
||||
time_t runtime() const noexcept {
|
||||
return time(nullptr) - m_start;
|
||||
}
|
||||
|
||||
/// Get "verbose" setting.
|
||||
bool verbose() const noexcept {
|
||||
return m_verbose;
|
||||
}
|
||||
|
||||
/// Set "verbose" setting.
|
||||
void verbose(bool verbose) noexcept {
|
||||
m_verbose = verbose;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void print(const T& value) {
|
||||
if (m_verbose) {
|
||||
start_line();
|
||||
std::cerr << value;
|
||||
|
||||
// check if there was a newline a the end and remember that
|
||||
std::ostringstream output_buffer;
|
||||
output_buffer << value;
|
||||
if (!output_buffer.str().empty() && output_buffer.str().back() == '\n') {
|
||||
m_newline = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // class VerboseOutput
|
||||
|
||||
template<typename T>
|
||||
inline VerboseOutput& operator<<(VerboseOutput& verbose_output, const T& value) {
|
||||
verbose_output.print(value);
|
||||
return verbose_output;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
|
||||
Reference in New Issue
Block a user