00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef moses_MmapAllocator_h
00023 #define moses_MmapAllocator_h
00024
00025 #include <limits>
00026 #include <iostream>
00027 #include <cstdio>
00028 #include <unistd.h>
00029
00030 #if defined(_WIN32) || defined(_WIN64)
00031 #include <windows.h>
00032 #include <io.h>
00033 #else
00034 #include <sys/mman.h>
00035 #endif
00036
00037 #include "util/mmap.hh"
00038
00039 namespace Moses
00040 {
00041 template <class T>
00042 class MmapAllocator
00043 {
00044 protected:
00045 std::FILE* m_file_ptr;
00046 size_t m_file_desc;
00047
00048 size_t m_page_size;
00049 size_t m_map_size;
00050
00051 char* m_data_ptr;
00052 size_t m_data_offset;
00053 bool m_fixed;
00054 size_t* m_count;
00055
00056 public:
00057 typedef T value_type;
00058 typedef T* pointer;
00059 typedef const T* const_pointer;
00060 typedef T& reference;
00061 typedef const T& const_reference;
00062 typedef std::size_t size_type;
00063 typedef std::ptrdiff_t difference_type;
00064
00065 MmapAllocator() throw()
00066 : m_file_ptr(std::tmpfile()), m_file_desc(fileno(m_file_ptr)),
00067 m_page_size(util::SizePage()), m_map_size(0), m_data_ptr(0),
00068 m_data_offset(0), m_fixed(false), m_count(new size_t(0)) {
00069 }
00070
00071 MmapAllocator(std::FILE* f_ptr) throw()
00072 : m_file_ptr(f_ptr), m_file_desc(fileno(m_file_ptr)),
00073 m_page_size(util::SizePage()), m_map_size(0), m_data_ptr(0),
00074 m_data_offset(0), m_fixed(false), m_count(new size_t(0)) {
00075 }
00076
00077 MmapAllocator(std::FILE* f_ptr, size_t data_offset) throw()
00078 : m_file_ptr(f_ptr), m_file_desc(fileno(m_file_ptr)),
00079 m_page_size(util::SizePage()), m_map_size(0), m_data_ptr(0),
00080 m_data_offset(data_offset), m_fixed(true), m_count(new size_t(0)) {
00081 }
00082
00083 MmapAllocator(std::string fileName) throw()
00084 : m_file_ptr(std::fopen(fileName.c_str(), "wb+")), m_file_desc(fileno(m_file_ptr)),
00085 m_page_size(util::SizePage()), m_map_size(0), m_data_ptr(0),
00086 m_data_offset(0), m_fixed(false), m_count(new size_t(0)) {
00087 }
00088
00089 MmapAllocator(const MmapAllocator& c) throw()
00090 : m_file_ptr(c.m_file_ptr), m_file_desc(c.m_file_desc),
00091 m_page_size(c.m_page_size), m_map_size(c.m_map_size),
00092 m_data_ptr(c.m_data_ptr), m_data_offset(c.m_data_offset),
00093 m_fixed(c.m_fixed), m_count(c.m_count) {
00094 (*m_count)++;
00095 }
00096
00097 ~MmapAllocator() throw() {
00098 if(m_data_ptr && *m_count == 0) {
00099 util::UnmapOrThrow(m_data_ptr, m_map_size);
00100 if(!m_fixed && std::ftell(m_file_ptr) != -1)
00101 std::fclose(m_file_ptr);
00102 }
00103 (*m_count)--;
00104 }
00105
00106 template <class U>
00107 struct rebind {
00108 typedef MmapAllocator<U> other;
00109 };
00110
00111 pointer address (reference value) const {
00112 return &value;
00113 }
00114
00115 const_pointer address (const_reference value) const {
00116 return &value;
00117 }
00118
00119 size_type max_size () const throw() {
00120 return std::numeric_limits<size_t>::max() / sizeof(value_type);
00121 }
00122
00123 pointer allocate (size_type num, const void* = 0) {
00124 m_map_size = num * sizeof(T);
00125
00126 #if defined(_WIN32) || defined(_WIN64)
00127
00128 const int map_shared = 0;
00129 #else
00130 const int map_shared = MAP_SHARED;
00131 #endif
00132 if(!m_fixed) {
00133 size_t read = 0;
00134 read += ftruncate(m_file_desc, m_map_size);
00135 m_data_ptr = (char *)util::MapOrThrow(
00136 m_map_size, true, map_shared, false, m_file_desc, 0);
00137 return (pointer)m_data_ptr;
00138 } else {
00139 const size_t map_offset = (m_data_offset / m_page_size) * m_page_size;
00140 const size_t relative_offset = m_data_offset - map_offset;
00141 const size_t adjusted_map_size = m_map_size + relative_offset;
00142
00143 m_data_ptr = (char *)util::MapOrThrow(
00144 adjusted_map_size, false, map_shared, false, m_file_desc, map_offset);
00145
00146 return (pointer)(m_data_ptr + relative_offset);
00147 }
00148 }
00149
00150 void deallocate (pointer p, size_type num) {
00151 if(!m_fixed) {
00152 util::UnmapOrThrow(p, num * sizeof(T));
00153 } else {
00154 const size_t map_offset = (m_data_offset / m_page_size) * m_page_size;
00155 const size_t relative_offset = m_data_offset - map_offset;
00156 const size_t adjusted_map_size = m_map_size + relative_offset;
00157
00158 util::UnmapOrThrow((pointer)((char*)p - relative_offset), adjusted_map_size);
00159 }
00160 }
00161
00162 void construct (pointer p, const T& value) {
00163 if(!m_fixed)
00164 new(p) value_type(value);
00165 }
00166 void destroy (pointer p) {
00167 if(!m_fixed)
00168 p->~T();
00169 }
00170
00171 template <class T1, class T2>
00172 friend bool operator== (const MmapAllocator<T1>&, const MmapAllocator<T2>&) throw();
00173
00174 template <class T1, class T2>
00175 friend bool operator!= (const MmapAllocator<T1>&, const MmapAllocator<T2>&) throw();
00176 };
00177
00178 template <class T1, class T2>
00179 bool operator== (const MmapAllocator<T1>& a1,
00180 const MmapAllocator<T2>& a2) throw()
00181 {
00182 bool equal = true;
00183 equal &= a1.m_file_ptr == a2.m_file_ptr;
00184 equal &= a1.m_file_desc == a2.m_file_desc;
00185 equal &= a1.m_page_size == a2.m_page_size;
00186 equal &= a1.m_map_size == a2.m_map_size;
00187 equal &= a1.m_data_ptr == a2.m_data_ptr;
00188 equal &= a1.m_data_offset == a2.m_data_offset;
00189 equal &= a1.m_fixed == a2.m_fixed;
00190 return equal;
00191 }
00192
00193 template <class T1, class T2>
00194 bool operator!=(const MmapAllocator<T1>& a1,
00195 const MmapAllocator<T2>& a2) throw()
00196 {
00197 return !(a1 == a2);
00198 }
00199
00200 }
00201
00202 #endif