#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 "mapper.h"
namespace marisa {
#if defined _WIN32 || defined _WIN64
Mapper::Mapper()
: ptr_(NULL), origin_(NULL), avail_(0), size_(0),
file_(NULL), map_(NULL) {}
Mapper::Mapper(const void *ptr, std::size_t size)
: ptr_(ptr), origin_(NULL), avail_(size), size_(0),
file_(NULL), map_(NULL) {
MARISA_THROW_IF((ptr == NULL) || (size == 0), MARISA_PARAM_ERROR);
}
#else // defined _WIN32 || defined _WIN64
Mapper::Mapper()
: ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {}
Mapper::Mapper(const void *ptr, std::size_t size)
: ptr_(ptr), origin_(MAP_FAILED), avail_(size), size_(0), fd_(-1) {
MARISA_THROW_IF((ptr == NULL) || (size == 0), MARISA_PARAM_ERROR);
}
#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
#if defined _WIN32 || defined _WIN64
void Mapper::open(const char *filename, long offset, int whence) {
MARISA_THROW_IF(is_open(), MARISA_STATE_ERROR);
MARISA_THROW_IF(filename == NULL, MARISA_PARAM_ERROR);
struct __stat64 st;
if (::_stat64(filename, &st) != 0) {
MARISA_THROW(MARISA_IO_ERROR);
}
const UInt64 file_size = st.st_size;
MARISA_THROW_IF(file_size > MARISA_UINT32_MAX, MARISA_SIZE_ERROR);
Mapper temp;
temp.size_ = (std::size_t)file_size;
temp.file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
MARISA_THROW_IF(temp.file_ == NULL, MARISA_IO_ERROR);
temp.map_ = ::CreateFileMapping(temp.file_, NULL, PAGE_READONLY, 0, 0, NULL);
MARISA_THROW_IF(temp.map_ == NULL, MARISA_IO_ERROR);
temp.origin_ = ::MapViewOfFile(temp.map_, FILE_MAP_READ, 0, 0, 0);
MARISA_THROW_IF(temp.origin_ == NULL, MARISA_IO_ERROR);
temp.seek(offset, whence);
temp.swap(this);
}
#else // defined _WIN32 || defined _WIN64
void Mapper::open(const char *filename, long offset, int whence) {
MARISA_THROW_IF(is_open(), MARISA_STATE_ERROR);
MARISA_THROW_IF(filename == NULL, MARISA_PARAM_ERROR);
struct stat st;
if (::stat(filename, &st) != 0) {
MARISA_THROW(MARISA_IO_ERROR);
}
UInt64 file_size = st.st_size;
MARISA_THROW_IF(file_size > MARISA_UINT32_MAX, MARISA_SIZE_ERROR);
Mapper temp;
temp.size_ = (std::size_t)file_size;
temp.fd_ = ::open(filename, O_RDONLY);
MARISA_THROW_IF(temp.fd_ == -1, MARISA_IO_ERROR);
temp.origin_ = ::mmap(NULL, temp.size_, PROT_READ, MAP_SHARED, temp.fd_, 0);
MARISA_THROW_IF(temp.origin_ == MAP_FAILED, MARISA_IO_ERROR);
temp.seek(offset, whence);
temp.swap(this);
}
#endif // defined _WIN32 || defined _WIN64
void Mapper::clear() {
Mapper().swap(this);
}
void Mapper::swap(Mapper *rhs) {
MARISA_THROW_IF(rhs == NULL, MARISA_PARAM_ERROR);
Swap(&ptr_, &rhs->ptr_);
Swap(&avail_, &rhs->avail_);
Swap(&origin_, &rhs->origin_);
Swap(&size_, &rhs->size_);
#if defined _WIN32 || defined _WIN64
Swap(&file_, &rhs->file_);
Swap(&map_, &rhs->map_);
#else // defined _WIN32 || defined _WIN64
Swap(&fd_, &rhs->fd_);
#endif // defined _WIN32 || defined _WIN64
}
void Mapper::seek(long offset, int whence) {
switch (whence) {
case SEEK_SET:
case SEEK_CUR: {
MARISA_THROW_IF((offset < 0) || ((unsigned long)offset > size_),
MARISA_IO_ERROR);
ptr_ = static_cast<const UInt8 *>(origin_) + offset;
avail_ = (std::size_t)(size_ - offset);
return;
}
case SEEK_END: {
MARISA_THROW_IF((offset > 0) || ((unsigned long)-offset > size_),
MARISA_IO_ERROR);
ptr_ = static_cast<const UInt8 *>(origin_) + size_ + offset;
avail_ = (std::size_t)-offset;
return;
}
default: {
MARISA_THROW(MARISA_PARAM_ERROR);
}
}
}
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);
ptr_ = static_cast<const UInt8 *>(ptr_) + size;
avail_ -= size;
return static_cast<const UInt8 *>(ptr_) - size;
}
} // namespace marisa