1 // 2 // Copyright RIME Developers 3 // Distributed under the BSD License 4 // 5 // 2011-06-27 GONG Chen <chen.sst@gmail.com> 6 // 7 #ifndef RIME_MAPPED_FILE_H_ 8 #define RIME_MAPPED_FILE_H_ 9 10 #include <stdint.h> 11 #include <cstring> 12 #include <boost/utility.hpp> 13 #include <rime_api.h> 14 #include <rime/common.h> 15 16 namespace rime { 17 18 // basic data structure 19 20 // Limitation: cannot point to itself (zero is used to represent NULL pointer) 21 template <class T = char, class Offset = int32_t> 22 class OffsetPtr { 23 public: 24 OffsetPtr() = default; OffsetPtr(Offset offset)25 OffsetPtr(Offset offset) : offset_(offset) {} OffsetPtr(const T * ptr)26 OffsetPtr(const T* ptr) : OffsetPtr(to_offset(ptr)) {} OffsetPtr(const OffsetPtr<T> & ptr)27 OffsetPtr(const OffsetPtr<T>& ptr) : OffsetPtr(ptr.get()) {} 28 OffsetPtr<T>& operator= (const OffsetPtr<T>& ptr) { 29 offset_ = to_offset(ptr.get()); 30 return *this; 31 } 32 OffsetPtr<T>& operator= (const T* ptr) { 33 offset_ = to_offset(ptr); 34 return *this; 35 } 36 operator bool() const { 37 return !!offset_; 38 } 39 T* operator-> () const { 40 return get(); 41 } 42 T& operator* () const { 43 return *get(); 44 } 45 T& operator[] (size_t index) const { 46 return *(get() + index); 47 } get()48 T* get() const { 49 if (!offset_) return NULL; 50 return reinterpret_cast<T*>((char*)&offset_ + offset_); 51 } 52 private: to_offset(const T * ptr)53 Offset to_offset(const T* ptr) const { 54 return ptr ? (char*)ptr - (char*)(&offset_) : 0; 55 } 56 Offset offset_ = 0; 57 }; 58 59 struct String { 60 OffsetPtr<char> data; c_strString61 const char* c_str() const { return data.get(); } lengthString62 size_t length() const { return c_str() ? strlen(c_str()) : 0; } emptyString63 bool empty() const { return !data || !data[0]; } 64 }; 65 66 template <class T, class Size = uint32_t> 67 struct Array { 68 Size size; 69 T at[1]; beginArray70 T* begin() { return &at[0]; } endArray71 T* end() { return &at[0] + size; } beginArray72 const T* begin() const { return &at[0]; } endArray73 const T* end() const { return &at[0] + size; } 74 }; 75 76 template <class T, class Size = uint32_t> 77 struct List { 78 Size size; 79 OffsetPtr<T> at; beginList80 T* begin() { return &at[0]; } endList81 T* end() { return &at[0] + size; } beginList82 const T* begin() const { return &at[0]; } endList83 const T* end() const { return &at[0] + size; } 84 }; 85 86 // MappedFile class definition 87 88 class MappedFileImpl; 89 90 class MappedFile : boost::noncopyable { 91 protected: 92 explicit MappedFile(const string& file_name); 93 RIME_API virtual ~MappedFile(); 94 95 bool Create(size_t capacity); 96 bool OpenReadOnly(); 97 bool OpenReadWrite(); 98 bool Flush(); 99 bool Resize(size_t capacity); 100 bool ShrinkToFit(); 101 102 template <class T> 103 T* Allocate(size_t count = 1); 104 105 template <class T> 106 Array<T>* CreateArray(size_t array_size); 107 108 String* CreateString(const string& str); 109 bool CopyString(const string& src, String* dest); 110 111 size_t capacity() const; 112 char* address() const; 113 114 public: 115 bool Exists() const; 116 bool IsOpen() const; 117 RIME_API void Close(); 118 RIME_API bool Remove(); 119 120 template <class T> 121 T* Find(size_t offset); 122 file_name()123 const string& file_name() const { return file_name_; } file_size()124 size_t file_size() const { return size_; } 125 126 private: 127 string file_name_; 128 size_t size_ = 0; 129 the<MappedFileImpl> file_; 130 }; 131 132 // member function definitions 133 134 # define RIME_ALIGNED(size, T) ((size + alignof(T) - 1) & ~(alignof(T) - 1)) 135 136 template <class T> Allocate(size_t count)137T* MappedFile::Allocate(size_t count) { 138 if (!IsOpen()) 139 return NULL; 140 141 size_t used_space = RIME_ALIGNED(size_, T); 142 size_t required_space = sizeof(T) * count; 143 size_t file_size = capacity(); 144 if (used_space + required_space > file_size) { 145 // not enough space; grow the file 146 size_t new_size = (std::max)(used_space + required_space, file_size * 2); 147 if(!Resize(new_size) || !OpenReadWrite()) 148 return NULL; 149 } 150 T* ptr = reinterpret_cast<T*>(address() + used_space); 151 std::memset(ptr, 0, required_space); 152 size_ = used_space + required_space; 153 return ptr; 154 } 155 156 template <class T> Find(size_t offset)157T* MappedFile::Find(size_t offset) { 158 if (!IsOpen() || offset > size_) 159 return NULL; 160 return reinterpret_cast<T*>(address() + offset); 161 } 162 163 template <class T> CreateArray(size_t array_size)164Array<T>* MappedFile::CreateArray(size_t array_size) { 165 size_t num_bytes = sizeof(Array<T>) + sizeof(T) * (array_size - 1); 166 Array<T>* ret = reinterpret_cast<Array<T>*>(Allocate<char>(num_bytes)); 167 if (!ret) 168 return NULL; 169 ret->size = array_size; 170 return ret; 171 } 172 173 } // namespace rime 174 175 #endif // RIME_MAPPED_FILE_H_ 176