blob: 379df69508cadc8943061575546ad59510ef1180 [file] [log] [blame]
// Copyright 2017 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 GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_BITFIELD_H_
#define GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_BITFIELD_H_
#include <stdint.h>
#include <type_traits>
namespace wlan {
namespace common {
template <typename ValueType> class BitField {
public:
static_assert(std::is_unsigned<ValueType>::value,
"BitField only supports unsigned value types.");
constexpr explicit BitField(ValueType val) : val_(val) {}
constexpr BitField() = default;
constexpr size_t len() { return sizeof(ValueType); }
void clear() { val_ = 0; }
void set_val(ValueType val) { val_ = val; }
ValueType* mut_val() { return &val_; }
ValueType val() const { return val_; }
template <unsigned int offset, size_t len> ValueType get_bits() const {
return (val_ & mask<offset, len>()) >> offset;
}
template <unsigned int offset, size_t len> void set_bits(ValueType value) {
ValueType cleared = val_ & ~mask<offset, len>();
val_ = cleared | ((value << offset) & mask<offset, len>());
}
private:
template <unsigned int offset, size_t len> constexpr static ValueType mask() {
static_assert(len > 0, "BitField member length must be positive");
static_assert(offset < (sizeof(ValueType) * 8),
"offset must be less than size of the BitField");
static_assert(offset + len <= (sizeof(ValueType) * 8),
"offset + len must be less than or equal to size of the BitField");
return ((1ull << len) - 1) << offset;
}
ValueType val_ = 0;
};
// Specialize the mask function for full 64-bit fields, since (1 << 64) - 1 is an error.
template <> template <> constexpr uint64_t BitField<uint64_t>::mask<0, 64>() {
return ~0ull;
}
template <typename AddrType, typename ValueType, AddrType A>
class AddressableBitField : public BitField<ValueType> {
public:
static constexpr AddrType addr() { return A; }
constexpr explicit AddressableBitField(ValueType val) : BitField<ValueType>(val) {}
constexpr AddressableBitField() = default;
};
namespace internal {
// Due to the way printf format specifiers work, we don't want to require all bitfield getters and
// setters to use uint64_t. The following type traits allow selecting the smallest uintN_t type that
// will hold the length of the bitfield.
constexpr size_t next_bitsize(size_t n) {
// clang-format off
return n < 8 ? 8 :
n < 16 ? 16 :
n < 32 ? 32 : 64;
// clang-format on
}
template <size_t N> struct IntegerType;
template <> struct IntegerType<8> { using type = uint8_t; };
template <> struct IntegerType<16> { using type = uint16_t; };
template <> struct IntegerType<32> { using type = uint32_t; };
template <> struct IntegerType<64> { using type = uint64_t; };
template <size_t N> struct Integer : IntegerType<next_bitsize(N)> {};
} // namespace internal
#define WLAN_BIT_FIELD(name, offset, len) \
void set_##name(::wlan::common::internal::Integer<len>::type val) { \
this->template set_bits<offset, len>(val); \
} \
constexpr ::wlan::common::internal::Integer<len>::type name() const { \
return this->template get_bits<offset, len>(); \
}
} // namespace common
} // namespace wlan
#endif // GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_BITFIELD_H_