LCOV - code coverage report
Current view: top level - home/yyan7/compiler/rexompiler/src/util/Sawyer - MappedBuffer.h (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 39 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // WARNING: Changes to this file must be contributed back to Sawyer or else they will
       2             : //          be clobbered by the next update from Sawyer.  The Sawyer repository is at
       3             : //          https://github.com/matzke1/sawyer.
       4             : 
       5             : 
       6             : 
       7             : 
       8             : #ifndef Sawyer_MappedBuffer_H
       9             : #define Sawyer_MappedBuffer_H
      10             : 
      11             : #include <Sawyer/AllocatingBuffer.h>
      12             : #include <Sawyer/Buffer.h>
      13             : #include <Sawyer/Sawyer.h>
      14             : #include <Sawyer/StaticBuffer.h>
      15             : 
      16             : #include <boost/algorithm/string/predicate.hpp>
      17             : #include <boost/filesystem.hpp>
      18             : #include <boost/iostreams/device/mapped_file.hpp>
      19             : #include <boost/lexical_cast.hpp>
      20             : #include <boost/serialization/access.hpp>
      21             : #include <boost/serialization/base_object.hpp>
      22             : #include <boost/serialization/nvp.hpp>
      23             : #include <boost/serialization/split_member.hpp>
      24             : #include <boost/serialization/string.hpp>
      25             : 
      26             : namespace Sawyer {
      27             : namespace Container {
      28             : 
      29             : /** Memory mapped file.
      30             :  *
      31             :  *  This buffer points to a file that is mapped into memory by the operating system.  The API supports a common divisor for
      32             :  *  POSIX and Microsoft Windows and is therefore not all that powerful, but it does allow simple maps to be created that have a
      33             :  *  file as backing store.  See http://www.boost.org/doc/libs for more information.
      34             :  *
      35             :  *  Access modes are the following enumerated constants:
      36             :  *
      37             :  *  @li <code>boost::iostreams::mapped_file::readonly</code>: shared read-only access
      38             :  *  @li <code>boost::iostreams::mapped_file::readwrite</code>: shared read/write access
      39             :  *  @li <code>boost::iostreams::mapped_file::priv</code>: private read/write access
      40             :  *  
      41             :  *  When a file is mapped with private access changes written to the buffer are not reflected in the underlying file. */
      42             : template<class A, class T>
      43             : class MappedBuffer: public Buffer<A, T> {
      44             :     boost::iostreams::mapped_file_params params_;
      45             :     boost::iostreams::mapped_file device_;
      46             : 
      47             : public:
      48             :     typedef A Address;                                  /**< Type of addresses. */
      49             :     typedef T Value;                                    /**< Type of values. */
      50             :     typedef Buffer<A, T> Super;                         /**< Type of base class. */
      51             : 
      52             : private:
      53             :     friend class boost::serialization::access;
      54             : 
      55             :     // Users: You'll need to register the subclass once you know its type, such as
      56             :     // BOOST_CLASS_REGISTER(Sawyer::Container::MappedBuffer<size_t,uint8_t>);
      57             :     template<class S>
      58             :     void save(S &s, const unsigned /*version*/) const {
      59             :         s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
      60             :         s & boost::serialization::make_nvp("path", params_.path);
      61             :         s & boost::serialization::make_nvp("flags", params_.flags);
      62             :         s & boost::serialization::make_nvp("mode", params_.mode);
      63             :         s & boost::serialization::make_nvp("offset", params_.offset);
      64             :         s & boost::serialization::make_nvp("length", params_.length);
      65             :         s & boost::serialization::make_nvp("new_file_size", params_.new_file_size);
      66             : 
      67             :         boost::uint64_t hint;
      68             :         BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
      69             :         hint = (boost::uint64_t)(params_.hint);
      70             :         s & BOOST_SERIALIZATION_NVP(hint);
      71             :     }
      72             : 
      73             :     // Users: You'll need to register the subclass once you know its type, such as
      74             :     // BOOST_CLASS_REGISTER(Sawyer::Container::MappedBuffer<size_t,uint8_t>);
      75             :     template<class S>
      76             :     void load(S &s, const unsigned /*version*/) {
      77             :         s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
      78             :         s & boost::serialization::make_nvp("path", params_.path);
      79             :         s & boost::serialization::make_nvp("flags", params_.flags);
      80             :         s & boost::serialization::make_nvp("mode", params_.mode);
      81             :         s & boost::serialization::make_nvp("offset", params_.offset);
      82             :         s & boost::serialization::make_nvp("length", params_.length);
      83             :         s & boost::serialization::make_nvp("new_file_size", params_.new_file_size);
      84             : 
      85             :         boost::uint64_t hint;
      86             :         BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
      87             :         s & BOOST_SERIALIZATION_NVP(hint);
      88             :         params_.hint = (const char*)hint;
      89             : 
      90             :         device_.open(params_);
      91             :     }
      92             : 
      93             :     BOOST_SERIALIZATION_SPLIT_MEMBER();
      94             : 
      95             : protected:
      96             :     MappedBuffer()
      97             :         : Super(".MappedBuffer") {}           // needed for de-serialization
      98           0 :     explicit MappedBuffer(const boost::iostreams::mapped_file_params &params)
      99           0 :         : Super(".MappedBuffer"), params_(params), device_(params) {}
     100             : 
     101             : public:
     102             :     /** Map a file according to boost parameters.
     103             :      *
     104             :      *  The parameters describe which file (by name) and part thereof should be mapped into memory. */
     105           0 :     static typename Buffer<A, T>::Ptr instance(const boost::iostreams::mapped_file_params &params) {
     106             :         try {
     107           0 :             return typename Buffer<A, T>::Ptr(new MappedBuffer(params));
     108           0 :         } catch (const std::ios_base::failure &e) {
     109           0 :             if (boost::contains(e.what(), "Invalid argument") &&
     110           0 :                 boost::filesystem::is_regular_file(params.path) &&
     111           0 :                 boost::filesystem::is_empty(params.path)) {
     112           0 :                 return StaticBuffer<Address, Value>::instance((const Value*)NULL, 0);
     113             :             } else {
     114           0 :                 throw;
     115             :             }
     116             :         }
     117             :     }
     118             : 
     119             :     /** Map a file by name.
     120             :      *
     121             :      *  The specified file, which must already exist, is mapped into memory and pointed to by this new buffer. */
     122             :     static typename Buffer<A, T>::Ptr
     123           0 :     instance(const boost::filesystem::path &path,
     124             :              boost::iostreams::mapped_file::mapmode mode=boost::iostreams::mapped_file::readonly,
     125             :              boost::intmax_t offset=0,
     126             :              boost::iostreams::mapped_file::size_type length=boost::iostreams::mapped_file::max_length) {
     127           0 :         boost::iostreams::mapped_file_params params(path.string());
     128           0 :         params.flags = mode;
     129           0 :         params.length = length;
     130           0 :         params.offset = offset;
     131           0 :         return instance(params);
     132             :     }
     133             : 
     134             :     // It doesn't make sense to copy a memory-mapped buffer since the point of copying is to result in two independent buffers
     135             :     // pointing to non-shared data. If a shared, writable, memory-mapped buffer is backed by a file and we make a new copy also
     136             :     // backed by the file, then changing one buffer would change the other.  Therefore, we allocate new memory that will hold a
     137             :     // snapshot of the source buffer.
     138           0 :     typename Buffer<A, T>::Ptr copy() const /*override*/ {
     139           0 :         typename Buffer<A, T>::Ptr newBuffer = AllocatingBuffer<A, T>::instance(this->size());
     140           0 :         Address nWritten = newBuffer->write((const Value*)device_.data(), 0, this->size());
     141           0 :         if (nWritten != this->size()) {
     142             :             throw std::runtime_error("MappedBuffer::copy() failed after copying " +
     143             :                                      boost::lexical_cast<std::string>(nWritten) + " of " +
     144           0 :                                      boost::lexical_cast<std::string>(this->size()) +
     145           0 :                                      (1==this->size()?" value":" values"));
     146             :         }
     147           0 :         return newBuffer;
     148             :     }
     149             :     
     150           0 :     Address available(Address address) const /*override*/ {
     151           0 :         return address >= device_.size() ? Address(0) : (Address(device_.size()) - address) / sizeof(Value);
     152             :     }
     153             : 
     154           0 :     void resize(Address n) /*override*/ {
     155           0 :         if (n != this->size())
     156           0 :             throw std::runtime_error("resizing not allowed for MappedBuffer");
     157           0 :     }
     158             : 
     159           0 :     Address read(Value *buf, Address address, Address n) const /*override*/ {
     160           0 :         Address nread = std::min(n, available(address));
     161           0 :         memcpy(buf, device_.const_data() + address, nread * sizeof(Value));
     162           0 :         return nread;
     163             :     }
     164             : 
     165           0 :     Address write(const Value *buf, Address address, Address n) /*override*/ {
     166           0 :         Address nwritten = std::min(n, available(address));
     167           0 :         memcpy(device_.data() + address, buf, nwritten * sizeof(Value));
     168           0 :         return nwritten;
     169             :     }
     170             : 
     171           0 :     const Value* data() const /*override*/ {
     172           0 :         return (Value*)device_.const_data();
     173             :     }
     174             : };
     175             : 
     176             : } // namespace
     177             : } // namespace
     178             : #endif

Generated by: LCOV version 1.14