//===-- DataBufferMemoryMap.h -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_DataBufferMemoryMap_h_
#define liblldb_DataBufferMemoryMap_h_

#include "lldb/lldb-private.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Error.h"
#include <string>

namespace lldb_private {

//----------------------------------------------------------------------
/// @class DataBufferMemoryMap DataBufferMemoryMap.h "lldb/Core/DataBufferMemoryMap.h"
/// @brief A subclass of DataBuffer that memory maps data.
///
/// This class memory maps data and stores any needed data for the
/// memory mapping in its internal state. Memory map requests are not
/// required to have any alignment or size constraints, this class will
/// work around any host OS issues regarding such things.
///
/// This class is designed to allow pages to be faulted in as needed and
/// works well data from large files that won't be accessed all at once.
//----------------------------------------------------------------------
class DataBufferMemoryMap : public DataBuffer
{
public:
    //------------------------------------------------------------------
    /// Default Constructor
    //------------------------------------------------------------------
    DataBufferMemoryMap ();

    //------------------------------------------------------------------
    /// Destructor.
    ///
    /// Virtual destructor since this class inherits from a pure virtual
    /// base class #DataBuffer.
    //------------------------------------------------------------------
    ~DataBufferMemoryMap () override;

    //------------------------------------------------------------------
    /// Reverts this object to an empty state by unmapping any memory
    /// that is currently owned.
    //------------------------------------------------------------------
    void
    Clear ();

    //------------------------------------------------------------------
    /// @copydoc DataBuffer::GetBytes()
    //------------------------------------------------------------------
    uint8_t *
    GetBytes () override;

    //------------------------------------------------------------------
    /// @copydoc DataBuffer::GetBytes() const
    //------------------------------------------------------------------
    const uint8_t *
    GetBytes () const override;

    //------------------------------------------------------------------
    /// @copydoc DataBuffer::GetByteSize() const
    //------------------------------------------------------------------
    lldb::offset_t
    GetByteSize () const override;

    //------------------------------------------------------------------
    /// Error get accessor.
    ///
    /// @return
    ///     A const reference to Error object in case memory mapping
    ///     fails.
    //------------------------------------------------------------------
    const Error &
    GetError() const;

    //------------------------------------------------------------------
    /// Memory map all or part of a file.
    ///
    /// Memory map \a length bytes from \a file starting \a offset
    /// bytes into the file. If \a length is set to \c SIZE_MAX,
    /// then map as many bytes as possible.
    ///
    /// @param[in] file
    ///     The file specification from which to map data.
    ///
    /// @param[in] offset
    ///     The offset in bytes from the beginning of the file where
    ///     memory mapping should begin.
    ///
    /// @param[in] length
    ///     The size in bytes that should be mapped starting \a offset
    ///     bytes into the file. If \a length is \c SIZE_MAX, map
    ///     as many bytes as possible.  Even though it may be possible
    ///     for a 32-bit host debugger to debug a 64-bit target, size_t
    ///     still dictates the maximum possible size that can be mapped
    ///     into this process.  For this kind of cross-arch debugging
    ///     scenario, mappings and views should be managed at a higher
    ///     level.
    ///
    /// @return
    ///     The number of bytes mapped starting from the \a offset.
    //------------------------------------------------------------------
    size_t
    MemoryMapFromFileSpec (const FileSpec* file,
                           lldb::offset_t offset = 0,
                           size_t length = SIZE_MAX,
                           bool writeable = false);

    //------------------------------------------------------------------
    /// Memory map all or part of a file.
    ///
    /// Memory map \a length bytes from an opened file descriptor \a fd
    /// starting \a offset bytes into the file. If \a length is set to
    /// \c SIZE_MAX, then map as many bytes as possible.
    ///
    /// @param[in] fd
    ///     The posix file descriptor for an already opened file
    ///     from which to map data.
    ///
    /// @param[in] offset
    ///     The offset in bytes from the beginning of the file where
    ///     memory mapping should begin.
    ///
    /// @param[in] length
    ///     The size in bytes that should be mapped starting \a offset
    ///     bytes into the file. If \a length is \c SIZE_MAX, map
    ///     as many bytes as possible.
    ///
    /// @return
    ///     The number of bytes mapped starting from the \a offset.
    //------------------------------------------------------------------
    size_t
    MemoryMapFromFileDescriptor (int fd, 
                                 lldb::offset_t offset,
                                 size_t length,
                                 bool write,
                                 bool fd_is_file);

protected:
    //------------------------------------------------------------------
    // Classes that inherit from DataBufferMemoryMap can see and modify these
    //------------------------------------------------------------------
    uint8_t * m_mmap_addr;  ///< The actual pointer that was returned from \c mmap()
    size_t m_mmap_size;     ///< The actual number of bytes that were mapped when \c mmap() was called
    uint8_t *m_data;        ///< The data the user requested somewhere within the memory mapped data.
    lldb::offset_t m_size;  ///< The size of the data the user got when data was requested

private:
    DISALLOW_COPY_AND_ASSIGN (DataBufferMemoryMap);
};

} // namespace lldb_private

#endif // liblldb_DataBufferMemoryMap_h_
