diff options
Diffstat (limited to 'lib/marisa/grimoire/io/mapper.cc')
-rw-r--r-- | lib/marisa/grimoire/io/mapper.cc | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/lib/marisa/grimoire/io/mapper.cc b/lib/marisa/grimoire/io/mapper.cc new file mode 100644 index 0000000..6ae0ee3 --- /dev/null +++ b/lib/marisa/grimoire/io/mapper.cc @@ -0,0 +1,163 @@ +#if (defined _WIN32) || (defined _WIN64) + #include <sys/types.h> + #include <sys/stat.h> + #include <windows.h> +#else // (defined _WIN32) || (defined _WIN64) + #include <sys/mman.h> + #include <sys/stat.h> + #include <sys/types.h> + #include <fcntl.h> + #include <unistd.h> +#endif // (defined _WIN32) || (defined _WIN64) + +#include "marisa/grimoire/io/mapper.h" + +namespace marisa { +namespace grimoire { +namespace io { + +#if (defined _WIN32) || (defined _WIN64) +Mapper::Mapper() + : ptr_(NULL), origin_(NULL), avail_(0), size_(0), + file_(NULL), map_(NULL) {} +#else // (defined _WIN32) || (defined _WIN64) +Mapper::Mapper() + : ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {} +#endif // (defined _WIN32) || (defined _WIN64) + +#if (defined _WIN32) || (defined _WIN64) +Mapper::~Mapper() { + if (origin_ != NULL) { + ::UnmapViewOfFile(origin_); + } + + if (map_ != NULL) { + ::CloseHandle(map_); + } + + if (file_ != NULL) { + ::CloseHandle(file_); + } +} +#else // (defined _WIN32) || (defined _WIN64) +Mapper::~Mapper() { + if (origin_ != MAP_FAILED) { + ::munmap(origin_, size_); + } + + if (fd_ != -1) { + ::close(fd_); + } +} +#endif // (defined _WIN32) || (defined _WIN64) + +void Mapper::open(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + Mapper temp; + temp.open_(filename); + swap(temp); +} + +void Mapper::open(const void *ptr, std::size_t size) { + MARISA_THROW_IF((ptr == NULL) && (size != 0), MARISA_NULL_ERROR); + + Mapper temp; + temp.open_(ptr, size); + swap(temp); +} + +void Mapper::seek(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR); + + map_data(size); +} + +bool Mapper::is_open() const { + return ptr_ != NULL; +} + +void Mapper::clear() { + Mapper().swap(*this); +} + +void Mapper::swap(Mapper &rhs) { + marisa::swap(ptr_, rhs.ptr_); + marisa::swap(avail_, rhs.avail_); + marisa::swap(origin_, rhs.origin_); + marisa::swap(size_, rhs.size_); +#if (defined _WIN32) || (defined _WIN64) + marisa::swap(file_, rhs.file_); + marisa::swap(map_, rhs.map_); +#else // (defined _WIN32) || (defined _WIN64) + marisa::swap(fd_, rhs.fd_); +#endif // (defined _WIN32) || (defined _WIN64) +} + +const void *Mapper::map_data(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR); + + const char * const data = static_cast<const char *>(ptr_); + ptr_ = data + size; + avail_ -= size; + return data; +} + +#if (defined _WIN32) || (defined _WIN64) + #ifdef __MSVCRT_VERSION__ + #if __MSVCRT_VERSION__ >= 0x0601 + #define MARISA_HAS_STAT64 + #endif // __MSVCRT_VERSION__ >= 0x0601 + #endif // __MSVCRT_VERSION__ +void Mapper::open_(const char *filename) { + #ifdef MARISA_HAS_STAT64 + struct __stat64 st; + MARISA_THROW_IF(::_stat64(filename, &st) != 0, MARISA_IO_ERROR); + #else // MARISA_HAS_STAT64 + struct _stat st; + MARISA_THROW_IF(::_stat(filename, &st) != 0, MARISA_IO_ERROR); + #endif // MARISA_HAS_STAT64 + MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)st.st_size; + + file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + MARISA_THROW_IF(file_ == INVALID_HANDLE_VALUE, MARISA_IO_ERROR); + + map_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY, 0, 0, NULL); + MARISA_THROW_IF(map_ == NULL, MARISA_IO_ERROR); + + origin_ = ::MapViewOfFile(map_, FILE_MAP_READ, 0, 0, 0); + MARISA_THROW_IF(origin_ == NULL, MARISA_IO_ERROR); + + ptr_ = static_cast<const char *>(origin_); + avail_ = size_; +} +#else // (defined _WIN32) || (defined _WIN64) +void Mapper::open_(const char *filename) { + struct stat st; + MARISA_THROW_IF(::stat(filename, &st) != 0, MARISA_IO_ERROR); + MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)st.st_size; + + fd_ = ::open(filename, O_RDONLY); + MARISA_THROW_IF(fd_ == -1, MARISA_IO_ERROR); + + origin_ = ::mmap(NULL, size_, PROT_READ, MAP_SHARED, fd_, 0); + MARISA_THROW_IF(origin_ == MAP_FAILED, MARISA_IO_ERROR); + + ptr_ = static_cast<const char *>(origin_); + avail_ = size_; +} +#endif // (defined _WIN32) || (defined _WIN64) + +void Mapper::open_(const void *ptr, std::size_t size) { + ptr_ = ptr; + avail_ = size; +} + +} // namespace io +} // namespace grimoire +} // namespace marisa |