Merge commit '788bc67faa7738cf7c6b2a192ecf3e3567d1c20e' into develop
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
#ifndef OSMIUM_UTIL_DATA_FILE_HPP
|
||||
#define OSMIUM_UTIL_DATA_FILE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2015 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 <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <osmium/util/file.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Class wrapper for convenient access to some low-level file
|
||||
* functions.
|
||||
*/
|
||||
class DataFile {
|
||||
|
||||
FILE* m_file;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create and open a temporary file. It is removed after opening.
|
||||
*
|
||||
* @throws std::system_error if something went wrong.
|
||||
*/
|
||||
DataFile() :
|
||||
m_file(::tmpfile()) {
|
||||
if (!m_file) {
|
||||
throw std::system_error(errno, std::system_category(), "tmpfile failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and open a temporary file with the specified size. It
|
||||
* is removed after opening.
|
||||
*
|
||||
* @throws std::system_error if something went wrong.
|
||||
*/
|
||||
explicit DataFile(size_t size) :
|
||||
DataFile() {
|
||||
grow(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and open a named file.
|
||||
*
|
||||
* @param filename the name of the file
|
||||
* @param writable should the file be writable?
|
||||
* @throws std::system_error if something went wrong.
|
||||
*/
|
||||
DataFile(const char* filename, bool writable) :
|
||||
m_file(::fopen(filename, writable ? "wb+" : "rb" )) {
|
||||
if (!m_file) {
|
||||
throw std::system_error(errno, std::system_category(), "fopen failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and open a named file.
|
||||
*
|
||||
* @param filename the name of the file
|
||||
* @param writable should the file be writable?
|
||||
* @throws std::system_error if something went wrong.
|
||||
*/
|
||||
DataFile(const std::string& filename, bool writable) :
|
||||
DataFile(filename.c_str(), writable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* In boolean context the DataFile class returns true if the file
|
||||
* is open.
|
||||
*/
|
||||
operator bool() const noexcept {
|
||||
return m_file != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the file.
|
||||
*
|
||||
* Does nothing if the file is already closed.
|
||||
*
|
||||
* @throws std::system_error if file could not be closed
|
||||
*/
|
||||
void close() {
|
||||
if (m_file) {
|
||||
if (::fclose(m_file) != 0) {
|
||||
throw std::system_error(errno, std::system_category(), "fclose failed");
|
||||
}
|
||||
m_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~DataFile() noexcept {
|
||||
try {
|
||||
close();
|
||||
} catch (std::system_error&) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file descriptor of underlying file.
|
||||
*
|
||||
* @throws std::runtime_errro if file is not open
|
||||
* @throws std::system_error if fileno(3) call failed
|
||||
*/
|
||||
int fd() const {
|
||||
if (!m_file) {
|
||||
throw std::runtime_error("no open file");
|
||||
}
|
||||
|
||||
int fd = ::fileno(m_file);
|
||||
|
||||
if (fd == -1) {
|
||||
throw std::system_error(errno, std::system_category(), "fileno failed");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the operating system for the size of this file.
|
||||
*
|
||||
* @throws std::system_error if fstat(2) call failed
|
||||
*/
|
||||
size_t size() const {
|
||||
return osmium::util::file_size(fd());
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow file to given size.
|
||||
*
|
||||
* If the file is large enough already, nothing is done.
|
||||
* The file is never shrunk.
|
||||
*
|
||||
* @throws std::system_error if ftruncate(2) call failed
|
||||
*/
|
||||
void grow(size_t new_size) const {
|
||||
if (size() < new_size) {
|
||||
osmium::util::resize_file(fd(), new_size);
|
||||
}
|
||||
}
|
||||
|
||||
}; // class DataFile
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_UTIL_DATA_FILE_HPP
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#ifndef OSMIUM_UTIL_DELTA_HPP
|
||||
#define OSMIUM_UTIL_DELTA_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2015 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 <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* Helper class for delta encoding.
|
||||
*/
|
||||
template <typename T>
|
||||
class DeltaEncode {
|
||||
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
|
||||
DeltaEncode(T value = 0) :
|
||||
m_value(value) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
T update(T new_value) {
|
||||
using std::swap;
|
||||
swap(m_value, new_value);
|
||||
return m_value - new_value;
|
||||
}
|
||||
|
||||
}; // class DeltaEncode
|
||||
|
||||
/**
|
||||
* Helper class for delta decoding.
|
||||
*/
|
||||
template <typename T>
|
||||
class DeltaDecode {
|
||||
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
|
||||
DeltaDecode() :
|
||||
m_value(0) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
T update(T delta) {
|
||||
m_value += delta;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
}; // class DeltaDecode
|
||||
|
||||
template <typename TBaseIterator, typename TTransform, typename TValue>
|
||||
class DeltaEncodeIterator : public std::iterator<std::input_iterator_tag, TValue> {
|
||||
|
||||
typedef TValue value_type;
|
||||
|
||||
TBaseIterator m_it;
|
||||
TBaseIterator m_end;
|
||||
value_type m_delta;
|
||||
DeltaEncode<value_type> m_value;
|
||||
TTransform m_trans;
|
||||
|
||||
public:
|
||||
|
||||
DeltaEncodeIterator(TBaseIterator first, TBaseIterator last, TTransform& trans) :
|
||||
m_it(first),
|
||||
m_end(last),
|
||||
m_delta(m_trans(m_it)),
|
||||
m_value(m_delta),
|
||||
m_trans(trans) {
|
||||
}
|
||||
|
||||
DeltaEncodeIterator& operator++() {
|
||||
if (m_it != m_end) {
|
||||
m_delta = m_value.update(m_trans(++m_it));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeltaEncodeIterator operator++(int) {
|
||||
DeltaEncodeIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
value_type operator*() {
|
||||
return m_delta;
|
||||
}
|
||||
|
||||
bool operator==(const DeltaEncodeIterator& rhs) const {
|
||||
return m_it == rhs.m_it && m_end == rhs.m_end;
|
||||
}
|
||||
|
||||
bool operator!=(const DeltaEncodeIterator& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
}; // class DeltaEncodeIterator
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_DELTA_HPP
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef OSMIUM_UTIL_ENDIAN_HPP
|
||||
#define OSMIUM_UTIL_ENDIAN_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2015 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(_WIN32) && !defined(__APPLE__)
|
||||
# include <endian.h>
|
||||
#else
|
||||
# define __LITTLE_ENDIAN 1234
|
||||
# define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif // OSMIUM_UTIL_ENDIAN_HPP
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#ifndef OSMIUM_UTIL_FILE_HPP
|
||||
#define OSMIUM_UTIL_FILE_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2015 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 <system_error>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# include <unistd.h>
|
||||
#else
|
||||
// https://msdn.microsoft.com/en-us/library/whx354w1.aspx
|
||||
# define ftruncate _chsize_s
|
||||
#endif
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace util {
|
||||
|
||||
/**
|
||||
* 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 size_t file_size(int fd) {
|
||||
#ifdef _MSC_VER
|
||||
// Windows implementation
|
||||
// https://msdn.microsoft.com/en-us/library/dfbc2kec.aspx
|
||||
auto size = ::_filelengthi64(fd);
|
||||
if (size == -1L) {
|
||||
throw std::system_error(errno, std::system_category(), "_filelengthi64 failed");
|
||||
}
|
||||
return size_t(size);
|
||||
#else
|
||||
// Unix implementation
|
||||
struct stat s;
|
||||
if (::fstat(fd, &s) != 0) {
|
||||
throw std::system_error(errno, std::system_category(), "fstat failed");
|
||||
}
|
||||
return size_t(s.st_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, size_t new_size) {
|
||||
if (::ftruncate(fd, new_size) != 0) {
|
||||
throw std::system_error(errno, std::system_category(), "ftruncate failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the page size for this system.
|
||||
*/
|
||||
inline size_t get_pagesize() {
|
||||
#ifdef _WIN32
|
||||
// Windows implementation
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
// Unix implementation
|
||||
return ::sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_UTIL_FILE_HPP
|
||||
@@ -0,0 +1,750 @@
|
||||
#ifndef OSMIUM_UTIL_MEMORY_MAPPING_HPP
|
||||
#define OSMIUM_UTIL_MEMORY_MAPPING_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2015 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 <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <osmium/util/file.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
#else
|
||||
# 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.
|
||||
*/
|
||||
class MemoryMapping {
|
||||
|
||||
public:
|
||||
enum class mapping_mode {
|
||||
readonly = 0,
|
||||
write_private = 1,
|
||||
write_shared = 2
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/// The size of the mapping
|
||||
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
|
||||
typedef DWORD flag_type;
|
||||
#else
|
||||
typedef int flag_type;
|
||||
#endif
|
||||
|
||||
flag_type get_protection() const noexcept;
|
||||
|
||||
flag_type get_flags() const noexcept;
|
||||
|
||||
// A zero-sized mapping is not allowed by the operating system.
|
||||
// So if the user asks for a mapping of size 0, we map a full
|
||||
// page instead. This way we don't have a special case in the rest
|
||||
// of the code.
|
||||
static size_t initial_size(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 size > 0 or mode == write_shared oder write_private
|
||||
*
|
||||
* @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(size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
|
||||
|
||||
/// DEPRECATED: For backwards compatibility
|
||||
MemoryMapping(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 (std::system_error&) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws std::system_error if the remapping fails
|
||||
*/
|
||||
void resize(size_t new_size);
|
||||
|
||||
/**
|
||||
* In a boolean context a MemoryMapping is true when it is a valid
|
||||
* existing mapping.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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:
|
||||
|
||||
AnonymousMemoryMapping(size_t size) :
|
||||
MemoryMapping(size, mapping_mode::write_private) {
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
/**
|
||||
* On systems other than Linux anonymous mappings can not be
|
||||
* resized!
|
||||
*/
|
||||
void resize(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
|
||||
*/
|
||||
TypedMemoryMapping(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(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
|
||||
TypedMemoryMapping(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() = 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(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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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:
|
||||
|
||||
AnonymousTypedMemoryMapping(size_t size) :
|
||||
TypedMemoryMapping<T>(size) {
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
/**
|
||||
* On systems other than Linux anonymous mappings can not be
|
||||
* resized!
|
||||
*/
|
||||
void resize(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(size_t size, mapping_mode mode, int fd, off_t offset) :
|
||||
m_size(initial_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(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;
|
||||
case mapping_mode::write_shared:
|
||||
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;
|
||||
case mapping_mode::write_shared:
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
inline osmium::util::MemoryMapping::MemoryMapping(size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset) :
|
||||
m_size(initial_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(GetLastError(), std::system_category(), "CreateFileMapping failed");
|
||||
}
|
||||
|
||||
m_addr = map_view_of_file();
|
||||
if (!is_valid()) {
|
||||
throw std::system_error(GetLastError(), 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(GetLastError(), std::system_category(), "UnmapViewOfFile failed");
|
||||
}
|
||||
make_invalid();
|
||||
}
|
||||
|
||||
if (m_handle) {
|
||||
if (! CloseHandle(m_handle)) {
|
||||
throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed");
|
||||
}
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline void osmium::util::MemoryMapping::resize(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(GetLastError(), std::system_category(), "CreateFileMapping failed");
|
||||
}
|
||||
|
||||
m_addr = map_view_of_file();
|
||||
if (!is_valid()) {
|
||||
throw std::system_error(GetLastError(), 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-2015 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
|
||||
+38
-4
@@ -43,21 +43,55 @@ namespace osmium {
|
||||
* Split string on the separator character.
|
||||
*
|
||||
* @param str The string to be split.
|
||||
* @param sep The separastor character.
|
||||
* @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) {
|
||||
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()) {
|
||||
size_t pos = 0;
|
||||
size_t nextpos = str.find_first_of(sep);
|
||||
while (nextpos != std::string::npos) {
|
||||
tokens.push_back(str.substr(pos, nextpos-pos));
|
||||
if (!compact || (nextpos - pos != 0)) {
|
||||
tokens.push_back(str.substr(pos, nextpos-pos));
|
||||
}
|
||||
pos = nextpos + 1;
|
||||
nextpos = str.find_first_of(sep, pos);
|
||||
}
|
||||
tokens.push_back(str.substr(pos));
|
||||
if (!compact || pos != str.size()) {
|
||||
tokens.push_back(str.substr(pos));
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string on the separator character(s).
|
||||
*
|
||||
* @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()) {
|
||||
size_t pos = 0;
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user