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)137 T* 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)157 T* 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)164 Array<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