celestia/src/celutil/binarywrite.h

114 lines
2.7 KiB
C++

#pragma once
#include <cstring>
#include <ostream>
#include <type_traits>
#include <utility>
#include <config.h>
namespace celestia::util
{
/*! Write a value to an output stream in machine-native byte order.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeNative(std::ostream& out, T value)
{
char data[sizeof(T)];
std::memcpy(data, &value, sizeof(T));
return out.write(data, sizeof(T)).good();
}
template<>
inline bool writeNative<char>(std::ostream& out, char value)
{
return out.put(value).good();
}
template<>
inline bool writeNative<signed char>(std::ostream& out, signed char value)
{
return out.put(static_cast<char>(value)).good();
}
template<>
inline bool writeNative<unsigned char>(std::ostream& out, unsigned char value)
{
return out.put(static_cast<unsigned char>(value)).good();
}
/*! Write a value to an output stream with the opposite of machine-native byte order.
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeReversed(std::ostream& out, T value)
{
char data[sizeof(T)];
std::memcpy(data, &value, sizeof(T));
for (std::size_t i = 0; i < sizeof(T) / 2; ++i)
{
std::swap(data[i], data[sizeof(T) - i - 1]);
}
return out.write(data, sizeof(T)).good();
}
template<>
inline bool writeReversed<char>(std::ostream& out, char value)
{
return writeNative(out, value);
}
template<>
inline bool writeReversed<signed char>(std::ostream& out, signed char value)
{
return writeNative(out, value);
}
template<>
inline bool writeReversed<unsigned char>(std::ostream& out, unsigned char value)
{
return writeNative(out, value);
}
#ifdef WORDS_BIGENDIAN
/*! Write a value to an output stream in little-endian byte order
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeLE(std::ostream& out, T value)
{
return writeReversed(out, value);
}
/*! Write a value to an output stream in big-endian byte order
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeBE(std::ostream& out, T value)
{
return writeNative(out, value);
}
#else
/*! Write a value to an output stream in little-endian byte order
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeLE(std::ostream& out, T value)
{
return writeNative(out, value);
}
/*! Write a value to an output stream in big-endian byte order
*/
template<typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
inline bool writeBE(std::ostream& out, T value)
{
return writeReversed(out, value);
}
#endif
} // end namespace celestia::util