mmf.hxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #ifndef MMF_H
  2. #define MMF_H
  3. #include <cstddef>
  4. #include <string>
  5. #include <iterator>
  6. #include "mmap_wrapper.hxx"
  7. #ifdef _WIN32
  8. #define IF_WIN(exp) exp
  9. #define IF_UNIX(exp)
  10. #else
  11. #define IF_WIN(exp)
  12. #define IF_UNIX(exp) exp
  13. #include <sys/mman.h>
  14. #include <unistd.h>
  15. #endif
  16. namespace pmmf {
  17. class MappedFile {
  18. public:
  19. template<typename T>
  20. class MappedData {
  21. friend class MappedFile;
  22. FileDescriptor file_descriptor = INVALID_FILE_DESCRIPTOR;
  23. size_t offset = -1;
  24. size_t byte_offset = -1;
  25. size_t element_count = -1;
  26. void* page_start = nullptr;
  27. MappedData(FileDescriptor file_descriptor, size_t offset, size_t byte_offset, size_t element_count, void* page_start)
  28. : file_descriptor(file_descriptor), offset(offset), byte_offset(byte_offset), element_count(element_count), page_start(page_start) {}
  29. T* getDataStart() const { return reinterpret_cast<T*>(reinterpret_cast<char*>(page_start) + byte_offset); }
  30. public:
  31. MappedData() = default;
  32. MappedData(const MappedData<T>&) = delete;
  33. MappedData(MappedData<T>&& other)
  34. : file_descriptor(other.file_descriptor), offset(other.offset), byte_offset(other.byte_offset), element_count(other.element_count), page_start(other.page_start) {
  35. other.file_descriptor = INVALID_FILE_DESCRIPTOR;
  36. other.offset = -1;
  37. other.byte_offset = -1;
  38. other.element_count = -1;
  39. other.page_start = nullptr;
  40. }
  41. ~MappedData() {
  42. if(page_start) {
  43. flush();
  44. munmap(page_start, byte_offset + element_count * sizeof(T));
  45. }
  46. }
  47. inline bool isMapped() const { return !!page_start; }
  48. inline size_t getDataOffset() const { return offset + byte_offset; }
  49. inline size_t getPageOffset() const { return offset; }
  50. inline size_t getElementCount() const { return element_count; }
  51. inline size_t getDataSize() const { return element_count * sizeof(T); }
  52. inline size_t getPageSize() const { return byte_offset + element_count * sizeof(T); }
  53. inline T& operator[](size_t index) { return *(getDataStart() + index); }
  54. inline const T& operator[](size_t index) const { return *(getDataStart() + index); }
  55. inline T& operator*() { return *getDataStart(); }
  56. inline const T& operator*() const { return *getDataStart(); }
  57. inline T* operator->() { return getDataStart(); }
  58. inline const T* operator->() const { return getDataStart(); }
  59. inline T* begin() { return getDataStart(); }
  60. inline T* end() { return getDataStart() + element_count; }
  61. inline const T* begin() const { return getDataStart(); }
  62. inline const T* end() const { return getDataStart() + element_count; }
  63. inline const T* cbegin() const { return getDataStart(); }
  64. inline const T* cend() const { return getDataStart() + element_count; }
  65. inline std::reverse_iterator<T*> rbegin() { return getDataStart() + element_count - 1; }
  66. inline std::reverse_iterator<T*> rend() { return getDataStart() - 1; }
  67. inline std::reverse_iterator<const T*> rbegin() const { return getDataStart() + element_count - 1; }
  68. inline std::reverse_iterator<const T*> rend() const { return getDataStart() - 1; }
  69. inline std::reverse_iterator<const T*> crbegin() const { return getDataStart() + element_count - 1; }
  70. inline std::reverse_iterator<const T*> crend() const { return getDataStart() - 1; }
  71. bool flush() {
  72. #ifdef _WIN32
  73. constexpr int MS_SYNC = 0;
  74. #endif
  75. if(isMapped()) return msync(file_descriptor, page_start, byte_offset + element_count * sizeof(T), MS_SYNC) == 0;
  76. return false;
  77. }
  78. MappedData<T>& operator=(MappedData<T>&& other) {
  79. ~MappedData<T>();
  80. return new(this) MappedData<T>(std::move(other));
  81. }
  82. };
  83. template<typename T>
  84. friend class MappedData;
  85. private:
  86. static size_t getSystemPageSize();
  87. static inline const size_t OS_PAGE_SIZE = getSystemPageSize();
  88. FileDescriptor file_descriptor = INVALID_FILE_DESCRIPTOR;
  89. ProtectionMode proterction_mode = ProtectionMode(0x00);
  90. MapFlag map_flag = MapFlag(0x00);
  91. FileDescriptor openFile(std::string file_path, ProtectionMode protection_mode);
  92. public:
  93. MappedFile(std::string file_path, ProtectionMode protection_mode = ProtectionMode::rw, MapFlag map_flag = MapFlag::shared);
  94. MappedFile(const MappedFile&) = delete;
  95. MappedFile(MappedFile&& other)
  96. : file_descriptor(other.file_descriptor),
  97. proterction_mode(other.proterction_mode),
  98. map_flag(other.map_flag) {
  99. other.file_descriptor = INVALID_FILE_DESCRIPTOR;
  100. other.proterction_mode = ProtectionMode(0);
  101. other.map_flag = MapFlag(0);
  102. }
  103. ~MappedFile();
  104. static inline size_t getOSPageSize() { return OS_PAGE_SIZE; }
  105. inline bool isFileOpen() const { return file_descriptor != INVALID_FILE_DESCRIPTOR; }
  106. size_t getFileSize() const;
  107. template<typename T>
  108. MappedData<T> getMappedData(size_t byte_offset, size_t element_count = 1) {
  109. if(!isFileOpen())
  110. return MappedData<T>(INVALID_FILE_DESCRIPTOR, -1, -1, -1, nullptr);
  111. #ifndef _WIN32
  112. if(getFileSize() < byte_offset + element_count * sizeof(T))
  113. if(ftruncate64(file_descriptor, byte_offset + element_count * sizeof(T)) != 0)
  114. return MappedData<T>(INVALID_FILE_DESCRIPTOR, -1, -1, -1, nullptr);
  115. #endif
  116. const size_t page_aligned_offset = (byte_offset / OS_PAGE_SIZE) * OS_PAGE_SIZE;
  117. byte_offset = byte_offset - page_aligned_offset;
  118. void* page_start = mmap(nullptr, byte_offset + element_count * sizeof(T), proterction_mode, map_flag, file_descriptor, page_aligned_offset);
  119. if(page_start == (void*)-1)
  120. return MappedData<T>(INVALID_FILE_DESCRIPTOR, -1, -1, -1, nullptr);
  121. return MappedData<T>(file_descriptor, page_aligned_offset, byte_offset, element_count, page_start);
  122. }
  123. };
  124. template <typename T>
  125. using MappedData = MappedFile::MappedData<T>;
  126. }
  127. #undef OS_DEP
  128. #endif //MMF_H