Permalink
Browse files

Merge pull request #18 from steinwurf/add-workaround-for-native-types

added mapping function for native types
  • Loading branch information...
jpihl committed Oct 27, 2017
2 parents 8ec14f7 + ebfa7d0 commit e22818803ba19b8cc4f8a0cb670e0a4fdbb518fa
@@ -6,7 +6,10 @@ detailed list of every change, see the Git log.
Latest
------
* tbd
* Minor: Added support for native types in the bitter readers and
writers. Such that using ``uint8_t``, ``uint16_t`` etc. now is the
default. Using the ``u8``, ``u16``, ``u24`` etc. types is still
possible and used under-the-hood by bitter.
4.0.0
-----
@@ -15,15 +15,19 @@ Usage
bitter provides 4 different readers/writers::
bitter::lsb0_writer<DataType, Fields...>();
bitter::lsb0_reader<DataType, Fields...>();
bitter::msb0_writer<DataType, Fields...>();
bitter::msb0_reader<DataType, Fields...>();
Where ``DataType`` is a bitter type e.g. ``u8``, ``u16``,
``u24`` etc. (u8 is short for unsigned 8 bit). ``Fields...`` is a variadic
bitter::lsb0_writer<Type, Fields...>();
bitter::lsb0_reader<Type, Fields...>();
bitter::msb0_writer<Type, Fields...>();
bitter::msb0_reader<Type, Fields...>();
Where ``Type`` is a unsigned integer type e.g. ``uint8_t``, ``uint16_t``,
``uint32_t`` etc. (``uint8_t`` is short for unsigned 8 bit, these types
are defined in the ``<ctdint>`` header). ``Fields...`` is a variadic
template argument specifying the different bit fields. The curiously
looking ``lsb0`` and ``msb0`` specifies the "bit numbering" used.
looking ``lsb0`` and ``msb0`` specifies the "bit numbering" used. In some
rare cases you may want to read e.g. 24 bits or 40 bits for which no
standard integer types are defined, however also for those you can use
bitter see Section `Generic sized bit fields`_ further down.
To use bitter for reading/writing bit fields you need to first decide on
what bit numbering scheme to use - if you never heard about this concept
@@ -63,10 +67,10 @@ LSB 0 mode
::
// Using an u32 data type divided into 4 bit fields each 8 bits in
// Using an uint32_t data type divided into 4 bit fields each 8 bits in
// size. The sum of the bit fields must match the number of bits in the
// data type.
auto writer = bitter::lsb0_writer<bitter::u32, 8, 8, 8, 8>();
auto writer = bitter::lsb0_writer<uint32_t, 8, 8, 8, 8>();
writer.field<0>(0x12); // Write bits 0-7
writer.field<1>(0x34); // Write bits 8-15
@@ -83,10 +87,10 @@ MSB 0 mode
::
// Using an u32 data type divided into 4 bit fields each 8 bits in
// Using an uint32_t data type divided into 4 bit fields each 8 bits in
// size. The sum of the bit fields must match the number of bits in the
// data type.
auto writer = bitter::msb0_writer<bitter::u32, 8, 8, 8, 8>();
auto writer = bitter::msb0_writer<uint32_t, 8, 8, 8, 8>();
writer.field<0>(0x12); // Write bits 24-31
writer.field<1>(0x34); // Write bits 16-23
@@ -108,7 +112,7 @@ LSB 0 mode
::
auto reader = bitter::lsb0_reader<bitter::u32, 8, 8, 8, 8>(0x12345678);
auto reader = bitter::lsb0_reader<uint32_t, 8, 8, 8, 8>(0x12345678);
uint8_t value0 = reader.field<0>().as<uint8_t>(); // Read bits 0-7
uint8_t value1 = reader.field<1>().as<uint8_t>(); // Read bits 8-15
@@ -128,7 +132,7 @@ MSB 0 mode
::
auto reader = bitter::msb0_reader<bitter::u32, 8, 8, 8, 8>(0x12345678);
auto reader = bitter::msb0_reader<uint32_t, 8, 8, 8, 8>(0x12345678);
uint8_t value0 = reader.field<0>().as<uint8_t>(); // Read bits 0-7
uint8_t value1 = reader.field<1>().as<uint8_t>(); // Read bits 8-15
@@ -227,7 +231,7 @@ inside the byte.
If on the other hand we use the ``msb0_reader`` the example would be::
auto reader = bitter::msb0_reader<bitter::u8, 1, 2, 3, 2>(0xdeadbeef);
auto reader = bitter::msb0_reader<uint8_t, 1, 2, 3, 2>(0xdeadbeef);
We would have the following layout of the four fields inside the byte::
@@ -240,6 +244,27 @@ We would have the following layout of the four fields inside the byte::
+-----------+ bit
Generic sized bit fields
------------------------
In some cases you may want to read/write an odd number of bytes e.g. 5
corresponding to 40 bits from//to a value. In that case you can use
bitter's generic data types (defined in ``src/bitter/types.hpp``) such
as ``u8``, ``u16``, ``u24``, ``u32``, ``u40`` etc.
Small example::
auto reader = bitter::msb0_reader<bitter::u24, 4, 12, 8>(0x123456U);
uint8_t value0 = reader.field<0>().as<uint8_t>(); // Read bits 0-3
uint16_t value1 = reader.field<1>().as<uint16_t>(); // Read bits 4-15
uint8_t value2 = reader.field<2>().as<uint8_t>(); // Read bits 16-23
assert(value0 == 0x1);
assert(value1 == 0x234);
assert(value2 == 0x56);
Byte endianness
---------------
@@ -10,7 +10,6 @@
int main()
{
uint32_t value = 0x8028041U;
auto reader = bitter::lsb0_reader<bitter::u32, 1, 7, 8, 16>(value);
@@ -12,6 +12,7 @@
#include "msb0.hpp"
#include "bit_field.hpp"
#include "types.hpp"
#include "to_type.hpp"
#include <cstdint>
#include <vector>
@@ -22,22 +23,25 @@ namespace bitter
{
/// @brief Reader class used for reading the content
/// of the value parsed to the reader at initialization
template<typename DataType, typename BitNumbering, uint32_t... Sizes>
template<typename Type, typename BitNumbering, uint32_t... Sizes>
class reader
{
public:
// Get the bitter type
using bitter_type = to_type<Type>;
/// Small alias for the bit_field
template<uint32_t Index>
using bit_field_type =
bit_field<typename DataType::type, field_size_in_bits<Index, Sizes...>()>;
bit_field<typename bitter_type::type, field_size_in_bits<Index, Sizes...>()>;
/// @brief Reader constructor
/// DataType must be either uint8_t, uint16_t, uint32_t, or uint64_t
reader(typename DataType::type value) :
/// DataType must be either u8, u16, u24, u32, u40, u48, u56, or u64
reader(typename bitter_type::type value) :
m_value(value)
{
static_assert(size_in_bits<DataType>() == sum_sizes<Sizes...>(),
static_assert(size_in_bits<bitter_type>() == sum_sizes<Sizes...>(),
"size of the DataType is not equal to the sum of sizes");
}
@@ -52,14 +56,14 @@ class reader
/// @brief Function used as a wrapper, used for retrieving a field
/// based on the Index provide
template<uint32_t Index>
typename DataType::type get() const
typename bitter_type::type get() const
{
return field_get<DataType, BitNumbering, Index, Sizes...>(m_value);
return field_get<bitter_type, BitNumbering, Index, Sizes...>(m_value);
}
private:
/// Store the value containing the data used by the reader
typename DataType::type m_value;
typename bitter_type::type m_value;
};
}
@@ -0,0 +1,69 @@
// Copyright (c) Steinwurf ApS 2016.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.
#pragma once
#include <cstdint>
#include <type_traits>
#include "types.hpp"
namespace bitter
{
namespace detail
{
/// Base case for BitterTypes (see types.hpp)
template<class BitterType>
struct to_type
{
static_assert(BitterType::size > 0, "DataType must have size.");
static_assert(std::is_unsigned<typename BitterType::type>::value,
"DataType must have a nested type which is unsigned. "
"See types.hpp");
using type = BitterType;
};
/// Special case for integer types
template<>
struct to_type<uint8_t>
{
using type = u8;
};
template<>
struct to_type<uint16_t>
{
using type = u16;
};
template<>
struct to_type<uint32_t>
{
using type = u32;
};
template<>
struct to_type<uint64_t>
{
using type = u64;
};
}
/// Helper function that converts a Type to a BitterType which is
/// defined in types.hpp
///
/// If the Type is a BitterType the function is just the identity
/// i.e.:
///
/// bitter::to_type<bitter::u8> == bitter::u8
///
/// However, for other integer types such as uint8_t we have:
///
/// bitter::to_type<uint8_t> == bitter::u8
///
template<class Type>
using to_type = typename detail::to_type<Type>::type;
}
@@ -11,6 +11,7 @@
#include "field_size_in_bits.hpp"
#include "field_set.hpp"
#include "types.hpp"
#include "to_type.hpp"
#include <cstdint>
#include <cassert>
@@ -21,18 +22,21 @@ namespace bitter
/// the fields given in the variadic template Sizes
template
<
typename DataType,
typename Type,
typename BitNumbering,
uint32_t... Sizes
>
class writer
{
public:
// Get the bitter type
using bitter_type = to_type<Type>;
/// Constructor
writer()
{
static_assert(size_in_bits<DataType>() ==
static_assert(size_in_bits<bitter_type>() ==
sum_sizes<Sizes...>(),
"The size of the DataType in bits must exactly match the "
"sum of all the bit fields. If needed an unused bit "
@@ -42,25 +46,25 @@ class writer
/// @brief based on the provided index, the value is written
/// @param value is the data, wished to written to the field at Index
template<uint32_t Index>
void field(typename DataType::type value)
void field(typename bitter_type::type value)
{
static_assert(field_size_in_bits<Index, Sizes...>() <=
size_in_bits<DataType>(), "The field size in bits cannot "
size_in_bits<bitter_type>(), "The field size in bits cannot "
"be larger than the total size of the data type");
m_data = field_set<
DataType, BitNumbering, Index, Sizes...>(m_data, value);
bitter_type, BitNumbering, Index, Sizes...>(m_data, value);
}
/// @return The value create by the writer containing the bit fields
typename DataType::type data() const
typename bitter_type::type data() const
{
return m_data;
}
private:
/// The value built by the writer containing the different fields
typename DataType::type m_data = 0;
typename bitter_type::type m_data = 0;
};
}
@@ -11,6 +11,46 @@
#include <gtest/gtest.h>
TEST(test_bit_reader, read_integer)
{
{
uint8_t input = 0x0FU;
auto reader = bitter::lsb0_reader<uint8_t, 4, 4>(input);
auto value = reader.field<0>().as<uint8_t>();
EXPECT_EQ(0xFU, value);
value = reader.field<1>().as<uint8_t>();
EXPECT_EQ(0x0U, value);
}
{
uint16_t input = 0x0FF0U;
auto reader = bitter::lsb0_reader<uint16_t, 8, 8>(input);
auto value = reader.field<0>().as<uint8_t>();
EXPECT_EQ(0xF0U, value);
value = reader.field<1>().as<uint8_t>();
EXPECT_EQ(0x0FU, value);
}
{
uint32_t input = 0x0FF0FF00U;
auto reader = bitter::lsb0_reader<uint32_t, 16, 16>(input);
auto value = reader.field<0>().as<uint16_t>();
EXPECT_EQ(0xFF00U, value);
value = reader.field<1>().as<uint16_t>();
EXPECT_EQ(0x0FF0U, value);
}
{
uint64_t input = 0xFFF0FF000FF0FF00U;
auto reader = bitter::lsb0_reader<uint64_t, 32, 32>(input);
auto value = reader.field<0>().as<uint32_t>();
EXPECT_EQ(0x0FF0FF00U, value);
value = reader.field<1>().as<uint32_t>();
EXPECT_EQ(0xFFF0FF00U, value);
}
}
TEST(test_bit_reader, read_bit)
{
uint32_t input = 0x0FF0FF00U;
Oops, something went wrong.

0 comments on commit e228188

Please sign in to comment.