Permalink
Browse files

working on it...

  • Loading branch information...
mortenvp committed Oct 27, 2017
1 parent 5baba9c commit 84afe8403934a0e86232b1583b082f336c9b1302
Showing with 201 additions and 30 deletions.
  1. +22 −9 README.rst
  2. +11 −7 src/bitter/reader.hpp
  3. +41 −7 src/bitter/to_type.hpp
  4. +11 −7 src/bitter/writer.hpp
  5. +40 −0 test/src/test_reader.cpp
  6. +13 −0 test/src/test_readme.cpp
  7. +31 −0 test/src/test_to_type.cpp
  8. +32 −0 test/src/test_writer.cpp
@@ -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
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
@@ -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,15 @@ 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.
Byte endianness
---------------
@@ -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 u8, u16, u24, u32, u40, u48, u56, or u64
reader(typename DataType::type value) :
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;
};
}
@@ -5,31 +5,65 @@
#pragma once
#include <cstdint>
#include <type_traits>
#include "types.hpp"
namespace bitter
{
template<class NativeType>
struct to_type;
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 value = u8;
using type = u8;
};
template<>
struct to_type<uint16_t>
{
using value = u16;
using type = u16;
};
template<>
struct to_type<uint32_t>
{
using value = u32;
using type = u32;
};
template<>
struct to_type<uint64_t>
{
using value = u64;
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;
@@ -71,3 +71,16 @@ TEST(test_readme, reading_a_msb0_bit_field)
assert(value2 == 0x56);
assert(value3 == 0x78);
}
TEST(test_readme, reading_a_generic_sized_bit_field)
{
auto reader = bitter::msb0_reader<bitter::u24, 4, 12, 8>(0x123456U);
uint8_t value0 = reader.field<0>().as<uint8_t>(); // Read bits 0-3
uint8_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);
}
@@ -0,0 +1,31 @@
// Copyright (c) Steinwurf ApS 2016.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.
#include <bitter/to_type.hpp>
#include <cstdint>
#include <gtest/gtest.h>
// Small Helper
template<class DataType, class BitterType>
using same = std::is_same<bitter::to_type<DataType>, BitterType>;
TEST(test_to_type, to_type)
{
EXPECT_TRUE((same<uint8_t, bitter::u8>::value));
EXPECT_TRUE((same<uint16_t, bitter::u16>::value));
EXPECT_TRUE((same<uint32_t, bitter::u32>::value));
EXPECT_TRUE((same<uint64_t, bitter::u64>::value));
EXPECT_TRUE((same<bitter::u8, bitter::u8>::value));
EXPECT_TRUE((same<bitter::u16, bitter::u16>::value));
EXPECT_TRUE((same<bitter::u24, bitter::u24>::value));
EXPECT_TRUE((same<bitter::u32, bitter::u32>::value));
EXPECT_TRUE((same<bitter::u40, bitter::u40>::value));
EXPECT_TRUE((same<bitter::u48, bitter::u48>::value));
EXPECT_TRUE((same<bitter::u56, bitter::u56>::value));
EXPECT_TRUE((same<bitter::u64, bitter::u64>::value));
}
@@ -11,6 +11,38 @@
#include <iostream>
#include <gtest/gtest.h>
TEST(test_bit_writer, write_integer)
{
{
auto writer = bitter::lsb0_writer<uint8_t, 4, 4>();
writer.field<0>(0x0U);
writer.field<1>(0xFU);
auto value = writer.data();
EXPECT_EQ(value, 0xF0U);
}
{
auto writer = bitter::lsb0_writer<uint16_t, 8, 8>();
writer.field<0>(0xF0U);
writer.field<1>(0x0FU);
auto value = writer.data();
EXPECT_EQ(value, 0x0FF0U);
}
{
auto writer = bitter::lsb0_writer<uint32_t, 16, 16>();
writer.field<0>(0xF0F0U);
writer.field<1>(0x0F0FU);
auto value = writer.data();
EXPECT_EQ(value, 0x0F0FF0F0U);
}
{
auto writer = bitter::lsb0_writer<uint64_t, 32, 32>();
writer.field<0>(0xF0F0F0F0U);
writer.field<1>(0x0F0F0F0FU);
auto value = writer.data();
EXPECT_EQ(value, 0x0F0F0F0FF0F0F0F0U);
}
}
TEST(test_bit_writer, write_bit)
{
{

0 comments on commit 84afe84

Please sign in to comment.