mirror of
https://github.com/ksherlock/mpw.git
synced 2025-02-16 12:30:53 +00:00
cxx
This commit is contained in:
parent
71bbee0479
commit
fbb92ef08d
@ -77,6 +77,7 @@ target_link_libraries(mpw MPW_LIB)
|
||||
target_link_libraries(mpw MPLITE_LIB)
|
||||
target_link_libraries(mpw NATIVE_LIB)
|
||||
target_link_libraries(mpw MACOS_LIB)
|
||||
target_link_libraries(mpw CXX_LIB)
|
||||
set_target_properties(mpw PROPERTIES LINK_FLAGS "-ledit")
|
||||
|
||||
|
||||
|
4
cxx/CMakeLists.txt
Normal file
4
cxx/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
set(CXX_SRC mapped_file.cpp)
|
||||
|
||||
add_library(CXX_LIB ${CXX_SRC})
|
377
cxx/mapped_file.cpp
Normal file
377
cxx/mapped_file.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
#include "mapped_file.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
#include "unique_resource.h"
|
||||
|
||||
namespace {
|
||||
class defer {
|
||||
public:
|
||||
typedef std::function<void()> FX;
|
||||
defer() = default;
|
||||
|
||||
defer(FX fx) : _fx(fx) {}
|
||||
defer(const defer &) = delete;
|
||||
defer(defer &&) = default;
|
||||
defer & operator=(const defer &) = delete;
|
||||
defer & operator=(defer &&) = default;
|
||||
|
||||
void cancel() { _fx = nullptr; }
|
||||
~defer() { if (_fx) _fx(); }
|
||||
private:
|
||||
FX _fx;
|
||||
};
|
||||
|
||||
void throw_error(int error) {
|
||||
throw std::system_error(error, std::system_category());
|
||||
}
|
||||
|
||||
|
||||
void throw_error(int error, const std::string &what) {
|
||||
throw std::system_error(error, std::system_category(), what);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
namespace {
|
||||
|
||||
void throw_error() {
|
||||
throw_error(GetLastError());
|
||||
}
|
||||
|
||||
void throw_error(const std::string &what) {
|
||||
throw_error(GetLastError(), what);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mapped_file_base::close() {
|
||||
if (is_open()) {
|
||||
|
||||
UnmapViewOfFile(_data);
|
||||
CloseHandle(_map_handle);
|
||||
CloseHandle(_file_handle);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, size_t offset) {
|
||||
|
||||
|
||||
HANDLE fh;
|
||||
HANDLE mh;
|
||||
|
||||
// length of 0 in CreateFileMapping / MapViewOfFile
|
||||
// means map the entire file.
|
||||
|
||||
if (is_open()) {
|
||||
throw std::runtime_error("mapped_file_base::open - file already open");
|
||||
}
|
||||
|
||||
fh = CreateFile(p.c_str(),
|
||||
flags == readonly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
flags == readonly ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
auto fh_close = make_unique_resource(fh, CloseHandle);
|
||||
|
||||
|
||||
if (length == -1) {
|
||||
LARGE_INTEGER file_size;
|
||||
GetFileSizeEx(fh, &file_size);
|
||||
length = file_size.QuadPart;
|
||||
}
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
DWORD protect = 0;
|
||||
DWORD access = 0;
|
||||
switch (flags) {
|
||||
case readonly:
|
||||
protect = PAGE_READONLY;
|
||||
access = FILE_MAP_READ;
|
||||
break;
|
||||
case readwrite:
|
||||
protect = PAGE_READWRITE;
|
||||
access = FILE_MAP_WRITE;
|
||||
break;
|
||||
case priv:
|
||||
protect = PAGE_WRITECOPY;
|
||||
access = FILE_MAP_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
mh = CreateFileMapping(fh, nullptr, protect, 0, 0, 0);
|
||||
if (mh == INVALID_HANDLE_VALUE) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
auto mh_close = make_unique_resource(mh, CloseHandle);
|
||||
|
||||
|
||||
_data = MapViewOfFileEx(mh,
|
||||
access,
|
||||
(DWORD)(offset >> 32),
|
||||
(DWORD)offset,
|
||||
length,
|
||||
nullptr);
|
||||
if (!_data) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
|
||||
_file_handle = fh_close.release();
|
||||
_map_handle = mh_close.release();
|
||||
_size = length;
|
||||
_flags = flags;
|
||||
}
|
||||
|
||||
|
||||
void mapped_file_base::create(const path_type& p, size_t length) {
|
||||
|
||||
const size_t offset = 0;
|
||||
|
||||
HANDLE fh;
|
||||
HANDLE mh;
|
||||
LARGE_INTEGER file_size;
|
||||
|
||||
const DWORD protect = PAGE_READWRITE;
|
||||
const DWORD access = FILE_MAP_WRITE;
|
||||
|
||||
|
||||
if (is_open()) {
|
||||
throw std::runtime_error("mapped_file_base::create - file already open");
|
||||
}
|
||||
|
||||
|
||||
fh = CreateFile(p.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
auto fh_close = make_unique_resource(fh, CloseHandle);
|
||||
|
||||
|
||||
file_size.QuadPart = length;
|
||||
if (!SetFilePointerEx(fh, file_size, nullptr, FILE_BEGIN));
|
||||
if (!SetEndOfFile(fh)) throw_error();
|
||||
|
||||
mh = CreateFileMapping(fh, nullptr, protect, 0, 0, 0);
|
||||
if (mh == INVALID_HANDLE_VALUE) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
auto mh_close = make_unique_resource(mh, CloseHandle);
|
||||
|
||||
_data = MapViewOfFileEx(mh,
|
||||
access,
|
||||
(DWORD)(offset >> 32),
|
||||
(DWORD)offset,
|
||||
length,
|
||||
nullptr);
|
||||
|
||||
if (!_data) {
|
||||
throw_error();
|
||||
}
|
||||
|
||||
_file_handle = fh_close.release();
|
||||
_map_handle = mh_close.release();
|
||||
|
||||
_size = length;
|
||||
_flags = readwrite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <cerrno>
|
||||
|
||||
namespace {
|
||||
|
||||
void throw_error() {
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
void throw_error(const std::string &what) {
|
||||
throw_error(errno, what);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mapped_file_base::close() {
|
||||
if (is_open()) {
|
||||
::munmap(_data, _size);
|
||||
::close(_fd);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, size_t offset) {
|
||||
|
||||
int fd;
|
||||
|
||||
int oflags = 0;
|
||||
|
||||
if (is_open()) {
|
||||
throw std::runtime_error("mapped_file_base::open - file already open");
|
||||
}
|
||||
|
||||
switch (flags) {
|
||||
case readonly:
|
||||
oflags = O_RDONLY;
|
||||
break;
|
||||
default:
|
||||
oflags = O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
fd = ::open(p.c_str(), oflags);
|
||||
if (fd < 0) {
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
//defer([fd](){::close(fd); });
|
||||
auto close_fd = make_unique_resource(fd, ::close);
|
||||
|
||||
|
||||
|
||||
if (length == -1) {
|
||||
struct stat st;
|
||||
|
||||
if (::fstat(fd, &st) < 0) {
|
||||
throw_error(errno);
|
||||
}
|
||||
length = st.st_size;
|
||||
}
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
_data = ::mmap(0, length,
|
||||
flags == readonly ? PROT_READ : PROT_READ | PROT_WRITE,
|
||||
flags == priv ? MAP_PRIVATE : MAP_SHARED,
|
||||
fd, offset);
|
||||
|
||||
if (_data == MAP_FAILED) {
|
||||
_data = nullptr;
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
_fd = close_fd.release();
|
||||
_size = length;
|
||||
_flags = flags;
|
||||
}
|
||||
|
||||
void mapped_file_base::create(const path_type& p, size_t length) {
|
||||
|
||||
int fd;
|
||||
const size_t offset = 0;
|
||||
|
||||
if (is_open()) {
|
||||
throw std::runtime_error("mapped_file_base::create - file already open");
|
||||
}
|
||||
|
||||
|
||||
|
||||
fd = ::open(p.c_str(), O_RDWR | O_CREAT | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
//defer([fd](){::close(fd); });
|
||||
|
||||
auto close_fd = make_unique_resource(fd, ::close);
|
||||
|
||||
|
||||
if (::ftruncate(fd, length) < 0) {
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
|
||||
_data = ::mmap(0, length,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fd, offset);
|
||||
|
||||
if (_data == MAP_FAILED) {
|
||||
_data = nullptr;
|
||||
throw_error(errno);
|
||||
}
|
||||
|
||||
_fd = close_fd.release();
|
||||
_size = length;
|
||||
_flags = readwrite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void mapped_file_base::reset() {
|
||||
_data = nullptr;
|
||||
_size = 0;
|
||||
_flags = readonly;
|
||||
#ifdef _WIN32
|
||||
_file_handle = nullptr;
|
||||
_map_handle = nullptr;
|
||||
#else
|
||||
_fd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mapped_file_base::swap(mapped_file_base &rhs)
|
||||
{
|
||||
if (std::addressof(rhs) != this) {
|
||||
std::swap(_data, rhs._data);
|
||||
std::swap(_size, rhs._size);
|
||||
std::swap(_flags, rhs._flags);
|
||||
#ifdef _WIN32
|
||||
std::swap(_file_handle, rhs._file_handle);
|
||||
std::swap(_map_handle, rhs._map_handle);
|
||||
#else
|
||||
std::swap(_fd, rhs._fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
mapped_file::mapped_file(mapped_file &&rhs) : mapped_file() {
|
||||
swap(rhs);
|
||||
//rhs.reset();
|
||||
}
|
||||
|
||||
mapped_file& mapped_file::operator=(mapped_file &&rhs) {
|
||||
if (std::addressof(rhs) == this) return *this;
|
||||
|
||||
swap(rhs);
|
||||
rhs.close();
|
||||
//rhs.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
143
cxx/mapped_file.h
Normal file
143
cxx/mapped_file.h
Normal file
@ -0,0 +1,143 @@
|
||||
#ifndef __mapped_file_h__
|
||||
#define __mapped_file_h__
|
||||
|
||||
#ifdef HAVE_TSFS
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class mapped_file_base {
|
||||
public:
|
||||
|
||||
#ifdef HAVE_TSFS
|
||||
typedef std::filesystem::path path_type ;
|
||||
#else
|
||||
typedef std::string path_type ;
|
||||
#endif
|
||||
|
||||
enum mapmode { readonly, readwrite, priv };
|
||||
|
||||
void close();
|
||||
|
||||
bool is_open() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
operator bool() const { return is_open(); }
|
||||
bool operator !() const { return !is_open(); }
|
||||
|
||||
~mapped_file_base() { close(); }
|
||||
|
||||
protected:
|
||||
|
||||
void swap(mapped_file_base &rhs);
|
||||
|
||||
void open(const path_type& p, mapmode flags, size_t length, size_t offset);
|
||||
void create(const path_type &p, size_t new_size); // always creates readwrite.
|
||||
void reset();
|
||||
|
||||
|
||||
size_t _size = 0;
|
||||
void *_data = nullptr;
|
||||
mapmode _flags = readonly;
|
||||
|
||||
#ifdef _WIN32
|
||||
void *_file_handle = nullptr;
|
||||
void *_map_handle = nullptr;
|
||||
#else
|
||||
int _fd = -1;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
class mapped_file : public mapped_file_base {
|
||||
|
||||
typedef mapped_file_base base;
|
||||
|
||||
public:
|
||||
|
||||
typedef unsigned char value_type;
|
||||
|
||||
typedef value_type *iterator;
|
||||
typedef const value_type *const_iterator;
|
||||
|
||||
typedef value_type &reference ;
|
||||
typedef const value_type &const_reference;
|
||||
|
||||
|
||||
mapped_file() = default;
|
||||
mapped_file(const path_type& p, mapmode flags = readonly, size_t length = -1, size_t offset = 0) {
|
||||
open(p, flags, length, offset);
|
||||
}
|
||||
|
||||
mapped_file(mapped_file &&);
|
||||
mapped_file(const mapped_file &) = delete;
|
||||
|
||||
mapped_file &operator=(mapped_file &&);
|
||||
mapped_file &operator=(const mapped_file &) = delete;
|
||||
|
||||
|
||||
void open(const path_type& p, mapmode flags, size_t length = -1, size_t offset = 0) {
|
||||
base::open(p, flags, length, offset);
|
||||
}
|
||||
|
||||
|
||||
const value_type *data() const {
|
||||
return (const value_type *)_data;
|
||||
}
|
||||
|
||||
value_type *data() {
|
||||
return _flags == readonly ? (value_type *)nullptr : (value_type *)_data;
|
||||
}
|
||||
|
||||
const_iterator cbegin() const {
|
||||
return data();
|
||||
}
|
||||
|
||||
const_iterator cend() const {
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return cend();
|
||||
}
|
||||
|
||||
|
||||
iterator begin() {
|
||||
return _flags == readonly ? (iterator)nullptr : (iterator)_data;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return _flags == readonly ? (iterator)nullptr : (iterator)_data + size();
|
||||
}
|
||||
|
||||
mapmode flags() const {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
void swap(mapped_file &rhs) {
|
||||
base::swap(rhs);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template<class T>
|
||||
void swap(mapped_file &a, mapped_file &b) {
|
||||
a.swap(b);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
95
cxx/unique_resource.h
Normal file
95
cxx/unique_resource.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __unique_resource_h__
|
||||
#define __unique_resource_h__
|
||||
|
||||
#include <utility>
|
||||
|
||||
template <class T, class D>
|
||||
class unique_resource {
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
unique_resource() = default;
|
||||
unique_resource(const unique_resource &) = delete;
|
||||
unique_resource(unique_resource &&rhs) {
|
||||
swap(rhs);
|
||||
}
|
||||
|
||||
unique_resource(T t, D d): _pair(t,d), _active(true)
|
||||
{}
|
||||
|
||||
~unique_resource() {
|
||||
reset();
|
||||
}
|
||||
|
||||
unique_resource &operator=(const unique_resource &) = delete;
|
||||
unique_resource &operator=(unique_resource &&rhs) {
|
||||
if (this != std::addressof(rhs)) {
|
||||
reset();
|
||||
swap(rhs);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(unique_resource & rhs) {
|
||||
if (this != std::addressof(rhs)) {
|
||||
std::swap(_active, rhs._active);
|
||||
std::swap(_pair, rhs._pair);
|
||||
}
|
||||
}
|
||||
|
||||
void reset(T t) {
|
||||
reset();
|
||||
_active = true;
|
||||
_pair.first = t;
|
||||
}
|
||||
|
||||
void reset(T t, D d) {
|
||||
reset();
|
||||
_active = true;
|
||||
_pair = std::make_pair(t, d);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (_active) {
|
||||
(*_pair.second)(_pair.first);
|
||||
_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
T release() {
|
||||
_active = false;
|
||||
return _pair.first;;
|
||||
}
|
||||
|
||||
T get() {
|
||||
return _pair.first;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return _active;
|
||||
}
|
||||
|
||||
D& get_deleter() {
|
||||
return _pair.second;
|
||||
}
|
||||
|
||||
const D& get_deleter() const {
|
||||
return _pair.second;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::pair<T, D> _pair;
|
||||
bool _active = false;
|
||||
};
|
||||
|
||||
#define MAKE_UNIQUE_RESOURCE(T, D) \
|
||||
unique_resource<decltype(T), decltype(D) *>(T, D)
|
||||
|
||||
template<class T, class D>
|
||||
unique_resource<T, D> make_unique_resource(T t, D d) {
|
||||
return unique_resource<T, D>(t, d);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user