MIT 라이선스가 포함된 사용하기 쉬운 헤더 전용 크로스 플랫폼 C++11 메모리 매핑 라이브러리입니다.
mio는 Boost를 가져올 필요 없이 메모리 매핑된 파일 IO가 필요한 모든 C++ 프로젝트에 쉽게 포함할 수 있다는(즉, 종속성 없음) 목표를 가지고 만들어졌습니다.
언제든지 문제를 열어주세요. 가능한 한 최선을 다해 우려 사항을 해결하도록 노력하겠습니다.
얇게 썬 빵 이후로 메모리 매핑이 가장 좋으니까!
더 심각하게 말하면, Boost.Iostreams를 사용하는 대신 이 라이브러리를 작성하는 주요 동기는 이미 열려 있는 파일 핸들/설명자를 사용하여 메모리 매핑을 설정하기 위한 지원이 부족했기 때문입니다. 미오라면 가능합니다.
또한 Boost.Iostreams의 솔루션에서는 사용자가 페이지 경계에서 정확하게 오프셋을 선택해야 하는데 이는 번거롭고 오류가 발생하기 쉽습니다. 반면에 mio는 이를 내부적으로 관리하여 오프셋을 받아들이고 가장 가까운 페이지 경계를 찾습니다.
사소한 문제이긴 하지만 Boost.Iostreams는 std::shared_ptr
사용하여 메모리 매핑된 파일 IO를 구현하여 필요하지 않더라도 공유 의미 체계를 제공하며 힙 할당의 오버헤드는 불필요하거나 원치 않을 수 있습니다. mio에는 두 가지 사용 사례를 처리하는 두 가지 클래스가 있습니다. 하나는 이동 전용 클래스(기본적으로 시스템 특정 mmapping 기능에 대한 비용이 들지 않는 추상화)이고 다른 하나는 Boost.Iostreams와 동일하게 작동합니다. 공유 의미론.
참고: 매핑을 생성하기 전에 파일이 존재해야 합니다.
파일을 메모리에 매핑하는 방법에는 세 가지가 있습니다.
std::system_error
발생시키는 생성자를 사용합니다. mio::mmap_source mmap (path, offset, size_to_map);
또는 전체 파일이 매핑되는 경우 offset
및 size_to_map
인수를 생략할 수 있습니다.
mio::mmap_source mmap (path);
std::error_code error;
mio::mmap_source mmap = mio::make_mmap_source(path, offset, size_to_map, error);
또는:
mio::mmap_source mmap = mio::make_mmap_source(path, error);
map
멤버 함수 사용: std::error_code error;
mio::mmap_source mmap;
mmap.map(path, offset, size_to_map, error);
또는:
mmap.map(path, error);
참고: 생성자를 활성화하려면 예외가 필요합니다 . -fno-exceptions
사용하여 프로젝트를 빌드하려는 경우에도 다른 방법을 사용할 수 있습니다.
또한 각 경우에 파일 경로에 대한 일부 문자열 유형을 제공하거나 기존의 유효한 파일 핸들을 사용할 수 있습니다.
# include < sys/types.h >
# include < sys/stat.h >
# include < fcntl.h >
# include < mio/mmap.hpp >
// #include <mio/mio.hpp> if using single header
# include < algorithm >
int main ()
{
// NOTE: error handling omitted for brevity.
const int fd = open ( " file.txt " , O_RDONLY);
mio::mmap_source mmap (fd, 0 , mio::map_entire_file);
// ...
}
그러나 mio는 제공된 파일 설명자가 원하는 매핑과 동일한 액세스 권한을 가지고 있는지 확인하지 않으므로 매핑이 실패할 수 있습니다. 이러한 오류는 매핑 함수에 전달되는 std::error_code
출력 매개변수를 통해 보고됩니다.
WINDOWS 사용자 : 이 라이브러리는 문자열이 필요한 함수(예: 경로 매개변수)에 대해 와이드 문자 유형의 사용을 지원 합니다 .
# include < mio/mmap.hpp >
// #include <mio/mio.hpp> if using single header
# include < system_error > // for std::error_code
# include < cstdio > // for std::printf
# include < cassert >
# include < algorithm >
# include < fstream >
int handle_error ( const std::error_code& error);
void allocate_file ( const std::string& path, const int size);
int main ()
{
const auto path = " file.txt " ;
// NOTE: mio does *not* create the file for you if it doesn't exist! You
// must ensure that the file exists before establishing a mapping. It
// must also be non-empty. So for illustrative purposes the file is
// created now.
allocate_file (path, 155 );
// Read-write memory map the whole file by using `map_entire_file` where the
// length of the mapping is otherwise expected, with the factory method.
std::error_code error;
mio::mmap_sink rw_mmap = mio::make_mmap_sink (
path, 0 , mio::map_entire_file, error);
if (error) { return handle_error (error); }
// You can use any iterator based function.
std::fill (rw_mmap. begin (), rw_mmap. end (), ' a ' );
// Or manually iterate through the mapped region just as if it were any other
// container, and change each byte's value (since this is a read-write mapping).
for ( auto & b : rw_mmap) {
b += 10 ;
}
// Or just change one value with the subscript operator.
const int answer_index = rw_mmap. size () / 2 ;
rw_mmap[answer_index] = 42 ;
// Don't forget to flush changes to disk before unmapping. However, if
// `rw_mmap` were to go out of scope at this point, the destructor would also
// automatically invoke `sync` before `unmap`.
rw_mmap. sync (error);
if (error) { return handle_error (error); }
// We can then remove the mapping, after which rw_mmap will be in a default
// constructed state, i.e. this and the above call to `sync` have the same
// effect as if the destructor had been invoked.
rw_mmap. unmap ();
// Now create the same mapping, but in read-only mode. Note that calling the
// overload without the offset and file length parameters maps the entire
// file.
mio::mmap_source ro_mmap;
ro_mmap. map (path, error);
if (error) { return handle_error (error); }
const int the_answer_to_everything = ro_mmap[answer_index];
assert (the_answer_to_everything == 42 );
}
int handle_error ( const std::error_code& error)
{
const auto & errmsg = error. message ();
std::printf ( " error mapping file: %s, exiting... n " , errmsg. c_str ());
return error. value ();
}
void allocate_file ( const std::string& path, const int size)
{
std::ofstream file (path);
std::string s (size, ' 0 ' );
file << s;
}
mio::basic_mmap
은 이동 전용이지만 동일한 매핑에 대한 여러 복사본이 필요한 경우 std::shared_ptr
의미 체계가 있고 mio::basic_shared_mmap
과 동일한 인터페이스를 갖는 mio::basic_mmap
을 사용하십시오.
# include < mio/shared_mmap.hpp >
mio::shared_mmap_source shared_mmap1 ( " path " , offset, size_to_map);
mio::shared_mmap_source shared_mmap2 (std::move(mmap1)); // or use operator=
mio::shared_mmap_source shared_mmap3 (std::make_shared<mio::mmap_source>(mmap1)); // or use operator=
mio::shared_mmap_source shared_mmap4;
shared_mmap4.map( " path " , offset, size_to_map, error);
가장 일반적인 별칭이 기본적으로 제공되지만 바이트 유형( char
과 너비가 같아야 함)을 정의하는 것이 가능합니다.
using mmap_source = basic_mmap_source< char >;
using ummap_source = basic_mmap_source< unsigned char >;
using mmap_sink = basic_mmap_sink< char >;
using ummap_sink = basic_mmap_sink< unsigned char >;
하지만 C++17에서 새로운 std::byte
유형을 사용할 때와 같이 자신만의 유형을 정의하는 것이 유용할 수 있습니다.
using mmap_source = mio::basic_mmap_source<std::byte>;
using mmap_sink = mio::basic_mmap_sink<std::byte>;
일반적으로 필요하지는 않지만 mio는 사용자가 요청한 오프셋을 페이지 경계에 매핑하므로 mio/page.hpp
에 있는 mio::page_size()
호출하여 기본 시스템의 페이지 할당 세분성을 쿼리할 수 있습니다.
single_includemiomio.hpp
포함하면 Mio를 프로젝트에 단일 헤더 파일로 추가할 수 있습니다. third_party
내에서 amalgamate.py
스크립트를 실행하면 언제든지 단일 헤더 파일을 다시 생성할 수 있습니다.
python amalgamate.py -c config.json -s ../include
헤더 전용 라이브러리인 mio에는 컴파일된 구성 요소가 없습니다. 그럼에도 불구하고 많은 플랫폼과 운영 체제에서 쉽게 테스트, 설치 및 하위 프로젝트 구성을 할 수 있도록 CMake 빌드 시스템이 제공됩니다.
Mio는 작은 테스트 및 예제 모음과 함께 배포됩니다. mio가 최고 수준의 CMake 프로젝트로 구성되면 이 실행 파일 모음이 기본적으로 빌드됩니다. Mio의 테스트 실행 파일은 CMake 테스트 드라이버 프로그램인 CTest와 통합되어 있습니다.
CMake는 컴파일 및 연결을 위한 다양한 백엔드를 지원합니다.
GNU Make 또는 Ninja와 같은 정적 구성 빌드 도구를 사용하려면 다음을 수행하세요.
cd < mio source directory >
mkdir build
cd build
# Configure the build
cmake -D CMAKE_BUILD_TYPE= < Debug | Release >
-G < " Unix Makefiles " | " Ninja " > ..
# build the tests
< make | ninja | cmake --build . >
# run the tests
< make test | ninja test | cmake --build . --target test | ctest >
Visual Studio 또는 Xcode와 같은 동적 구성 빌드 도구를 사용하려면 다음을 수행하세요.
cd < mio source directory >
mkdir build
cd build
# Configure the build
cmake -G < " Visual Studio 14 2015 Win64 " | " Xcode " > ..
# build the tests
cmake --build . --config < Debug | Release >
# run the tests via ctest...
ctest --build-config < Debug | Release >
# ... or via CMake build tool mode...
cmake --build . --config < Debug | Release > --target test
물론 구성 단계에서 생성된 프로젝트 파일을 연 후 IDE 내에서 각각 all 및 테스트 대상을 통해 빌드 및 테스트 단계를 실행할 수도 있습니다.
Mio의 테스트는 CDash 소프트웨어 품질 대시보드 애플리케이션에 대한 클라이언트로 작동하도록 구성되어 있습니다. 이 작동 모드에 대한 자세한 내용은 Kitware 설명서를 참조하세요.
Mio의 빌드 시스템은 CMake의 find_package
내장 함수를 통해 설치 대상과 다운스트림 소비에 대한 지원을 제공합니다. CMake를 사용하면 구성 시 CMAKE_INSTALL_PREFIX
정의하여 지정할 수 있는 임의의 위치에 설치할 수 있습니다. 사용자 사양이 없으면 CMake는 플랫폼 운영 체제를 기반으로 하는 기존 위치에 mio를 설치합니다.
GNU Make 또는 Ninja와 같은 정적 구성 빌드 도구를 사용하려면 다음을 수행하세요.
cd < mio source directory >
mkdir build
cd build
# Configure the build
cmake [-D CMAKE_INSTALL_PREFIX = " path/to/installation " ]
[-D BUILD_TESTING = False]
-D CMAKE_BUILD_TYPE=Release
-G < " Unix Makefiles " | " Ninja " > ..
# install mio
< make install | ninja install | cmake --build . --target install >
Visual Studio 또는 Xcode와 같은 동적 구성 빌드 도구를 사용하려면 다음을 수행하세요.
cd < mio source directory >
mkdir build
cd build
# Configure the project
cmake [-D CMAKE_INSTALL_PREFIX = " path/to/installation " ]
[-D BUILD_TESTING = False]
-G < " Visual Studio 14 2015 Win64 " | " Xcode " > ..
# install mio
cmake --build . --config Release --target install
설치 루트 디렉터리가 홈 디렉터리 외부에 있는 경우 설치 순서의 마지막 명령에는 관리자 권한(예: sudo
)이 필요할 수 있습니다.
이번 설치
include/mio
하위 디렉터리에 복사합니다.share/cmake/mio
하위 디렉터리에 복사합니다. 이 후자의 단계에서는 다운스트림 CMake 프로젝트가 find_package
통해 mio를 소비할 수 있습니다. 예:
find_package ( mio REQUIRED )
target_link_libraries ( MyTarget PUBLIC mio::mio )
WINDOWS 사용자 : mio::mio
대상 #define
s WIN32_LEAN_AND_MEAN
및 NOMINMAX
. 전자는 Win API의 가져온 노출 영역을 최소화하고 후자는 Windows의 min
및 max
매크로를 비활성화하여 std::min
및 std::max
방해하지 않도록 합니다. mio 는 헤더 전용 라이브러리이므로 이러한 정의는 다운스트림 CMake 빌드로 누출됩니다. 이러한 존재로 인해 빌드에 문제가 발생하는 경우 이러한 정의를 추가하지 않는 대체 mio::mio_full_winapi
대상을 사용할 수 있습니다.
mio가 일반적인 위치가 아닌 위치에 설치된 경우 다운스트림 프로젝트에서 다음 중 하나를 통해 mio 설치 루트 디렉터리를 지정해야 할 수도 있습니다.
CMAKE_PREFIX_PATH
구성 옵션CMAKE_PREFIX_PATH
환경 변수 또는mio_DIR
환경 변수.자세한 내용은 Kitware 설명서를 참조하세요.
또한 mio는 CPack을 통해 패키지된 재배치 가능 설치를 지원합니다. 구성에 따라 빌드 디렉터리에서 다음과 같이 cpack을 호출하여 패키지 설치를 생성합니다.
cpack -G < generator name > -C Release
지원되는 생성기 목록은 플랫폼마다 다릅니다. 플랫폼에서 지원되는 생성기의 전체 목록을 보려면 cpack --help
출력을 참조하세요.
mio를 하위 프로젝트로 사용하려면 mio 저장소를 프로젝트의 종속성/외부 폴더에 복사하세요. 프로젝트가 git을 사용하여 버전 제어되는 경우 git 하위 모듈 또는 git 하위 트리를 사용하여 updstream 저장소와 동기화할 수 있습니다. 이러한 git 기능의 사용 및 상대적 이점은 이 문서의 범위를 벗어나지만 간단히 말하면 각 기능은 다음과 같이 설정될 수 있습니다.
# via git submodule
cd < my project ' s dependencies directory>
git submodule add -b master https://github.com/mandreyel/mio.git
# via git subtree
cd <my project ' s root directory >
git subtree add --prefix < path/to/dependencies > /mio
https://github.com/mandreyel/mio.git master --squash
프로젝트에 mio 하위 디렉터리가 있으면 프로젝트에 다음 줄을 추가하여 대상의 포함 경로에 mio 포함 디렉터리를 추가하면 됩니다.
add_subdirectory ( path /to/mio/ )
target_link_libraries ( MyTarget PUBLIC <mio::mio | mio> )
하위 프로젝트로서 mio의 테스트 및 예제는 빌드되지 않으며 CPack 통합은 호스트 프로젝트로 연기됩니다.