mirror of
https://github.com/vimpunk/mio.git
synced 2025-12-07 01:06:51 +08:00
Calling the operating system's API makes a lot more sense. Exceptions are definitely thrown for non-existent files. Formatting the source code makes it more readable. Remove the direct use of the c++ 2011 type trait, All switched to c++2020 concepts and type constraints. Update README.md
348 lines
13 KiB
C++
348 lines
13 KiB
C++
/*
|
||
* Copyright (C) 2022-2030 Twilight-Dream
|
||
*
|
||
* 本文件是 mio 的一部分。
|
||
*
|
||
* mio 是自由软件:你可以再分发之和/或依照由自由软件基金会发布的 GNU 通用公共许可证修改之,无论是版本 3 许可证,还是(按你的决定)任何以后版都可以。
|
||
*
|
||
* 发布 TDOM-EncryptOrDecryptFile-Reborn 是希望它能有用,但是并无保障;甚至连可销售和符合某个特定的目的都不保证。请参看 GNU 通用公共许可证,了解详情。
|
||
* 你应该随程序获得一份 GNU 通用公共许可证的复本。如果没有,请看 <https://www.gnu.org/licenses/>。
|
||
*/
|
||
|
||
/*
|
||
* Copyright (C) 2022-2030 Twilight-Dream
|
||
*
|
||
* This file is part of mio.
|
||
*
|
||
* mio is free software: you may redistribute it and/or modify it under the GNU General Public License as published by the Free Software Foundation, either under the Version 3 license, or (at your discretion) any later version.
|
||
*
|
||
* mio is released in the hope that it will be useful, but there are no guarantees; not even that it will be marketable and fit a particular purpose. Please see the GNU General Public License for details.
|
||
* You should get a copy of the GNU General Public License with your program. If not, see <https://www.gnu.org/licenses/>.
|
||
*/
|
||
#pragma once
|
||
|
||
#include "mio/mio.hpp"
|
||
|
||
//将文件数据进行镜像(映射)到操作系统的内存对象。以实现对磁盘的大文件(这里规定大小大于4GB)的字节流模拟访问和修改
|
||
//Mirroring (mapping) file data to the operating system's memory objects. to enable byte stream emulation access and modification of large files (here specified size > 4 giga byte) on disk
|
||
namespace MemoryObjectConfrontationDiskFileData
|
||
{
|
||
/*
|
||
|
||
Use C++ project mio
|
||
|
||
Github https://github.com/mandreyel/mio
|
||
|
||
An easy to use header-only cross-platform C++11 memory mapping library with an MIT license.
|
||
mio has been created with the goal to be easily includable (i.e. no dependencies) in any C++ project that needs memory mapped file IO without the need to pull in C++ Boost library.
|
||
Please feel free to open an issue, I'll try to address any concerns as best I can.
|
||
|
||
一个易于使用的头文件跨平台的C++11内存映射库,拥有MIT许可证。
|
||
创建mio的目的是为了在任何需要内存映射文件IO的C++项目中都能方便地包含(即没有依赖性),而不需要拉入C++ Boost 库。
|
||
请随时提出问题,我将尽力解决任何问题。
|
||
|
||
*/
|
||
|
||
template <typename Type>
|
||
concept TemplateConcept_MemoryMap = std::is_same_v<Type, mio::mmap_source> || std::is_same_v<Type, mio::mmap_sink> || std::is_same_v<Type, mio::ummap_source> || std::is_same_v<Type, mio::ummap_sink>;
|
||
|
||
template <typename Type>
|
||
concept TemplateConcept_MemoryMap_ReadAndWrite = std::is_same_v<Type, mio::mmap_sink> || std::is_same_v<Type, mio::ummap_sink>;
|
||
|
||
enum class MemoryMapTypes
|
||
{
|
||
SIGNED_READ_AND_WRITE = 0,
|
||
SIGNED_READ_ONLY = 1,
|
||
UNSIGNED_READ_AND_WRITE = 2,
|
||
UNSIGNED_READ_ONLY = 3
|
||
};
|
||
|
||
class MemoryMapPointers
|
||
{
|
||
|
||
private:
|
||
|
||
std::unique_ptr<mio::mmap_sink> pointer_signed_rw;
|
||
std::unique_ptr<mio::mmap_source> pointer_signed_ro;
|
||
std::unique_ptr<mio::ummap_sink> pointer_unsigned_rw;
|
||
std::unique_ptr<mio::ummap_source> pointer_unsigned_ro;
|
||
|
||
public:
|
||
|
||
std::unique_ptr<mio::mmap_sink>& signed_rw()
|
||
{
|
||
return pointer_signed_rw;
|
||
}
|
||
|
||
std::unique_ptr<mio::mmap_source>& signed_ro()
|
||
{
|
||
return pointer_signed_ro;
|
||
}
|
||
|
||
std::unique_ptr<mio::ummap_sink>& unsigned_rw()
|
||
{
|
||
return pointer_unsigned_rw;
|
||
}
|
||
|
||
std::unique_ptr<mio::ummap_source>& unsigned_ro()
|
||
{
|
||
return pointer_unsigned_ro;
|
||
}
|
||
|
||
MemoryMapPointers() noexcept : pointer_signed_rw( nullptr ), pointer_signed_ro( nullptr ), pointer_unsigned_rw( nullptr ), pointer_unsigned_ro( nullptr ) {}
|
||
|
||
MemoryMapPointers(MemoryMapPointers& _object) = delete;
|
||
MemoryMapPointers& operator=(const MemoryMapPointers _object) = delete;
|
||
|
||
MemoryMapPointers( MemoryMapTypes map_types )
|
||
{
|
||
switch ( map_types )
|
||
{
|
||
case MemoryMapTypes::SIGNED_READ_AND_WRITE:
|
||
{
|
||
this->pointer_signed_rw = std::unique_ptr<mio::mmap_sink, std::default_delete<mio::mmap_sink>>( new mio::mmap_sink, std::default_delete<mio::mmap_sink>() );
|
||
break;
|
||
}
|
||
case MemoryMapTypes::SIGNED_READ_ONLY:
|
||
{
|
||
this->pointer_signed_ro = std::unique_ptr<mio::mmap_source, std::default_delete<mio::mmap_source>>( new mio::mmap_source, std::default_delete<mio::mmap_source>() );
|
||
break;
|
||
}
|
||
case MemoryMapTypes::UNSIGNED_READ_AND_WRITE:
|
||
{
|
||
this->pointer_unsigned_rw = std::unique_ptr<mio::ummap_sink, std::default_delete<mio::ummap_sink>>( new mio::ummap_sink, std::default_delete<mio::ummap_sink>() );
|
||
break;
|
||
}
|
||
case MemoryMapTypes::UNSIGNED_READ_ONLY:
|
||
{
|
||
this->pointer_unsigned_ro = std::unique_ptr<mio::ummap_source, std::default_delete<mio::ummap_source>>( new mio::ummap_source, std::default_delete<mio::ummap_source>() );
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
~MemoryMapPointers()
|
||
{
|
||
if ( !( pointer_signed_rw == nullptr ) )
|
||
{
|
||
auto* pointer = pointer_signed_rw.release();
|
||
pointer = nullptr;
|
||
}
|
||
|
||
if ( !( pointer_signed_ro == nullptr ) )
|
||
{
|
||
auto* pointer = pointer_signed_ro.release();
|
||
pointer = nullptr;
|
||
}
|
||
|
||
if ( !( pointer_unsigned_rw == nullptr ) )
|
||
{
|
||
auto* pointer = pointer_unsigned_rw.release();
|
||
pointer = nullptr;
|
||
}
|
||
|
||
if ( !( pointer_unsigned_ro == nullptr ) )
|
||
{
|
||
auto* pointer = pointer_unsigned_ro.release();
|
||
pointer = nullptr;
|
||
}
|
||
}
|
||
};
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
bool MMMO_CheckIsAssocisatedFile( MemoryMapType& mapped_object );
|
||
|
||
inline MemoryMapPointers MakeDefaultMemoryMappingObject( MemoryMapTypes map_types );
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
std::tuple<bool, MemoryMapType> MMMO_TryAssociateFile_ToPack( const std::filesystem::path& file_path_name, MemoryMapType* memory_map_pointer );
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
bool MMMO_FromUnpack( std::tuple<bool, MemoryMapType>& associated_data, MemoryMapType& default_memory_map_object);
|
||
|
||
template <typename MemoryMapType_ReadAndWrite>
|
||
requires TemplateConcept_MemoryMap_ReadAndWrite<MemoryMapType_ReadAndWrite>
|
||
void MMMO_TrySyncDiskFile( MemoryMapType_ReadAndWrite& mapped );
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
bool UnmappingMemoryMapObject( MemoryMapType& mapped );
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
inline bool MMMO_CheckIsAssocisatedFile( MemoryMapType& mapped_object )
|
||
{
|
||
if ( !mapped_object.is_mapped() )
|
||
{
|
||
std::cerr << CommonToolkit::from_u8string(u8"你开玩笑呢?这个内存映射对象根本就没有关联一个文件。") << std::endl;
|
||
std::cerr << "Are you kidding me? This memory mapped object is not associated with a file at all." << std::endl;
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
//创建一个内存映射对象
|
||
//Create a memory map object
|
||
inline MemoryMapPointers MakeDefaultMemoryMappingObject( MemoryMapTypes map_types )
|
||
{
|
||
return MemoryMapPointers( map_types );
|
||
}
|
||
|
||
//提供一个内存映射对象,然后尝试关联文件
|
||
//Provide a memory map object and then try to associate the file
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
std::tuple<bool, MemoryMapType> MMMO_TryAssociateFile_ToPack( const std::filesystem::path& file_path_name, MemoryMapType* memory_map_pointer )
|
||
{
|
||
auto this_file_path_name = std::move( file_path_name );
|
||
auto& memory_map_reference = *memory_map_pointer;
|
||
|
||
if constexpr( std::same_as<std::remove_reference_t<decltype(memory_map_reference)>, mio::mmap_sink> || std::same_as<std::remove_reference_t<decltype(memory_map_reference)>, mio::ummap_sink> )
|
||
{
|
||
std::fstream file_stream_object;
|
||
|
||
if ( std::filesystem::exists( file_path_name ) )
|
||
{
|
||
std::u8string u8string_extension_name = u8".newfile";
|
||
this_file_path_name += CommonToolkit::from_u8string(u8string_extension_name);
|
||
std::filesystem::copy(file_path_name, this_file_path_name);
|
||
|
||
//文件打开后立即寻找流的末端
|
||
//seek to the end of stream immediately after open
|
||
file_stream_object.open( this_file_path_name, std::ios::in | std::ios::out | std::ios::ate | std::ios::binary );
|
||
|
||
if(file_stream_object.is_open())
|
||
{
|
||
//立即关闭文件
|
||
//Close the file now
|
||
file_stream_object.close();
|
||
}
|
||
}
|
||
}
|
||
|
||
memory_map_reference.map( this_file_path_name.string(), 0, mio::map_entire_file );
|
||
|
||
if ( !memory_map_reference.is_open() )
|
||
{
|
||
std::cerr << CommonToolkit::from_u8string(u8"呃,你确定那个文件的路径确实存在吗?你需要好好检查一下。") << std::endl;
|
||
std::cerr << "Uh, are you sure the path to that file actually exists? You need to check it properly." << std::endl;
|
||
|
||
std::cerr << CommonToolkit::from_u8string(u8"内存映射对象无效,可能是文件无法访问或者内存不足。\n文件路径是: ")
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
std::cerr << "The memory mapped object is invalid, probably because the file is inaccessible or out of memory.\nThe file path is. "
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
UnmappingMemoryMapObject( memory_map_reference );
|
||
return std::make_tuple( std::move( false ), std::move( memory_map_reference ) );
|
||
}
|
||
else
|
||
{
|
||
if ( MMMO_CheckIsAssocisatedFile( memory_map_reference ) )
|
||
{
|
||
std::cout << CommonToolkit::from_u8string(u8"内存映射对象已经关联文件\n文件路径是: ")
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
std::cout << "The memory mapped object has associated files.\nThe file path is: "
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
return std::make_tuple( std::move( true ), std::move( memory_map_reference ) );
|
||
}
|
||
else
|
||
{
|
||
std::cerr << CommonToolkit::from_u8string(u8"内存映射对象不能关联文件,文件路径是: ")
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
std::cerr << "The memory mapped objects cannot be associated with files.\nThe file path is. "
|
||
<< "[" << CommonToolkit::from_u8string(file_path_name.u8string()) << "]" << std::endl;
|
||
UnmappingMemoryMapObject( memory_map_reference );
|
||
return std::make_tuple( std::move( false ), std::move( memory_map_reference ) );
|
||
}
|
||
}
|
||
}
|
||
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
bool MMMO_FromUnpack( std::tuple<bool, MemoryMapType>& associated_data, MemoryMapType& default_memory_map_object )
|
||
{
|
||
#if __cplusplus >= 201703L
|
||
|
||
auto& [associated_mmap_data_package_status, memory_map_object] = associated_data;
|
||
|
||
if ( associated_mmap_data_package_status )
|
||
{
|
||
default_memory_map_object = std::move( memory_map_object );
|
||
return associated_mmap_data_package_status;
|
||
}
|
||
else
|
||
{
|
||
return associated_mmap_data_package_status;
|
||
}
|
||
|
||
#else
|
||
|
||
bool associated_mmap_data_package_status = std::get<bool>( associated_data );
|
||
|
||
if ( associated_mmap_data_package_status )
|
||
{
|
||
default_memory_map_object = std::move( std::get<MemoryMapType>( associated_data ) );
|
||
return associated_mmap_data_package_status;
|
||
}
|
||
else
|
||
{
|
||
return associated_mmap_data_package_status;
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
//已经映射完成的内存对象,只要内存对象管理的数据发生改变时,就需要同步磁盘文件数据进行写入
|
||
//Whenever the memory object is mapped, the data managed by the memory object is changed, the disk file data needs to be synchronized for writing.
|
||
template <typename MemoryMapType_ReadAndWrite>
|
||
requires TemplateConcept_MemoryMap_ReadAndWrite<MemoryMapType_ReadAndWrite>
|
||
void MMMO_TrySyncDiskFile( MemoryMapType_ReadAndWrite& mapped_object )
|
||
{
|
||
if ( mapped_object.is_open() && mapped_object.is_mapped() )
|
||
{
|
||
std::cout << CommonToolkit::from_u8string(u8"好了,试着把内存映射对象管理的数据的变化同步到磁盘上。") << std::endl;
|
||
std::cout << "OK, try synchronizing the changes in the data managed by the memory mapped object to the disk." << std::endl;
|
||
mapped_object.sync();
|
||
}
|
||
}
|
||
|
||
//提供一个内存映射对象,然后解除关联文件。
|
||
//Provide a memory map object and then unassociate the file
|
||
template <typename MemoryMapType>
|
||
requires TemplateConcept_MemoryMap<MemoryMapType>
|
||
inline bool UnmappingMemoryMapObject( MemoryMapType& mapped_object )
|
||
{
|
||
if ( MMMO_CheckIsAssocisatedFile( mapped_object ) )
|
||
{
|
||
mapped_object.unmap();
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
//测试代码是否可以被编译
|
||
//Test if the code can be compiled
|
||
#if 0
|
||
|
||
MemoryMapPointers mmp_pointer_object = MakeDefaultMemoryMappingObject(MIO_LibraryHelper::MemoryMapTypes::SIGNED_READ_AND_WRITE);
|
||
auto* managed_pointer = mmp_pointer_object.signed_rw().get();
|
||
auto associated_mmap_data_package = MMMO_TryAssociateFile_ToPack(std::string("./filename.dat"), managed_pointer);
|
||
bool associated_mmap_data_unpackage_status;
|
||
auto mapped_object = MMMO_FromUnpack(associated_mmap_data_package, associated_mmap_data_unpackage_status);
|
||
MMMO_TrySyncDiskFile(mapped_object);
|
||
bool unmake_status = UnmappingMemoryMapObject(mapped_object);
|
||
|
||
#endif
|
||
} // namespace MemoryObjectConfrontationDiskFileData
|