Skip to content

Instantly share code, notes, and snippets.

@cbsmith
Last active December 30, 2015 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbsmith/7836293 to your computer and use it in GitHub Desktop.
Save cbsmith/7836293 to your computer and use it in GitHub Desktop.
My demonstration of how byte swap can still be useful despite http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
// -*- compile-command: "g++ -O3 -march=native -std=c++11 -Wall -Werror endian.cpp -o endian" -*-
#include <fstream>
#include <ostream>
#include <istream>
#include <cstdint>
#include <algorithm>
#include <cassert>
#include <string>
#include <vector>
#include <limits>
#include <type_traits>
#include <iostream>
static const uint64_t BYTE_ORDER_TAG = 1ull << 56 | 2ull << 48 | 3ull << 40 | 4ull << 32 | 5ull << 24 | 6ull << 16 | 7ull << 8 | 8u;
static const uint64_t BYTE_ORDER_REVERSED_TAG = 8ull << 56 | 7ull << 48 | 6ull << 40 | 5ull << 32 | 4ull << 24 | 3ull << 16 | 2ull << 8 | 1ull;
template <typename Iter>
void saveVals(const std::string& path, Iter start, Iter stop) {
using element_type = decltype(*start);
std::ofstream store(path, std::ofstream::binary);
store.write(reinterpret_cast<const char *>(&BYTE_ORDER_TAG), sizeof(BYTE_ORDER_TAG));
std::for_each(start, stop, [&store](const element_type& t){store.write(reinterpret_cast<char*>(&t), sizeof(element_type));});
}
//just to avoid an outside dependency
template <typename T>
T byteswap(T x, typename std::enable_if<std::is_integral<T>::value >::type* = 0) {
char* start = reinterpret_cast<char *>(&x);
char* end = start + sizeof(T);
while (start < end) {
std::swap(*start++, *--end);
}
return x;
}
//use gcc builtins to help the compiler do optimized byteswaps
#define fast_byteswap_helper(inttype, builtinswap) \
inline inttype byteswap(inttype x, typename std::enable_if<std::is_integral<inttype>::value >::type* = 0) { \
return builtinswap(x); \
}
#define fast_byteswap(intwidth) \
fast_byteswap_helper(int##intwidth##_t, __builtin_bswap##intwidth ) \
fast_byteswap_helper(uint##intwidth##_t, __builtin_bswap##intwidth )
fast_byteswap(16)
fast_byteswap(32)
fast_byteswap(64)
template <typename OutputIter, typename element_type = typename OutputIter::container_type::value_type>
void readVals(const std::string& path, OutputIter target) {
// using element_type = typename std::iterator_traits<OutputIter>::value_type;
std::ifstream store(path, std::ifstream::binary);
uint64_t byte_order;
store.read(reinterpret_cast<char *>(&byte_order), sizeof(byte_order));
const bool needs_swap = byte_order != BYTE_ORDER_TAG;
assert (needs_swap == (byte_order == BYTE_ORDER_REVERSED_TAG));
while (store) {
char temp[sizeof(element_type)];
if (store.read(temp, sizeof(element_type))) {
element_type& typed_temp{*reinterpret_cast<element_type*>(temp)};
*target++ = (needs_swap) ? byteswap(typed_temp) : typed_temp;
}
}
}
void muck_up_byte_order(const std::string& path) {
std::fstream tweaker("store", std::fstream::binary | std::fstream::out | std::fstream::in);
tweaker.seekp(0);
tweaker.write(reinterpret_cast<const char*>(&BYTE_ORDER_REVERSED_TAG), sizeof(BYTE_ORDER_REVERSED_TAG));
tweaker.flush(); //paranoia
}
int main() {
using namespace std;
using value_type = int;
value_type test_vals[4] = { 42, -52, 0, 1 };
const size_t test_size = sizeof(test_vals)/sizeof(decltype(test_vals[0]));
cout << "Test values: ";
copy(begin(test_vals), end(test_vals), ostream_iterator<value_type>(cout, " "));
cout << endl;
saveVals("store", begin(test_vals), end(test_vals));
{
vector<value_type> answers{};
readVals("store", back_inserter(answers));
assert (test_size == answers.size());
for (size_t i = 0; i < test_size; ++i) {
assert(test_vals[i] == answers[i]);
}
}
muck_up_byte_order("store");
//test again
{
vector<value_type> answers{};
assert (answers.size() == 0);
readVals("store", back_inserter(answers));
assert (answers.size() == test_size);
for (size_t i = 0; i < test_size; ++i) {
assert((test_vals[i] == byteswap(test_vals[i])) || (test_vals[i] != answers[i]));
assert(test_vals[i] == byteswap(answers[i]));
}
}
cout << "Verified" << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment