に回答するために、mmapを調べていたら
という記事を見つけたのだが、これはCで書かれているのでC++から使うためにラップした。
どうもWindowsの場合は上述ブログ中のget_filecontent
で開いてclose_map
で閉じるらしい。このときget_filecontent
で得たmap領域へのポインタとハンドル両方いるのだそう。
unixではget_filecontent
で開いてmunmap
で閉じるらしい。このときget_filecontent
で得たmap領域へのポインタとサイズがいるらしい。
というわけでこれをRAII技法を使ってラップした。
なおついでに
- C++には
void*
から任意のポインタへの暗黙変換はないのでキャストが必要 - キャストは
static_cast
を使う
などした。
#ifndef YUMETODO_MMAP_HPP_ #define YUMETODO_MMAP_HPP_ // ref: http://nnabeyang.hatenablog.com/entry/20110620/1308560702 #include <cstdint> #include <cassert> #ifdef OS_WINDOWS #include <stdio.h> #include <windows.h> #else #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <sys/mman.h> #endif #ifdef OS_WINDOWS namespace impl{ std::size_t get_filecontent(char** buf, const char* fpath, HANDLE* map_handle) noexcept { unsigned int mode1, mode2, mode3, mode4; mode1 = GENERIC_READ; //assert(0x80000000 == mode1); mode2 = PAGE_READONLY; mode3 = FILE_MAP_READ; mode4 = FILE_SHARE_READ; wchar_t fname[80]; int len; char* p = fpath; int i = 0; while(*p != '\0') { mbtowc(&fname[i++], p, MB_CUR_MAX); p++; } fname[i] = '\0'; HANDLE handle = CreateFileW(fname, mode1, mode4, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(handle == INVALID_HANDLE_VALUE) { fprintf(stderr, "file open failed\n"); exit(1); } auto size = GetFileSize(handle, 0); assert(size >= 0); *map_handle = CreateFileMapping(handle, 0, mode2, 0, 0, 0); *buf = static_cast<char*>(MapViewOfFile(*map_handle, mode3, 0, 0, 0)); if(handle != INVALID_HANDLE_VALUE) { CloseHandle(handle); handle = INVALID_HANDLE_VALUE; } return std::size_t(size); } void close_map(char** inp, HANDLE* map_handle) noexcept { UnmapViewOfFile(*inp); if(*map_handle != INVALID_HANDLE_VALUE) { CloseHandle(*map_handle); *map_handle = INVALID_HANDLE_VALUE; } *inp_ = NULL; } } class mmap_handle { char *inp_; std::size_t size_; HANDLE map_handle_; public: mmap_handle(const char* fpath) noexcept { this->size_ = impl::get_filecontent(&inp_, fpath, &map_handle_); } ~mmap_handle() noexcept { impl::close_map(&inp_, &map_handle_); } char* get() noexcept; const char* get() const noexcept; std::size_t size() const noexcept; char* begin() noexcept; const char* begin() const noexcept; const char* cbegin() const noexcept; char* end() noexcept; const char* end() const noexcept; const char* cend() const noexcept; }; #else namespace impl{ std::size_t get_filecontent(char** buf, const char* fpath) noexcept { int fd = open(fpath, O_RDONLY); assert(fd > 0); struct stat st; assert(fstat(fd, &st) >= 0 && st.st_size >= 0); const auto re = std::size_t(st.st_size); *buf = static_cast<char*>(mmap(NULL, re, PROT_READ, MAP_PRIVATE, fd, 0)); close(fd); return re; } } class mmap_handle { char *inp_; std::size_t size_; public: mmap_handle(const char* fpath) noexcept { this->size_ = impl::get_filecontent(&inp_, fpath); } ~mmap_handle() noexcept { munmap(inp_, size_); } char* get() noexcept; const char* get() const noexcept; std::size_t size() const noexcept; char* begin() noexcept; const char* begin() const noexcept; const char* cbegin() const noexcept; char* end() noexcept; const char* end() const noexcept; const char* cend() const noexcept; }; #endif inline char* mmap_handle::get() noexcept { return this->inp_; } inline const char* mmap_handle::get() const noexcept { return this->inp_; } inline std::size_t mmap_handle::size() const noexcept { return this->size_; } inline char* mmap_handle::begin() noexcept { return this->inp_; } inline const char* mmap_handle::begin() const noexcept { return this->inp_; } inline const char* mmap_handle::cbegin() const noexcept { return this->inp_; } inline char* mmap_handle::end() noexcept { return this->inp_ + this->size_; } inline const char* mmap_handle::end() const noexcept { return this->inp_ + this->size_; } inline const char* mmap_handle::cend() const noexcept { return this->inp_ + this->size_; } #endif //YUMETODO_MMAP_HPP_
使用例は