Mercurial > code
view C++/Pack.h @ 266:41bdde9027c0
Pack:
* TypeInfo<T>::convert does not check and is constexpr
* Pack::convert does the check though
* Make overloads for std::[oi]stream available for different streams
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 14 Oct 2014 12:59:10 +0200 |
parents | c6513d9c696b |
children | bc9b5e7421a7 |
line wrap: on
line source
/* * Pack.h -- binary data serialization * * Copyright (c) 2013 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _PACK_H_ #define _PACK_H_ #include <cstdint> #include <fstream> #include <stdexcept> #include <string> /** * @class Pack * @brief Serialize binary data to files * * This class write and read binary data from files. It currently * support: * uint8_t, * uint16_t, * uint32_t, * uint64_t */ class Pack { public: /** * @enum Endian * @brief Endian mode */ enum Endian { Little, //! Little endian Big //! Big endian }; public: /** * Host system endian mode. */ static const Endian mode; /** * @struct TypeInfo * @brief Type information * * Used for conversions. */ template <typename T> struct TypeInfo { static const bool supported = false; }; /** * Convert data only if the requested endian is different. * * @param value the value to convert if needed * @param endian the endian mode * @return the converted value */ template <typename T> static inline T convert(T value, Endian endian) { static_assert(TypeInfo<T>::supported, "unsupported type"); if (endian != mode) return TypeInfo<T>::convert(value, endian); return value; } /** * Write nothing, stop recursion. */ static void write(std::ostream &, Endian) { } /** * Write binary data to the stream. * * @param out the output stream * @param endian the endian mode * @param args the arguments * @throw std::runtime_exception on error */ template <typename T, typename... Args> static void write(std::ostream &out, Endian endian, const T &value, const Args&... args) { T ret = convert(value, endian); out.write(reinterpret_cast<const char *>(&ret), TypeInfo<T>::size); write(out, endian, args...); } /** * Write binary data to the file. * * @param path the path to the file * @param endian the endian mode * @param args the arguments * @throw std::runtime_exception on error */ template <typename... Args> static void write(const std::string &path, Endian endian, const Args&... args) { std::ofstream out; out.open(path, std::ios_base::binary); if (!out.is_open()) throw std::runtime_error("Can't open file for writing"); write(out, endian, args...); } /** * Read nothing, stop recursion. */ static void read(std::istream &, Endian) { } /** * Read binary data from the stream. * * @param in the input stream * @param endian the endian mode * @param args the arguments * @throw std::runtime_exception on error */ template <typename T, typename... Args> static void read(std::istream &in, Endian endian, T &value, Args&... args) { in.read(reinterpret_cast<char *>(&value), TypeInfo<T>::size); value = convert(value, endian); read(in, endian, args...); } /** * Read binary data from the file. * * @param path the path to the file * @param endian the endian mode * @param args the arguments * @throw std::runtime_exception on error */ template <typename... Args> static void read(const std::string &path, Endian endian, Args&&... args) { std::ifstream in; in.open(path, std::ios_base::binary); if (!in.is_open()) throw std::runtime_error("Can't open file for reading"); read(in, endian, args...); } }; template <> struct Pack::TypeInfo<uint8_t> { static constexpr const bool supported = true; static constexpr const size_t size = sizeof (uint8_t); static constexpr uint8_t convert(uint8_t v, Endian endian) { return v; } }; template <> struct Pack::TypeInfo<uint16_t> { static constexpr const bool supported = true; static constexpr const size_t size = sizeof (uint16_t); static constexpr uint16_t convert(uint16_t v, Endian endian) { return (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L)); } }; template <> struct Pack::TypeInfo<uint32_t> { static constexpr const bool supported = true; static constexpr const size_t size = sizeof (uint32_t); static constexpr uint32_t convert(uint32_t v, Endian endian) { return ((((v) >> 24) & 0x000000FFL) | (((v) >> 8) & 0x0000FF00L) | (((v) << 8) & 0x00FF0000L) | (((v) << 24) & 0xFF000000L)); } }; template <> struct Pack::TypeInfo<uint64_t> { static constexpr const bool supported = true; static constexpr const size_t size = sizeof (uint64_t); static constexpr uint64_t convert(uint64_t v, Endian endian) { return ((((v) & 0xff00000000000000ull) >> 56) | (((v) & 0x00ff000000000000ull) >> 40) | (((v) & 0x0000ff0000000000ull) >> 24) | (((v) & 0x000000ff00000000ull) >> 8 ) | (((v) & 0x00000000ff000000ull) << 8 ) | (((v) & 0x0000000000ff0000ull) << 24) | (((v) & 0x000000000000ff00ull) << 40) | (((v) & 0x00000000000000ffull) << 56)); } }; #endif // !_PACK_H_