1 // 2 // memory_buffer.hpp 3 // 4 // Copyright © 2024 Apple Inc. All rights reserved. 5 // 6 // Please refer to the license found in the LICENSE file in the root directory of the source tree. 7 8 #pragma once 9 10 #include <memory> 11 #include <stdio.h> 12 #include <string> 13 #include <system_error> 14 #include <vector> 15 16 #include "range.hpp" 17 18 namespace inmemoryfs { 19 /// A class representing a memory buffer. 20 class MemoryBuffer: public std::enable_shared_from_this<MemoryBuffer> { 21 public: 22 /// The kind of buffer. 23 enum class Kind: uint8_t { 24 MMap = 0, // If the buffer is memory mapped. 25 Malloc , // If the buffer is heap allocated. 26 }; 27 28 enum class ReadOption: uint8_t { 29 Malloc = 0, 30 MMap, 31 LazyMMap 32 }; 33 MemoryBuffer(void * data,size_t size,Kind kind=Kind::Malloc,std::shared_ptr<MemoryBuffer> parent=nullptr)34 inline MemoryBuffer(void *data, 35 size_t size, 36 Kind kind = Kind::Malloc, 37 std::shared_ptr<MemoryBuffer> parent = nullptr) noexcept: 38 data_(data), 39 size_(size), 40 kind_(kind), 41 parent_(parent) 42 {} 43 44 MemoryBuffer(const MemoryBuffer &) = delete; 45 MemoryBuffer &operator=(const MemoryBuffer &) = delete; 46 ~MemoryBuffer()47 virtual ~MemoryBuffer() noexcept {} 48 49 /// Returns the underlying data. data()50 virtual inline void *data() noexcept { 51 return data_; 52 } 53 54 /// Returns the size of the buffer. size() const55 inline const size_t size() const noexcept { 56 return size_; 57 } 58 59 /// Loads the contents of the buffer. 60 /// 61 /// - For a malloced buffer, the method is a no op, content is loaded at the initialization time. 62 /// - For a memory mapped buffer, the method can result in memory mapping the contents of the backed file. 63 /// 64 /// @param error On failure, error is populated with the failure reason. 65 /// @retval `true` if the copy succeeded otherwise `false`. load(std::error_code & error)66 inline virtual bool load(std::error_code& error) noexcept { 67 return true; 68 } 69 70 /// Returns the kind of the buffer. kind() const71 inline const Kind kind() const noexcept { 72 return kind_; 73 } 74 75 /// Returns the offset range that would be used when writing the buffer content. 76 /// 77 /// @param proposed_offset The proposed offset. 78 /// @retval The offset range that would be used when writing the buffer content. get_offset_range(size_t proposed_offset) const79 inline virtual std::pair<size_t, size_t> get_offset_range(size_t proposed_offset) const noexcept { 80 return {proposed_offset, proposed_offset}; 81 } 82 83 /// Returns the revised range that must be used for writing. 84 /// 85 /// @param dst The destination pointer. 86 /// @param proposed_range The proposed offset and size for writing the buffer content. 87 /// @retval The revised offset and size that must be used to write the buffer content. get_revised_range_for_writing(void * dst,Range proposed_range) const88 inline virtual Range get_revised_range_for_writing(void *dst, Range proposed_range) const noexcept { 89 return proposed_range; 90 } 91 92 /// Writes the contents of the buffer to the destination buffer at the given offset. 93 /// 94 /// @param dst The destination pointer. 95 /// @param offset The offset. 96 /// @param error On failure, error is populated with the failure reason. 97 /// @retval `true` if the write succeeded otherwise `false`. 98 virtual bool write(void *dst, 99 size_t offset, 100 std::error_code& error) noexcept; 101 102 /// Slices a buffer. 103 /// 104 /// @param range The memory range. 105 /// @retval The sliced buffer if the region is inside the buffer otherwise `nullptr`. 106 virtual std::shared_ptr<MemoryBuffer> slice(Range range) noexcept; 107 108 /// Reads the file content at the specified path. 109 /// 110 /// @param file_path The file path. 111 /// @param ranges The ranges to be read. 112 /// @param option The read option. 113 /// @param error On failure, error is populated with the failure reason. 114 /// @retval The read buffers or an empty vector if the read failed. 115 static std::vector<std::shared_ptr<MemoryBuffer>> 116 read_file_content(const std::string& file_path, 117 const std::vector<Range>& ranges, 118 ReadOption option, 119 std::error_code& error); 120 121 /// Reads the whole file content at the specified path. 122 /// 123 /// @param file_path The file path. 124 /// @param option The read option. 125 /// @param error On failure, error is populated with the failure reason. 126 /// @retval The read buffer or `nullptr` if the read failed. 127 static std::shared_ptr<MemoryBuffer> 128 read_file_content(const std::string& file_path, 129 ReadOption option, 130 std::error_code& error); 131 132 /// Constructs a `MemoryBuffer`. 133 /// 134 /// @param size The size of the buffer. 135 /// @param alignment The address alignment. 136 static std::unique_ptr<MemoryBuffer> 137 make_using_malloc(size_t size, size_t alignment = 1); 138 139 140 /// Constructs a `MemoryBuffer` from memory allocated using `mmap`. 141 /// 142 /// @param size The size of the buffer. 143 static std::unique_ptr<MemoryBuffer> 144 make_using_mmap(size_t size); 145 146 /// Constructs a `MemoryBuffer` without copying data. 147 /// 148 /// @param data The buffer content. 149 /// @param size The size of the buffer. 150 static std::unique_ptr<MemoryBuffer> 151 make_unowned(void *data, size_t size); 152 153 /// Constructs a `MemoryBuffer` with copying data. 154 /// 155 /// @param data The buffer content. 156 /// @param size The size of the buffer. 157 static std::unique_ptr<MemoryBuffer> 158 make_copy(void *data, size_t size); 159 private: 160 void *data_; 161 const size_t size_; 162 Kind kind_; 163 const std::shared_ptr<MemoryBuffer> parent_; 164 }; 165 } 166