Pustaka pemetaan memori C++11 lintas platform khusus header yang mudah digunakan dengan lisensi MIT.
mio telah dibuat dengan tujuan agar mudah disertakan (yaitu tidak ada ketergantungan) dalam proyek C++ apa pun yang memerlukan file IO yang dipetakan memori tanpa perlu menarik Boost.
Silakan membuka masalah, saya akan mencoba mengatasi masalah apa pun sebaik mungkin.
Karena pemetaan memori adalah yang terbaik sejak mengiris roti!
Lebih serius lagi, motivasi utama untuk menulis perpustakaan ini daripada menggunakan Boost.Iostreams, adalah kurangnya dukungan untuk membuat pemetaan memori dengan pegangan/deskriptor file yang sudah terbuka. Hal ini dimungkinkan dengan mio.
Selain itu, solusi Boost.Iostreams mengharuskan pengguna memilih offset tepat pada batas halaman, yang rumit dan rawan kesalahan. mio, di sisi lain, mengelola ini secara internal, menerima offset apa pun dan menemukan batas halaman terdekat.
Meskipun merupakan masalah kecil, Boost.Iostreams mengimplementasikan file IO yang dipetakan memori dengan std::shared_ptr
untuk menyediakan semantik bersama, bahkan jika tidak diperlukan, dan overhead alokasi heap mungkin tidak diperlukan dan/atau tidak diinginkan. Di mio, ada dua kelas yang mencakup dua kasus penggunaan: satu yang bersifat move-only (pada dasarnya merupakan abstraksi tanpa biaya atas fungsi mmapping khusus sistem), dan yang lainnya bertindak seperti mitra Boost.Iostreams-nya, dengan semantik bersama.
CATATAN: file harus ada sebelum membuat pemetaan.
Ada tiga cara untuk memetakan file ke dalam memori:
std::system_error
jika gagal: mio::mmap_source mmap (path, offset, size_to_map);
atau Anda dapat menghilangkan argumen offset
dan size_to_map
, dalam hal ini seluruh file dipetakan:
mio::mmap_source mmap (path);
std::error_code error;
mio::mmap_source mmap = mio::make_mmap_source(path, offset, size_to_map, error);
atau:
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);
atau:
mmap.map(path, error);
CATATAN: Konstruktor memerlukan pengecualian untuk diaktifkan. Jika Anda lebih suka membangun proyek dengan -fno-exceptions
, Anda masih dapat menggunakan cara lain.
Selain itu, dalam setiap kasus, Anda dapat memberikan beberapa jenis string untuk jalur file, atau Anda dapat menggunakan pegangan file yang valid dan sudah ada.
# 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);
// ...
}
Namun, mio tidak memeriksa apakah deskriptor file yang disediakan memiliki izin akses yang sama dengan pemetaan yang diinginkan, sehingga pemetaan mungkin gagal. Kesalahan tersebut dilaporkan melalui parameter std::error_code
out yang diteruskan ke fungsi pemetaan.
PENGGUNA WINDOWS : Pustaka ini mendukung penggunaan tipe karakter lebar untuk fungsi yang mengharapkan string karakter (misalnya parameter jalur).
# 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
hanya dapat dipindahkan, tetapi jika diperlukan beberapa salinan untuk pemetaan yang sama, gunakan mio::basic_shared_mmap
yang memiliki semantik std::shared_ptr
dan memiliki antarmuka yang sama dengan 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);
Tipe byte dapat ditentukan (yang lebarnya harus sama dengan char
), meskipun alias untuk byte yang paling umum disediakan secara default:
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 >;
Namun mungkin berguna untuk mendefinisikan tipe Anda sendiri, misalnya saat menggunakan tipe std::byte
baru di C++17:
using mmap_source = mio::basic_mmap_source<std::byte>;
using mmap_sink = mio::basic_mmap_sink<std::byte>;
Meskipun umumnya tidak diperlukan, karena pengguna mio memetakan offset ke batas halaman, Anda dapat menanyakan granularitas alokasi halaman sistem yang mendasarinya dengan memanggil mio::page_size()
, yang terletak di mio/page.hpp
.
Mio dapat ditambahkan ke proyek Anda sebagai file header tunggal hanya dengan menyertakan single_includemiomio.hpp
. File header tunggal dapat dibuat ulang kapan saja dengan menjalankan skrip amalgamate.py
dalam third_party
.
python amalgamate.py -c config.json -s ../include
Sebagai perpustakaan khusus header, mio tidak memiliki komponen yang dikompilasi. Namun demikian, sistem build CMake disediakan untuk memudahkan pengujian, instalasi, dan komposisi subproyek di banyak platform dan sistem operasi.
Mio didistribusikan dengan serangkaian kecil tes dan contoh. Ketika mio dikonfigurasikan sebagai proyek CMake tingkat tertinggi, rangkaian executable ini dibuat secara default. Eksekusi uji Mio terintegrasi dengan program driver uji CMake, CTest.
CMake mendukung sejumlah backend untuk kompilasi dan penautan.
Untuk menggunakan alat pembuatan konfigurasi statis, seperti GNU Make atau 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 >
Untuk menggunakan alat pembuatan konfigurasi dinamis, seperti Visual Studio atau 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
Tentu saja langkah build dan test juga dapat dijalankan melalui target all dan test masing-masing dari dalam IDE setelah membuka file proyek yang dihasilkan selama langkah konfigurasi.
Pengujian Mio juga dikonfigurasi untuk beroperasi sebagai klien pada aplikasi dasbor kualitas perangkat lunak CDash. Silakan lihat dokumentasi Kitware untuk informasi lebih lanjut tentang mode operasi ini.
Sistem build Mio menyediakan target instalasi dan dukungan untuk konsumsi hilir melalui fungsi intrinsik find_package
CMake. CMake memungkinkan instalasi ke lokasi sewenang-wenang, yang dapat ditentukan dengan mendefinisikan CMAKE_INSTALL_PREFIX
pada waktu konfigurasi. Jika tidak ada spesifikasi pengguna, CMake akan menginstal mio ke lokasi konvensional berdasarkan sistem operasi platform.
Untuk menggunakan alat pembuatan konfigurasi statis, seperti GNU Make atau 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 >
Untuk menggunakan alat pembuatan konfigurasi dinamis, seperti Visual Studio atau 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
Perhatikan bahwa perintah terakhir dari urutan instalasi mungkin memerlukan hak administrator (misalnya sudo
) jika direktori root instalasi terletak di luar direktori home Anda.
Instalasi ini
include/mio
dari root instalasishare/cmake/mio
dari root instalasi Langkah terakhir ini memungkinkan proyek CMake hilir menggunakan mio melalui find_package
, misalnya
find_package ( mio REQUIRED )
target_link_libraries ( MyTarget PUBLIC mio::mio )
PENGGUNA WINDOWS : mio::mio
target #define
s WIN32_LEAN_AND_MEAN
dan NOMINMAX
. Yang pertama memastikan luas permukaan yang diimpor dari Win API minimal, dan yang terakhir menonaktifkan makro min
dan max
Windows sehingga tidak mengganggu std::min
dan std::max
. Karena mio hanyalah pustaka header, definisi ini akan bocor ke build CMake hilir. Jika kehadirannya menyebabkan masalah pada build Anda, maka Anda dapat menggunakan target mio::mio_full_winapi
alternatif, yang tidak menambahkan definisi berikut.
Jika mio diinstal ke lokasi non-konvensional, proyek hilir mungkin perlu menentukan direktori root instalasi mio melalui salah satu
CMAKE_PREFIX_PATH
,CMAKE_PREFIX_PATH
, ataumio_DIR
.Silakan lihat dokumentasi Kitware untuk informasi lebih lanjut.
Selain itu, mio mendukung instalasi paket yang dapat direlokasi melalui CPack. Konfigurasi berikut, dari direktori build, aktifkan cpack sebagai berikut untuk menghasilkan instalasi terpaket:
cpack -G < generator name > -C Release
Daftar generator yang didukung bervariasi dari satu platform ke platform lainnya. Lihat keluaran cpack --help
untuk daftar lengkap generator yang didukung di platform Anda.
Untuk menggunakan mio sebagai subproyek, salin repositori mio ke folder dependensi/eksternal proyek Anda. Jika proyek Anda dikontrol versinya menggunakan git, submodul git atau subpohon git dapat digunakan untuk melakukan sinkronisasi dengan repositori updstream. Penggunaan dan keuntungan relatif dari fasilitas git ini berada di luar cakupan dokumen ini, namun secara singkat, masing-masing fasilitas dapat ditetapkan sebagai berikut:
# 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
Mengingat subdirektori mio dalam sebuah proyek, cukup tambahkan baris berikut ke proyek Anda untuk menambahkan direktori mio include ke jalur include target Anda.
add_subdirectory ( path /to/mio/ )
target_link_libraries ( MyTarget PUBLIC <mio::mio | mio> )
Perhatikan bahwa, sebagai subproyek, pengujian dan contoh mio tidak akan dibuat dan integrasi CPack ditangguhkan ke proyek host.