// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2010, Knut Reinert, FU Berlin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// ==========================================================================

#ifndef SEQAN_HEADER_STRING_MMAP_H
#define SEQAN_HEADER_STRING_MMAP_H


//////////////////////////////////////////////////////////////////////////////

namespace SEQAN_NAMESPACE_MAIN
{

    template < typename TFile_ = File<>,				// default file type
               typename TSize_ = size_t >				// size type
    struct MMapConfig {
        typedef TFile_ TFile;
        typedef TSize_ TSize;
    };

    template < typename TConfig = MMapConfig<> >
    struct MMap;
	
	
	//////////////////////////////////////////////////////////////////////////////
    // Memory Mapped String
    //////////////////////////////////////////////////////////////////////////////

/**
.Spec.MMap String:
..cat:Strings
..general:Class.String
..summary:String that is stored in external memory. Uses memory mapping.
..signature:String<TValue, MMap<> >
..signature:String<TValue, MMap<TConfig> >
..param.TValue:The value type, that is the type of the items/characters stored in the string.
...remarks:Use @Metafunction.Value@ to get the value type for a given class.
..param.TConfig:A structure to configure the memory mapped string.
...type:Tag.ExternalConfig
...type:Tag.ExternalConfigLarge
...type:Tag.ExternalConfigSize
...default:@Tag.ExternalConfig@
..remarks:The MMap String enables to access sequences larger than the available physical memory (RAM) by using
external memory (e.g. Hard disk, Network storage, ...) mapped into memory.
The size of the string is limited by external memory and the logical address space (4GB on a 32bit OS).
See the @Memfunc.ExtString#String.constructor@ for more details.
..remarks:This String also supports fast appending and removing of values at the end (see @Spec.Block String@, @Function.appendValue@)
..include:seqan/file.h
*/

#ifdef PLATFORM_WINDOWS

		enum MMapAdviseScheme {
			MMAP_NORMAL = 0,
			MMAP_RANDOM = 0,
			MMAP_SEQUENTIAL = 0,
			MMAP_WILLNEED = 0,
			MMAP_DONTNEED = 0
		};

#else

		enum MMapAdviseScheme {
			MMAP_NORMAL = POSIX_MADV_NORMAL,
			MMAP_RANDOM = POSIX_MADV_RANDOM,
			MMAP_SEQUENTIAL = POSIX_MADV_SEQUENTIAL,
			MMAP_WILLNEED = POSIX_MADV_WILLNEED,
			MMAP_DONTNEED = POSIX_MADV_DONTNEED
		};

#endif

    template < typename TValue,
               typename TConfig >
	class String<TValue, MMap<TConfig> >
	{
	public:

        typedef typename TConfig::TFile		TFile;
        typedef typename TConfig::TSize		TSize;

		TValue				*data_begin;
		TValue				*data_end;
		TSize				data_capacity;

		TFile				file;
		int					_openMode;
        bool                _temporary, _ownFile;

#ifdef PLATFORM_WINDOWS
        HANDLE				handle;
#endif
		MMapAdviseScheme	scheme;

		String(TSize size = 0):
			data_begin(0),
			data_end(0),
			data_capacity(0),
            file(NULL),
			scheme(MMAP_NORMAL)
        {
            _temporary = true;
            _ownFile = false;

			resize(*this, size);
        }

		String(TFile &_file):
			data_begin(0),
			data_end(0),
			data_capacity(0),
            file(NULL),
			scheme(MMAP_NORMAL)
        {
			open(*this, _file);
        }

		String(const char *fileName, int openMode = DefaultOpenMode<TFile>::VALUE):
			data_begin(0),
			data_end(0),
			data_capacity(0),
            file(NULL),
			scheme(MMAP_NORMAL)
        {
			open(*this, fileName, openMode);
        }

		template <typename TSource>
		String & operator =(TSource const & source)
		{
	SEQAN_CHECKPOINT
			assign(*this, source);
			return *this;
		}
		String & operator =(String const & source)
		{
	SEQAN_CHECKPOINT
			assign(*this, source);
			return *this;
		}

		~String() 
		{
			close(*this);
		}

//____________________________________________________________________________

		template <typename TPos>
		inline typename Reference<String>::Type
		operator [] (TPos pos)
		{
	SEQAN_CHECKPOINT
			return value(*this, pos);
		}

		template <typename TPos>
		inline typename Reference<String const>::Type 
		operator [] (TPos pos) const
		{
	SEQAN_CHECKPOINT
			return value(*this, pos);
		}

//____________________________________________________________________________

        inline operator bool() 
   	{
            return file;
        }

//____________________________________________________________________________

};

   template < typename TValue, typename TConfig >
	inline typename Iterator<String<TValue, MMap<TConfig> > , Standard>::Type
	begin(String<TValue, MMap<TConfig> > & me,
		Standard)
	{
SEQAN_CHECKPOINT
		return me.data_begin;
	}
   template < typename TValue, typename TConfig >
	inline typename Iterator<String<TValue, MMap<TConfig> >  const, Standard>::Type
	begin(String<TValue, MMap<TConfig> > const & me,
		Standard)
	{
SEQAN_CHECKPOINT
		return me.data_begin;
	}

//____________________________________________________________________________

   template < typename TValue, typename TConfig >
   inline typename Iterator<String<TValue, MMap<TConfig> > , Standard>::Type
	end(String<TValue, MMap<TConfig> > & me,
		Standard)
	{
SEQAN_CHECKPOINT
		return me.data_end;
	}
   template < typename TValue, typename TConfig >
	inline typename Iterator<String<TValue, MMap<TConfig> >  const, Standard>::Type
	end(String<TValue, MMap<TConfig> > const & me,
		Standard)
	{
SEQAN_CHECKPOINT
		return me.data_end;
	}

//____________________________________________________________________________

   template < typename TValue, typename TConfig >
	inline typename Size<String<TValue, MMap<TConfig> > >::Type
	capacity(String<TValue, MMap<TConfig> > & me) 
	{
SEQAN_CHECKPOINT
		return me.data_capacity;
	}

   template < typename TValue, typename TConfig >
	inline typename Size<String<TValue, MMap<TConfig> > >::Type
	capacity(String<TValue, MMap<TConfig> > const & me) 
	{
SEQAN_CHECKPOINT
		return me.data_capacity;
	}

//____________________________________________________________________________

   template < typename TValue, typename TConfig >
	inline void 
	_setLength(
		String<TValue, MMap<TConfig> > & me, 
		size_t new_length)
	{
SEQAN_CHECKPOINT
		me.data_end = me.data_begin + new_length;
	}

//____________________________________________________________________________

	template < typename TValue, typename TConfig >
   inline void 
	_setCapacity(
		String<TValue, MMap<TConfig> > & me, 
		size_t new_capacity)
	{
SEQAN_CHECKPOINT
		me.data_capacity = new_capacity;
	}


    //////////////////////////////////////////////////////////////////////////////
    // meta-function interface

    template < typename TValue, typename TConfig >
    struct Size< String<TValue, MMap<TConfig> > >
    {
        typedef size_t Type;
    };

    template < typename TValue, typename TConfig >
    struct Difference< String<TValue, MMap<TConfig> > >
    {
		typedef typename MakeSigned_<size_t>::Type Type;
    };
//____________________________________________________________________________

    template < typename TValue, typename TConfig >
	struct DefaultOverflowExplicit<String<TValue, MMap<TConfig> > >
	{
		typedef Generous Type;
	};

    template < typename TValue, typename TConfig >
	struct DefaultOverflowImplicit<String<TValue, MMap<TConfig> > >
	{
		typedef Generous Type;
	};
//____________________________________________________________________________

    template < typename TValue, typename TConfig >
	struct IsContiguous< String<TValue, MMap<TConfig> > >
	{
		typedef True Type;
		enum { VALUE = true };
	};

    template < typename TValue, typename TConfig >
	struct AllowsFastRandomAccess< String<TValue, MMap<TConfig> > >
	{
		typedef False Type;
		enum { VALUE = false };
	};


	//////////////////////////////////////////////////////////////////////////////
    // global interface

//____________________________________________________________________________

    template < typename TValue, typename TConfig >
	inline void 
	waitForAll(String<TValue, MMap<TConfig> > &)
	{
	}
	
#ifdef PLATFORM_WINDOWS

    static SECURITY_ATTRIBUTES MMapStringDefaultAttributes = {
        sizeof(SECURITY_ATTRIBUTES),
        NULL,
        true
    };

    template < typename TValue, typename TConfig, typename TScheme, typename TBeginPos, typename TEndPos >
	inline int
	mmapAdvise(String<TValue, MMap<TConfig> > &/*me*/, TScheme const & /*scheme*/, TBeginPos const &, TEndPos const &)
	{
		return 0;
	}
		
    template < typename TValue, typename TConfig >
    inline void 
	flush(String<TValue, MMap<TConfig> > &) 
	{
    }

	// cancel all transactions
    template < typename TValue, typename TConfig >
	inline void 
	cancel(String<TValue, MMap<TConfig> > &)
	{
	}

	// flush and free all allocated pages
    template < typename TValue, typename TConfig >
	inline int
	flushAndFree(String<TValue, MMap<TConfig> > &)
	{
		return 0;
	}
//____________________________________________________________________________

	template < typename TValue, typename TConfig >
    inline bool 
    _map(String<TValue, MMap<TConfig> > &me, size_t new_capacity) 
	{
		if (new_capacity > 0) 
		{
			resize(me.file, new_capacity * sizeof(TValue));
			DWORD prot = 0;
			DWORD access = 0;
			if ((me._openMode & OPEN_MASK) == OPEN_RDONLY) 
			{
				prot = PAGE_READONLY;
				access = FILE_MAP_READ;
			} else {
				prot = PAGE_READWRITE;
				access = FILE_MAP_ALL_ACCESS;
			}
            LARGE_INTEGER largeSize;
			largeSize.QuadPart = new_capacity;
			largeSize.QuadPart *= sizeof(TValue);

			me.handle = CreateFileMapping(me.file.handle, &MMapStringDefaultAttributes, prot, largeSize.HighPart, largeSize.LowPart, NULL);
			if (me.handle == NULL)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "CreateFileMapping failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
			#endif
				return false;
			}

			void *addr = MapViewOfFile(me.handle, access, 0, 0, 0);	
			if (addr == NULL)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "MapViewOfFile failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
			#endif
				return false;
			}
				
			me.data_begin = (TValue *) addr;
			_setLength(me, new_capacity);
			_setCapacity(me, new_capacity);
		}
		return true;
	}

	template < typename TValue, typename TConfig >
    inline bool 
    _unmap(String<TValue, MMap<TConfig> > &me) 
	{
		bool result = true;
		if (me.data_begin) 
		{
			if (UnmapViewOfFile(me.data_begin) == 0)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "UnmapViewOfFile failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
			#endif
				result = false;
			}
			
			if (CloseHandle(me.handle) == 0)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "CloseHandle failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
			#endif
				result = false;
			}
			
			resize(me.file, length(me) * sizeof(TValue));
			me.data_begin = NULL;
			me.data_end = NULL;
			me.data_capacity = 0;
		}
		return result;
	}

	template < typename TValue, typename TConfig, typename TCapSize >
    inline bool 
    _remap(String<TValue, MMap<TConfig> > &me, TCapSize new_capacity) 
	{
		typedef typename Size< String<TValue, MMap<TConfig> > >::Type TSize;

		if (me.data_begin) 
		{
			if (new_capacity > 0) 
			{
				TSize seq_length = length(me);
				
				DWORD prot = 0;
				DWORD access = 0;
				if ((me._openMode & OPEN_MASK) == OPEN_RDONLY) 
				{
					prot = PAGE_READONLY;
					access = FILE_MAP_READ;
				} else {
					prot = PAGE_READWRITE;
					access = FILE_MAP_ALL_ACCESS;
				}
				LARGE_INTEGER largeSize;
				largeSize.QuadPart = new_capacity;
				largeSize.QuadPart *= sizeof(TValue);

				bool result = true;
				result &= (UnmapViewOfFile(me.data_begin) != 0);
				result &= (CloseHandle(me.handle) != 0);

				HANDLE handle = CreateFileMapping(me.file.handle, &MMapStringDefaultAttributes, prot, largeSize.HighPart, largeSize.LowPart, NULL);
				if (handle == NULL)
				{
				#ifdef SEQAN_DEBUG
					::std::cerr << "CreateFileMapping failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
				#endif
					return false;
				}

				void *addr = MapViewOfFile(handle, access, 0, 0, 0);	
				if (addr == NULL)
				{
				#ifdef SEQAN_DEBUG
					::std::cerr << "MapViewOfFile failed. (ErrNo=" << GetLastError() << ")" << ::std::endl;
				#endif
					return false;
				}

				if (capacity(me) > new_capacity)
					resize(me.file, new_capacity * sizeof(TValue));

				me.handle = handle;
				me.data_begin = (TValue*) addr;
				_setLength(me, seq_length);
				_setCapacity(me, new_capacity);
				return true;
			} else
				return _unmap(me);
		} else
			return _allocateStorage(me, new_capacity) != NULL;
	}

#else

///.Function.flush.param.string.type:Spec.MMap String

    template < typename TValue, typename TConfig, typename TScheme, typename TBeginPos, typename TEndPos >
	inline int
	mmapAdvise(String<TValue, MMap<TConfig> > &me, TScheme const & scheme, TBeginPos const & beginPos, TEndPos const & endPos)
	{
		me.scheme = scheme;
//		posix_fadvise(me.file.handle, beginPos * sizeof(TValue), (endPos - beginPos) * sizeof(TValue), scheme);
		if (scheme == MMAP_DONTNEED)
			msync(me.data_begin + beginPos, (endPos - beginPos) * sizeof(TValue), MS_INVALIDATE);
		return posix_madvise(me.data_begin + beginPos, (endPos - beginPos) * sizeof(TValue), scheme);
	}
		
    template < typename TValue, typename TConfig >
    inline void 
	flush(String<TValue, MMap<TConfig> > &me) 
	{
		msync(me.data_begin, length(me) * sizeof(TValue), MS_SYNC);
    }

	// cancel all transactions
    template < typename TValue, typename TConfig >
	inline void 
	cancel(String<TValue, MMap<TConfig> > &me)
	{
		msync(me.data_begin, capacity(me) * sizeof(TValue), MS_INVALIDATE);
	}

	// flush and free all allocated pages
    template < typename TValue, typename TConfig >
	inline int
	flushAndFree(String<TValue, MMap<TConfig> > &me)
	{
		return posix_madvise(me.data_begin, capacity(me) * sizeof(TValue), MADV_DONTNEED);
	}
	
//____________________________________________________________________________

	template < typename TValue, typename TConfig >
    inline bool 
    _map(String<TValue, MMap<TConfig> > &me, size_t new_capacity) 
	{
		if (new_capacity > 0) 
		{
			_ensureFileIsOpen(me);
			resize(me.file, new_capacity * sizeof(TValue));
			int prot = 0;
			if (me._openMode & OPEN_RDONLY) prot |= PROT_READ;
			if (me._openMode & OPEN_WRONLY) prot |= PROT_WRITE;
			void *addr = mmap(NULL, new_capacity * sizeof(TValue), prot, MAP_SHARED, me.file.handle, 0);
			mmapAdvise(me, me.scheme);
			
			if (addr == MAP_FAILED)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "mmap failed. errno=" << errno << " (" << ::strerror(errno) << ")" << ::std::endl;
			#endif
				return false;
			}
				
			me.data_begin = (TValue *) addr;
			_setLength(me, new_capacity);
			_setCapacity(me, new_capacity);
		}
		return true;
	}

	template < typename TValue, typename TConfig >
    inline bool 
    _unmap(String<TValue, MMap<TConfig> > &me) 
	{
		if (me.data_begin) 
		{
			int error = munmap(me.data_begin, capacity(me) * sizeof(TValue));
			if (error != 0)
			{
			#ifdef SEQAN_DEBUG
				::std::cerr << "munmap failed. errno=" << errno << " (" << ::strerror(errno) << ")" << ::std::endl;
			#endif
				return false;
			}
			
			resize(me.file, length(me) * sizeof(TValue));
			me.data_begin = NULL;
			me.data_end = NULL;
			me.data_capacity = 0;
		}
		return true;
	}

	template < typename TValue, typename TConfig, typename TCapSize >
    inline bool 
    _remap(String<TValue, MMap<TConfig> > &me, TCapSize new_capacity) 
	{
		typedef typename Size< String<TValue, MMap<TConfig> > >::Type TSize;

		if (me.data_begin)
		{
			if (new_capacity > 0) 
			{
				TSize seq_length = length(me);
				
				_ensureFileIsOpen(me);
				if (capacity(me) < new_capacity)
					resize(me.file, new_capacity * sizeof(TValue));

#ifdef MREMAP_MAYMOVE
				void *addr = mremap(me.data_begin, capacity(me) * sizeof(TValue), new_capacity * sizeof(TValue), MREMAP_MAYMOVE);
				mmapAdvise(me, me.scheme);
#else
				// for BSD systems without mremap(..) like Mac OS X ...
				int prot = 0;
				if (me._openMode & OPEN_RDONLY) prot |= PROT_READ;
				if (me._openMode & OPEN_WRONLY) prot |= PROT_WRITE;
	//			void *addr = mmap(me.data_begin, new_capacity * sizeof(TValue), prot, MAP_SHARED | MAP_FIXED, me.file.handle, 0);
				munmap(me.data_begin, capacity(me) * sizeof(TValue));
				void *addr = mmap(NULL, new_capacity * sizeof(TValue), prot, MAP_SHARED, me.file.handle, 0);
				mmapAdvise(me, me.scheme);
#endif

				if (addr == MAP_FAILED) 
				{
				#ifdef SEQAN_DEBUG
					::std::cerr << "mremap failed. errno=" << errno << " (" << ::strerror(errno) << ")" << ::std::endl;
				#endif
					return false;
				}

				if (capacity(me) > new_capacity)
					resize(me.file, new_capacity * sizeof(TValue));

				me.data_begin = (TValue*) addr;
				_setLength(me, seq_length);
				_setCapacity(me, new_capacity);
				return true;
			} else
				return _unmap(me);
		} else
			return _map(me, new_capacity);
	}

#endif

	template < typename TValue, typename TConfig >
    inline void 
    clear(String<TValue, MMap<TConfig> > &me) 
	{
		cancel(me);
		_unmap(me);
		resize(me.file, 0);
	}
//____________________________________________________________________________

    template < typename TValue, typename TConfig, typename TScheme >
	inline int
	mmapAdvise(String<TValue, MMap<TConfig> > &me, TScheme scheme)
	{
		return mmapAdvise(me, scheme, 0, capacity(me));
	}
		
//____________________________________________________________________________

	template < typename TValue, typename TConfig, typename TSize >
    inline typename Value<String<TValue, MMap<TConfig> > >::Type * 
    _allocateStorage(String<TValue, MMap<TConfig> > &me, TSize new_capacity) 
	{
		TSize size = _computeSizeForCapacity(me, new_capacity);
		_map(me, size);
		return NULL;
	}

	template < typename TValue, typename TConfig, typename TSize >
    inline typename Value<String<TValue, MMap<TConfig> > >::Type * 
    _reallocateStorage(
		String<TValue, MMap<TConfig> > &me,
		TSize new_capacity) 
	{
		TSize size = _computeSizeForCapacity(me, new_capacity);
		_remap(me, size);
		return NULL;
	}

	template < typename TValue, typename TConfig, typename TSize >
    inline void
    _deallocateStorage(String<TValue, MMap<TConfig> > &/*me*/, TValue * /*ptr*/, TSize /*capacity*/)
	{
	}
//____________________________________________________________________________
///.Function.open.param.string.type:Spec.MMap String

	template < typename TValue, typename TConfig >
    inline bool 
    open(String<TValue, MMap<TConfig> > &me, const char *fileName, int openMode) 
	{
		close(me);
		me._temporary = false;
				
		if ((me._ownFile = open(me.file, fileName, openMode))) 
		{
			me._openMode = openMode;
			return _map(me, (size_t)(size(me.file) / sizeof(TValue)));
		}

		return false;
    }

	template < typename TValue, typename TConfig >
    inline bool 
    open(String<TValue, MMap<TConfig> > &me, const char *fileName) 
	{
		typedef typename String<TValue, MMap<TConfig> >::TFile	TFile;
		return open(me, fileName, DefaultOpenMode<TFile>::VALUE);
    }

	template < typename TValue, typename TConfig >
    inline bool 
    open(String<TValue, MMap<TConfig> > &me, typename TConfig::TFile file) 
	{
		close(me);
		me.file = file;
        me._temporary = false;
        me._ownFile = false;

		if (me.file) 
		{
			me._openMode = OPEN_RDWR;
			return _map(me, size(me.file) / sizeof(TValue));
		}

		return false;
    }

///.Function.openTemp.param.string.type:Spec.MMap String

	template < typename TValue, typename TConfig >
    inline bool 
    openTemp(String<TValue, MMap<TConfig> > &me) 
	{
		close(me);
        me._temporary = true;
		me._openMode = OPEN_RDWR;
		
		return me._ownFile = openTemp(me.file);
    }
//____________________________________________________________________________

	template < typename TValue, typename TConfig >
	inline void _ensureFileIsOpen(String<TValue, MMap<TConfig> > &me) 
	{
		if (!me.file)
		{
			me._temporary = true;
			me._openMode = OPEN_RDWR;

			if (!(me._ownFile = openTemp(me.file)))
				::std::cerr << "Memory Mapped String couldn't open temporary file" << ::std::endl;
		}
	}
//____________________________________________________________________________

	template < typename TValue, typename TConfig >
    inline bool 
    save(String<TValue, MMap<TConfig> > const &/*me*/, const char * /*fileName*/, int /*openMode*/) {
		// Memory Mapped Strings are persistent, thus there is no need to save them
		//MMapStringsDontNeedToBeSaved error;
		return true;
	}

	template < typename TValue, typename TConfig >
    inline bool 
    save(String<TValue, MMap<TConfig> > const &/*me*/, const char * /*fileName*/) {
		// Memory Mapped Strings are persistent, thus there is no need to save them
		//MMapStringsDontNeedToBeSaved error;
		return true;
	}

	template < typename TValue, typename TConfig >
    inline bool 
    save(String<TValue, MMap<TConfig> > const &/*me*/, typename TConfig::TFile /*file*/) {
		// Memory Mapped Strings are persistent, thus there is no need to save them
		//MMapStringsDontNeedToBeSaved error;
		return true;
	}
//____________________________________________________________________________
///.Function.flush.close.string.type:Spec.MMap String

	template < typename TValue, typename TConfig >
    inline bool 
    close(String<TValue, MMap<TConfig> > &me) 
	{
		if (me.file) 
		{
			// close associated file
			if (me._temporary) 
			{
				me._temporary = false;
				cancel(me);
			}

			_unmap(me);

			if (me._ownFile) 
			{
				me._ownFile = false;
				return close(me.file);
			}
		}
		return true;
    }

//////////////////////////////////////////////////////////////////////////////



} //namespace SEQAN_NAMESPACE_MAIN

#endif //#ifndef SEQAN_HEADER_...
