/* -*- c++ -*-
C++ bitfield alias class
This file is part of the dpp library of C++ template classes
doc: http://diaxen.ssji.net/dpp/index.html
repo: https://www.ssji.net/svn/projets/trunk/libdpp
This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see
.
(c) 2011 Alexandre Becoulet
*/
#ifndef DPP_BITFIELD_HH_
#define DPP_BITFIELD_HH_
#include
/** @file @module{Bitfield alias} */
namespace dpp {
#ifndef DPP_BITFIELD_SWAP
/** @This globally changes swap mask used by @ref bitfield classes
by xoring with the swap mask value. */
# define DPP_BITFIELD_SWAP 0
#endif
/** @internal */
template
inline X _bitfield_swap(X x)
{
unsigned int m = swap_mask ^ (DPP_BITFIELD_SWAP);
if (m & 1)
x = ((x & 0x5555555555555555ULL) << 1) | ((x & 0xaaaaaaaaaaaaaaaaULL) >> 1);
if (m & 2)
x = ((x & 0x3333333333333333ULL) << 2) | ((x & 0xccccccccccccccccULL) >> 2);
if (m & 4)
x = ((x & 0x0f0f0f0f0f0f0f0fULL) << 4) | ((x & 0xf0f0f0f0f0f0f0f0ULL) >> 4);
if (sizeof(X) > 8 && (m & 8))
x = ((x & 0x00ff00ff00ff00ffULL) << 8) | ((x & 0xff00ff00ff00ff00ULL) >> 8);
if (sizeof(X) > 16 && (m & 16))
x = ((x & 0x0000ffff0000ffffULL) << 16) | ((x & 0xffff0000ffff0000ULL) >> 16);
if (sizeof(X) > 32 && (m & 32))
x = ((x & 0x00000000ffffffffULL) << 32) | ((x & 0xffffffff00000000ULL) >> 32);
return x;
}
#define _DPP_BITFIELD(C, X) \
class C \
{ \
static const X mask = ((1 << width) - 1); \
static const X smask = mask << position; \
\
public: \
\
/** @This creates a bitfield alias object for the given integer. */ \
C(X &x) \
: _x(x) \
{ \
} \
\
/** @This extracts bits from given integer. */ \
static const X get(X x) \
{ \
return (_bitfield_swap(x) >> position) & mask; \
} \
\
/** @This sets bits in referenced integer to given value. */ \
static void set(X &v, X x) \
{ \
static const X wmask = _bitfield_swap(smask); \
x = _bitfield_swap(x << position); \
v = (v & ~wmask) | (x & wmask); \
} \
\
/** @This extracts bits from aliased integer. */ \
operator X () const \
{ \
return get(_x); \
} \
\
/** @This sets bits in aliased integer to given value. */ \
X operator=(X x) \
{ \
set(_x, x); \
return x; \
} \
\
private: \
X &_x; \
}
/** @short Generic bitfield alias class
@module {Bitfield alias}
@header dpp/bitfield
@main
@This can be used to declare an alias which permit convenient
access to specified bits range inside an integer value.
This class requires the integer type as parameter, other classes
are available for 8, 16, 32 and 64 bits, signed and unsigned
integer types.
This class exposes bits at specified @tt position and @tt width
in aliased integer value.
@section {Bits swapping}
An additional @tt swap_mask parameter can be used to perform a
bits permutation on accessed integer. Each bit in the mask specify
size of swapped bit packets; for instance a mask value of
(8+16+32) performs a bytes swap on 32 bits values.
The value of the @ref DPP_BITFIELD_SWAP macro is xored with the
swap mask. Its default value is 0 and it can be defined before
including the @tt bitfield header. This allows globally
inverting swap mask depending on processor endianness.
@end section
*/
template
_DPP_BITFIELD(bitfield, X);
#define _DPP_BITFIELD_INT(u, s, n, t) \
/** @short s bits u bitfield alias class \
@module {Bitfield alias} \
@header dpp/bitfield \
\
@This can be used to declare an alias which permit convenient \
access to specified bits range inside an integer value. \
\
This class is designed to work with s bits u values. See the \
@ref bitfield class documentation for details. \
*/ \
template \
_DPP_BITFIELD(bitfield_##n, t);
_DPP_BITFIELD_INT(unsigned, 8, u8, uint8_t);
_DPP_BITFIELD_INT(signed, 8, s8, int8_t);
_DPP_BITFIELD_INT(unsigned, 16, u16, uint16_t);
_DPP_BITFIELD_INT(signed, 16, s16, int16_t);
_DPP_BITFIELD_INT(unsigned, 32, u32, uint32_t);
_DPP_BITFIELD_INT(signed, 32, s32, int32_t);
_DPP_BITFIELD_INT(unsigned, 64, u64, uint64_t);
_DPP_BITFIELD_INT(signed, 64, s64, int64_t);
}
#endif