ROSE 0.11.145.147
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://gitlab.com/charger7534/sawyer.git.
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
21#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
22#include <boost/serialization/string.hpp>
23#endif
24
25#ifdef SAWYER_HAVE_CEREAL
26#include <cereal/types/string.hpp>
27#endif
28
29namespace Sawyer {
30namespace Container {
31
45template<class A, class T>
46class MappedBuffer: public Buffer<A, T> {
47 boost::iostreams::mapped_file_params params_;
48 boost::iostreams::mapped_file device_;
49
50public:
51 typedef A Address;
52 typedef T Value;
55#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
56private:
57 friend class boost::serialization::access;
58
59 // Users: You'll need to register the subclass once you know its type, such as
60 // BOOST_CLASS_REGISTER(Sawyer::Container::MappedBuffer<size_t,uint8_t>);
61 template<class S>
62 void save(S &s, const unsigned /*version*/) const {
63 s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
64 s & boost::serialization::make_nvp("path", params_.path);
65 s & boost::serialization::make_nvp("flags", params_.flags);
66 s & boost::serialization::make_nvp("mode", params_.mode);
67 s & boost::serialization::make_nvp("offset", params_.offset);
68 s & boost::serialization::make_nvp("length", params_.length);
69 s & boost::serialization::make_nvp("new_file_size", params_.new_file_size);
70
71 boost::uint64_t hint;
72 BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
73 hint = (boost::uint64_t)(params_.hint);
74 s & BOOST_SERIALIZATION_NVP(hint);
75 }
76
77 // Users: You'll need to register the subclass once you know its type, such as
78 // BOOST_CLASS_REGISTER(Sawyer::Container::MappedBuffer<size_t,uint8_t>);
79 template<class S>
80 void load(S &s, const unsigned /*version*/) {
81 s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
82 s & boost::serialization::make_nvp("path", params_.path);
83 s & boost::serialization::make_nvp("flags", params_.flags);
84 s & boost::serialization::make_nvp("mode", params_.mode);
85 s & boost::serialization::make_nvp("offset", params_.offset);
86 s & boost::serialization::make_nvp("length", params_.length);
87 s & boost::serialization::make_nvp("new_file_size", params_.new_file_size);
88
89 boost::uint64_t hint;
90 BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
91 s & BOOST_SERIALIZATION_NVP(hint);
92 params_.hint = (const char*)hint;
93
94 device_.open(params_);
95 }
96
97 BOOST_SERIALIZATION_SPLIT_MEMBER();
98#endif
99
100#ifdef SAWYER_HAVE_CEREAL
101private:
102 friend class cereal::access;
103
104 template<class Archive>
105 void CEREAL_SAVE_FUNCTION_NAME(Archive &archive) const {
106 archive(cereal::base_class<Super>());
107 archive(cereal::make_nvp("path", params_.path));
108 archive(cereal::make_nvp("flags", params_.flags));
109 archive(cereal::make_nvp("mode", params_.mode));
110 archive(cereal::make_nvp("offset", params_.offset));
111 archive(cereal::make_nvp("length", params_.length));
112 archive(cereal::make_nvp("new_file_size", params_.new_file_size));
113
114 boost::uint64_t hint;
115 BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
116 hint = (boost::uint64_t)(params_.hint);
117 archive(CEREAL_NVP(hint));
118 }
119
120 template<class Archive>
121 void CEREAL_LOAD_FUNCTION_NAME(Archive &archive) {
122 archive(cereal::base_class<Super>());
123 archive(cereal::make_nvp("path", params_.path));
124 archive(cereal::make_nvp("flags", params_.flags));
125 archive(cereal::make_nvp("mode", params_.mode));
126 archive(cereal::make_nvp("offset", params_.offset));
127 archive(cereal::make_nvp("length", params_.length));
128 archive(cereal::make_nvp("new_file_size", params_.new_file_size));
129
130 boost::uint64_t hint;
131 BOOST_STATIC_ASSERT(sizeof hint >= sizeof params_.hint);
132 archive(CEREAL_NVP(hint));
133 params_.hint = (const char*)hint;
134
135 device_.open(params_);
136 }
137#endif
138
139protected:
140 MappedBuffer()
141 : Super(".MappedBuffer") {} // needed for de-serialization
142 explicit MappedBuffer(const boost::iostreams::mapped_file_params &params)
143 : Super(".MappedBuffer"), params_(params), device_(params) {}
144
145public:
149 static typename Buffer<A, T>::Ptr instance(const boost::iostreams::mapped_file_params &params) {
150 try {
151 return typename Buffer<A, T>::Ptr(new MappedBuffer(params));
152 } catch (const std::ios_base::failure &e) {
153 if (boost::contains(e.what(), "Invalid argument") &&
154 boost::filesystem::is_regular_file(params.path) &&
155 boost::filesystem::is_empty(params.path)) {
156 return StaticBuffer<Address, Value>::instance((const Value*)NULL, 0);
157 } else {
158 throw;
159 }
160 }
161 }
162
166 static typename Buffer<A, T>::Ptr
167 instance(const boost::filesystem::path &path,
168 boost::iostreams::mapped_file::mapmode mode=boost::iostreams::mapped_file::readonly,
169 boost::intmax_t offset=0,
170 boost::iostreams::mapped_file::size_type length=boost::iostreams::mapped_file::max_length) {
171 boost::iostreams::mapped_file_params params(path.string());
172 params.flags = mode;
173 params.length = length;
174 params.offset = offset;
175 return instance(params);
176 }
177
178 // It doesn't make sense to copy a memory-mapped buffer since the point of copying is to result in two independent buffers
179 // pointing to non-shared data. If a shared, writable, memory-mapped buffer is backed by a file and we make a new copy also
180 // backed by the file, then changing one buffer would change the other. Therefore, we allocate new memory that will hold a
181 // snapshot of the source buffer.
182 typename Buffer<A, T>::Ptr copy() const /*override*/ {
183 typename Buffer<A, T>::Ptr newBuffer = AllocatingBuffer<A, T>::instance(this->size());
184 Address nWritten = newBuffer->write((const Value*)device_.data(), 0, this->size());
185 if (nWritten != this->size()) {
186 throw std::runtime_error("MappedBuffer::copy() failed after copying " +
187 boost::lexical_cast<std::string>(nWritten) + " of " +
188 boost::lexical_cast<std::string>(this->size()) +
189 (1==this->size()?" value":" values"));
190 }
191 return newBuffer;
192 }
193
194 Address available(Address address) const /*override*/ {
195 return address >= device_.size() ? Address(0) : (Address(device_.size()) - address) / sizeof(Value);
196 }
197
198 void resize(Address n) /*override*/ {
199 if (n != this->size())
200 throw std::runtime_error("resizing not allowed for MappedBuffer");
201 }
202
203 Address read(Value *buf, Address address, Address n) const /*override*/ {
204 Address nread = std::min(n, available(address));
205 memcpy(buf, device_.const_data() + address, nread * sizeof(Value));
206 return nread;
207 }
208
209 Address write(const Value *buf, Address address, Address n) /*override*/ {
210 Address nwritten = std::min(n, available(address));
211 memcpy(device_.data() + address, buf, nwritten * sizeof(Value));
212 return nwritten;
213 }
214
215 const Value* data() const /*override*/ {
216 return (Value*)device_.const_data();
217 }
218};
219
220} // namespace
221} // namespace
222#endif
static Buffer< A, T >::Ptr instance(Address size)
Allocating constructor.
Base class for all buffers.
Definition Buffer.h:23
virtual Address size() const
Size of buffer.
Definition Buffer.h:93
SharedPointer< Buffer > Ptr
Reference counting smart pointer.
Definition Buffer.h:62
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.
void resize(Address n)
Change the size of the buffer.
static Buffer< A, T >::Ptr instance(const boost::iostreams::mapped_file_params &params)
Map a file according to boost parameters.
Address read(Value *buf, Address address, Address n) const
Reads data from a buffer.
A Address
Type of addresses.
const Value * data() const
Data for the buffer.
Buffer< A, T > Super
Type of base class.
Address write(const Value *buf, Address address, Address n)
Writes data to a buffer.
Address available(Address address) const
Distance to end of buffer.
Buffer< A, T >::Ptr copy() const
Create a new copy of buffer data.
static Buffer< A, T >::Ptr instance(Value *values, Address size)
Construct from caller-supplied data.
Reference-counting intrusive smart pointer.
Sawyer support library.