// $Id$ // vim:tabstop=2 /*********************************************************************** Moses - factored phrase-based language decoder Copyright (C) 2006 University of Edinburgh This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ***********************************************************************/ #ifndef moses_MmapAllocator_h #define moses_MmapAllocator_h #include #include #include #if defined(_WIN32) || defined(_WIN64) #define _WINSOCKAPI_ #include #include #else #include #include #endif #include "util/mmap.hh" namespace Moses2 { template class MmapAllocator { protected: std::FILE* m_file_ptr; size_t m_file_desc; size_t m_page_size; size_t m_map_size; char* m_data_ptr; size_t m_data_offset; bool m_fixed; size_t* m_count; public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; MmapAllocator() throw () : m_file_ptr(std::tmpfile()), m_file_desc(fileno(m_file_ptr)), m_page_size( util::SizePage()), m_map_size(0), m_data_ptr(0), m_data_offset(0), m_fixed( false), m_count(new size_t(0)) { } MmapAllocator(std::FILE* f_ptr) throw () : m_file_ptr(f_ptr), m_file_desc(fileno(m_file_ptr)), m_page_size( util::SizePage()), m_map_size(0), m_data_ptr(0), m_data_offset(0), m_fixed( false), m_count(new size_t(0)) { } MmapAllocator(std::FILE* f_ptr, size_t data_offset) throw () : m_file_ptr(f_ptr), m_file_desc(fileno(m_file_ptr)), m_page_size( util::SizePage()), m_map_size(0), m_data_ptr(0), m_data_offset( data_offset), m_fixed(true), m_count(new size_t(0)) { } MmapAllocator(std::string fileName) throw () : m_file_ptr(std::fopen(fileName.c_str(), "wb+")), m_file_desc( fileno(m_file_ptr)), m_page_size(util::SizePage()), m_map_size(0), m_data_ptr( 0), m_data_offset(0), m_fixed(false), m_count(new size_t(0)) { } MmapAllocator(const MmapAllocator& c) throw () : m_file_ptr(c.m_file_ptr), m_file_desc(c.m_file_desc), m_page_size( c.m_page_size), m_map_size(c.m_map_size), m_data_ptr(c.m_data_ptr), m_data_offset( c.m_data_offset), m_fixed(c.m_fixed), m_count(c.m_count) { (*m_count)++; } ~MmapAllocator() throw () { if (m_data_ptr && *m_count == 0) { util::UnmapOrThrow(m_data_ptr, m_map_size); if (!m_fixed && std::ftell(m_file_ptr) != -1) std::fclose(m_file_ptr); } (*m_count)--; } template struct rebind { typedef MmapAllocator other; }; pointer address(reference value) const { return &value; } const_pointer address(const_reference value) const { return &value; } size_type max_size() const throw () { return std::numeric_limits::max() / sizeof(value_type); } pointer allocate(size_type num, const void* = 0) { m_map_size = num * sizeof(T); #if defined(_WIN32) || defined(_WIN64) // On Windows, MAP_SHARED is not defined and MapOrThrow ignores the flags. const int map_shared = 0; #else const int map_shared = MAP_SHARED; #endif if (!m_fixed) { size_t read = 0; #ifdef _WIN32 read += _chsize_s(m_file_desc, m_map_size); #else read += ftruncate(m_file_desc, m_map_size); #endif m_data_ptr = (char *) util::MapOrThrow(m_map_size, true, map_shared, false, m_file_desc, 0); return (pointer) m_data_ptr; } else { const size_t map_offset = (m_data_offset / m_page_size) * m_page_size; const size_t relative_offset = m_data_offset - map_offset; const size_t adjusted_map_size = m_map_size + relative_offset; m_data_ptr = (char *) util::MapOrThrow(adjusted_map_size, false, map_shared, false, m_file_desc, map_offset); return (pointer) (m_data_ptr + relative_offset); } } void deallocate(pointer p, size_type num) { if (!m_fixed) { util::UnmapOrThrow(p, num * sizeof(T)); } else { const size_t map_offset = (m_data_offset / m_page_size) * m_page_size; const size_t relative_offset = m_data_offset - map_offset; const size_t adjusted_map_size = m_map_size + relative_offset; util::UnmapOrThrow((pointer) ((char*) p - relative_offset), adjusted_map_size); } } void construct(pointer p, const T& value) { if (!m_fixed) new (p) value_type(value); } void destroy(pointer p) { if (!m_fixed) p->~T(); } template friend bool operator==(const MmapAllocator&, const MmapAllocator&) throw (); template friend bool operator!=(const MmapAllocator&, const MmapAllocator&) throw (); }; template bool operator==(const MmapAllocator& a1, const MmapAllocator& a2) throw () { bool equal = true; equal &= a1.m_file_ptr == a2.m_file_ptr; equal &= a1.m_file_desc == a2.m_file_desc; equal &= a1.m_page_size == a2.m_page_size; equal &= a1.m_map_size == a2.m_map_size; equal &= a1.m_data_ptr == a2.m_data_ptr; equal &= a1.m_data_offset == a2.m_data_offset; equal &= a1.m_fixed == a2.m_fixed; return equal; } template bool operator!=(const MmapAllocator& a1, const MmapAllocator& a2) throw () { return !(a1 == a2); } } #endif