2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Defines gmx::ISerializer implementation for in-memory serialization.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_utility
44 #include "inmemoryserializer.h"
61 static constexpr size_t ValueSize = sizeof(T);
63 explicit CharBuffer(T value) { u.v = value; }
64 explicit CharBuffer(const char buffer[]) { std::copy(buffer, buffer + ValueSize, u.c); }
66 T value() const { return u.v; }
68 void appendTo(std::vector<char>* buffer)
70 buffer->insert(buffer->end(), u.c, u.c + ValueSize);
81 //! Return \c value with the byte order swapped.
83 T swapEndian(const T& value)
88 std::array<char, sizeof(T)> valueAsCharArray_;
89 } endianessSwappedValue;
91 endianessSwappedValue.value_ = value;
92 int hiByte = sizeof(T) - 1;
93 for (int loByte = 0; hiByte > loByte; loByte++, hiByte--)
95 std::swap(endianessSwappedValue.valueAsCharArray_[loByte],
96 endianessSwappedValue.valueAsCharArray_[hiByte]);
99 return endianessSwappedValue.value_;
102 /*! \brief Change the host-dependent endian settings to either Swap or DoNotSwap.
104 * \param endianSwapBehavior input swap behavior, might depend on host.
106 * \return Host-independent setting, either Swap or DoNotSwap. */
107 EndianSwapBehavior setEndianSwapBehaviorFromHost(EndianSwapBehavior endianSwapBehavior)
109 if (endianSwapBehavior == EndianSwapBehavior::SwapIfHostIsBigEndian)
111 return GMX_INTEGER_BIG_ENDIAN ? EndianSwapBehavior::Swap : EndianSwapBehavior::DoNotSwap;
113 else if (endianSwapBehavior == EndianSwapBehavior::SwapIfHostIsLittleEndian)
115 return GMX_INTEGER_BIG_ENDIAN ? EndianSwapBehavior::DoNotSwap : EndianSwapBehavior::Swap;
119 return endianSwapBehavior;
125 /********************************************************************
129 class InMemorySerializer::Impl
132 Impl(EndianSwapBehavior endianSwapBehavior) :
133 endianSwapBehavior_(setEndianSwapBehaviorFromHost(endianSwapBehavior))
138 void doValue(T value)
140 if (endianSwapBehavior_ == EndianSwapBehavior::Swap)
142 CharBuffer<T>(swapEndian(value)).appendTo(&buffer_);
146 CharBuffer<T>(value).appendTo(&buffer_);
149 void doString(const std::string& value)
151 doValue<uint64_t>(value.size());
152 buffer_.insert(buffer_.end(), value.begin(), value.end());
154 void doOpaque(const char* data, std::size_t size)
156 buffer_.insert(buffer_.end(), data, data + size);
159 std::vector<char> buffer_;
160 EndianSwapBehavior endianSwapBehavior_;
163 InMemorySerializer::InMemorySerializer(EndianSwapBehavior endianSwapBehavior) :
164 impl_(new Impl(endianSwapBehavior))
168 InMemorySerializer::~InMemorySerializer() = default;
170 std::vector<char> InMemorySerializer::finishAndGetBuffer()
172 return std::move(impl_->buffer_);
175 void InMemorySerializer::doBool(bool* value)
177 impl_->doValue(*value);
180 void InMemorySerializer::doUChar(unsigned char* value)
182 impl_->doValue(*value);
185 void InMemorySerializer::doChar(char* value)
187 impl_->doValue(*value);
190 void InMemorySerializer::doUShort(unsigned short* value)
192 impl_->doValue(*value);
195 void InMemorySerializer::doInt(int* value)
197 impl_->doValue(*value);
200 void InMemorySerializer::doInt32(int32_t* value)
202 impl_->doValue(*value);
205 void InMemorySerializer::doInt64(int64_t* value)
207 impl_->doValue(*value);
210 void InMemorySerializer::doFloat(float* value)
212 impl_->doValue(*value);
215 void InMemorySerializer::doDouble(double* value)
217 impl_->doValue(*value);
220 void InMemorySerializer::doReal(real* value)
222 impl_->doValue(*value);
225 void InMemorySerializer::doRvec(rvec* value)
227 for (int d = 0; d < DIM; d++)
229 doReal(&(*value)[d]);
233 void InMemorySerializer::doIvec(ivec* value)
235 for (int d = 0; d < DIM; d++)
241 void InMemorySerializer::doString(std::string* value)
243 impl_->doString(*value);
246 void InMemorySerializer::doOpaque(char* data, std::size_t size)
248 impl_->doOpaque(data, size);
251 /********************************************************************
252 * InMemoryDeserializer
255 class InMemoryDeserializer::Impl
258 explicit Impl(ArrayRef<const char> buffer, bool sourceIsDouble, EndianSwapBehavior endianSwapBehavior) :
260 sourceIsDouble_(sourceIsDouble),
262 endianSwapBehavior_(setEndianSwapBehaviorFromHost(endianSwapBehavior))
267 void doValue(T* value)
269 if (endianSwapBehavior_ == EndianSwapBehavior::Swap)
271 *value = swapEndian(CharBuffer<T>(&buffer_[pos_]).value());
275 *value = CharBuffer<T>(&buffer_[pos_]).value();
277 pos_ += CharBuffer<T>::ValueSize;
279 void doString(std::string* value)
282 doValue<uint64_t>(&size);
283 *value = std::string(&buffer_[pos_], size);
286 void doOpaque(char* data, std::size_t size)
288 std::copy(&buffer_[pos_], &buffer_[pos_ + size], data);
292 ArrayRef<const char> buffer_;
293 bool sourceIsDouble_;
295 EndianSwapBehavior endianSwapBehavior_;
298 InMemoryDeserializer::InMemoryDeserializer(ArrayRef<const char> buffer,
300 EndianSwapBehavior endianSwapBehavior) :
301 impl_(new Impl(buffer, sourceIsDouble, endianSwapBehavior))
305 InMemoryDeserializer::~InMemoryDeserializer() = default;
307 bool InMemoryDeserializer::sourceIsDouble() const
309 return impl_->sourceIsDouble_;
312 void InMemoryDeserializer::doBool(bool* value)
314 impl_->doValue(value);
317 void InMemoryDeserializer::doUChar(unsigned char* value)
319 impl_->doValue(value);
322 void InMemoryDeserializer::doChar(char* value)
324 impl_->doValue(value);
327 void InMemoryDeserializer::doUShort(unsigned short* value)
329 impl_->doValue(value);
332 void InMemoryDeserializer::doInt(int* value)
334 impl_->doValue(value);
337 void InMemoryDeserializer::doInt32(int32_t* value)
339 impl_->doValue(value);
342 void InMemoryDeserializer::doInt64(int64_t* value)
344 impl_->doValue(value);
347 void InMemoryDeserializer::doFloat(float* value)
349 impl_->doValue(value);
352 void InMemoryDeserializer::doDouble(double* value)
354 impl_->doValue(value);
357 void InMemoryDeserializer::doReal(real* value)
359 if (sourceIsDouble())
373 void InMemoryDeserializer::doRvec(rvec* value)
375 for (int d = 0; d < DIM; d++)
377 doReal(&(*value)[d]);
381 void InMemoryDeserializer::doIvec(ivec* value)
383 for (int d = 0; d < DIM; d++)
389 void InMemoryDeserializer::doString(std::string* value)
391 impl_->doString(value);
394 void InMemoryDeserializer::doOpaque(char* data, std::size_t size)
396 impl_->doOpaque(data, size);