blob: 59db393ae5d27130a5481c50d362fc072e04f82d [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_BIGENDIAN_H_
#define SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_BIGENDIAN_H_
#include <byteswap.h>
#include <endian.h>
#include <stdint.h>
// Fuchsia only runs on little endian architectures.
// So this file assumes that it is true. Just to be safe:
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
// Store an object of type 'T' as a big endian value doing automagic byte
// swapping when assigned or read.
template <typename T>
class __attribute__((packed)) BigEndian {
private:
// The actual in-memory object stored in big-endian form.
T rep;
// Function to do the swapping when needed.
// Leaving the generic implementation commented out for now. Ideally, it
// should never be needed. The specializations below should be exhaustive.
inline static T swap(const T& arg); /* {
T ret;
// Start by pointing 1 byte past the input arg.
// And at the beginning of the value to return.
// Then, bopy bytes backwards.
const char* src = reinterpret_cast<const char*>(&arg + 1);
char* tgt = reinterpret_cast<char*>(&ret);
for (size_t i = 0; i < sizeof(T); i++)
*dst++ = *--src;
return ret;
} */
public:
using wrapped_type = T;
BigEndian() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
BigEndian(const T& t) : rep(swap(t)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
operator T() const { return swap(rep); }
T val() const { return swap(rep); }
T GetBE() const { return rep; } // Returns the unswapped value.
T SetBE(T t) { // Sets the unswapped value (and returns the swapped one).
rep = t;
return val();
}
};
// The uint8_t version is just a noop.
template <>
inline uint8_t BigEndian<uint8_t>::swap(const uint8_t& arg) {
return arg;
}
static_assert(sizeof(BigEndian<uint8_t>) == sizeof(uint8_t));
// Speciliazations to use the (presumably) more efficient bswap functions from
// byteswap.h for the basic integer types.
template <>
inline uint16_t BigEndian<uint16_t>::swap(const uint16_t& arg) {
return bswap_16(arg);
}
static_assert(sizeof(BigEndian<uint16_t>) == sizeof(uint16_t));
template <>
inline uint32_t BigEndian<uint32_t>::swap(const uint32_t& arg) {
return bswap_32(arg);
}
static_assert(sizeof(BigEndian<uint32_t>) == sizeof(uint32_t));
template <>
inline uint64_t BigEndian<uint64_t>::swap(const uint64_t& arg) {
return bswap_64(arg);
}
static_assert(sizeof(BigEndian<uint64_t>) == sizeof(uint64_t));
#endif // SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_BIGENDIAN_H_