ROSE  0.11.145.0
MappedBuffer.h
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 
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;
49  typedef T Value;
50  typedef Buffer<A, T> Super;
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  explicit MappedBuffer(const boost::iostreams::mapped_file_params &params)
99  : Super(".MappedBuffer"), params_(params), device_(params) {}
100 
101 public:
105  static typename Buffer<A, T>::Ptr instance(const boost::iostreams::mapped_file_params &params) {
106  try {
107  return typename Buffer<A, T>::Ptr(new MappedBuffer(params));
108  } catch (const std::ios_base::failure &e) {
109  if (boost::contains(e.what(), "Invalid argument") &&
110  boost::filesystem::is_regular_file(params.path) &&
111  boost::filesystem::is_empty(params.path)) {
112  return StaticBuffer<Address, Value>::instance((const Value*)NULL, 0);
113  } else {
114  throw;
115  }
116  }
117  }
118 
122  static typename Buffer<A, T>::Ptr
123  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  boost::iostreams::mapped_file_params params(path.string());
128  params.flags = mode;
129  params.length = length;
130  params.offset = offset;
131  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  typename Buffer<A, T>::Ptr copy() const /*override*/ {
139  typename Buffer<A, T>::Ptr newBuffer = AllocatingBuffer<A, T>::instance(this->size());
140  Address nWritten = newBuffer->write((const Value*)device_.data(), 0, this->size());
141  if (nWritten != this->size()) {
142  throw std::runtime_error("MappedBuffer::copy() failed after copying " +
143  boost::lexical_cast<std::string>(nWritten) + " of " +
144  boost::lexical_cast<std::string>(this->size()) +
145  (1==this->size()?" value":" values"));
146  }
147  return newBuffer;
148  }
149 
150  Address available(Address address) const /*override*/ {
151  return address >= device_.size() ? Address(0) : (Address(device_.size()) - address) / sizeof(Value);
152  }
153 
154  void resize(Address n) /*override*/ {
155  if (n != this->size())
156  throw std::runtime_error("resizing not allowed for MappedBuffer");
157  }
158 
159  Address read(Value *buf, Address address, Address n) const /*override*/ {
160  Address nread = std::min(n, available(address));
161  memcpy(buf, device_.const_data() + address, nread * sizeof(Value));
162  return nread;
163  }
164 
165  Address write(const Value *buf, Address address, Address n) /*override*/ {
166  Address nwritten = std::min(n, available(address));
167  memcpy(device_.data() + address, buf, nwritten * sizeof(Value));
168  return nwritten;
169  }
170 
171  const Value* data() const /*override*/ {
172  return (Value*)device_.const_data();
173  }
174 };
175 
176 } // namespace
177 } // namespace
178 #endif
Address write(const Value *buf, Address address, Address n)
Writes data to a buffer.
Definition: MappedBuffer.h:165
const Value * data() const
Data for the buffer.
Definition: MappedBuffer.h:171
Buffer< A, T >::Ptr copy() const
Create a new copy of buffer data.
Definition: MappedBuffer.h:138
A Address
Type of addresses.
Definition: MappedBuffer.h:48
void resize(Address n)
Change the size of the buffer.
Definition: MappedBuffer.h:154
static Buffer< A, T >::Ptr instance(Address size)
Allocating constructor.
Memory mapped file.
Definition: MappedBuffer.h:43
Reference-counting intrusive smart pointer.
Definition: SharedPointer.h:68
Name space for the entire library.
Definition: FeasiblePath.h:767
virtual Address size() const
Size of buffer.
Definition: Buffer.h:76
Address read(Value *buf, Address address, Address n) const
Reads data from a buffer.
Definition: MappedBuffer.h:159
static Buffer< A, T >::Ptr instance(const boost::iostreams::mapped_file_params &params)
Map a file according to boost parameters.
Definition: MappedBuffer.h:105
Buffer< A, T > Super
Type of base class.
Definition: MappedBuffer.h:50
Address available(Address address) const
Distance to end of buffer.
Definition: MappedBuffer.h:150
static Buffer< A, T >::Ptr instance(Value *values, Address size)
Construct from caller-supplied data.
Definition: StaticBuffer.h:85
SharedPointer< Buffer > Ptr
Reference counting smart pointer.
Definition: Buffer.h:45
Base class for all buffers.
Definition: Buffer.h:25
static Buffer< A, T >::Ptr instance(const boost::filesystem::path &path, boost::iostreams::mapped_file::mapmode mode=boost::iostreams::mapped_file::readonly, boost::intmax_t offset=0, boost::iostreams::mapped_file::size_type length=boost::iostreams::mapped_file::max_length)
Map a file by name.
Definition: MappedBuffer.h:123