Files
epics-base/modules/libcom/src/osi/osiWireFormat.h
Michael Davidsaver e34b6c5c0c Fix spelling in comments
Should be non-functional, except for some error message strings.
2021-08-29 07:27:50 -07:00

259 lines
6.8 KiB
C++

/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#ifndef osiWireFormat
#define osiWireFormat
#include "epicsTypes.h"
//
// With future CA protocols user defined payload composition will be
// supported and we will need to move away from a naturally aligned
// protocol (because pad byte overhead will probably be excessive when
// maintaining 8 byte natural alignment if the user isn't thinking about
// placing like sized elements together).
//
// Nevertheless, the R3.14 protocol continues to be naturally aligned,
// and all of the fields within the DBR_XXXX types are naturally aligned.
// Therefore we support here two wire transfer interfaces (naturally
// aligned and otherwise) because there are important optimizations
// specific to each of them.
//
// At some point in the future the naturally aligned interfaces might
// be eliminated (or unbundled from base) should they be no-longer needed.
//
template < class T >
void WireGet ( const epicsUInt8 * pWireSrc, T & );
template < class T >
void WireSet ( const T &, epicsUInt8 * pWireDst );
template < class T >
void AlignedWireGet ( const T &, T & );
template < class T >
void AlignedWireSet ( const T &, T & );
template < class T >
class AlignedWireRef {
public:
AlignedWireRef ( T & ref );
operator T () const;
AlignedWireRef < T > & operator = ( const T & );
private:
T & _ref;
AlignedWireRef ( const AlignedWireRef & );
AlignedWireRef & operator = ( const AlignedWireRef & );
};
template < class T >
class AlignedWireRef < const T > {
public:
AlignedWireRef ( const T & ref );
operator T () const;
private:
const T & _ref;
AlignedWireRef ( const AlignedWireRef & );
AlignedWireRef & operator = ( const AlignedWireRef & );
};
template < class T >
inline AlignedWireRef < T > :: AlignedWireRef ( T & ref ) :
_ref ( ref )
{
}
template < class T >
inline AlignedWireRef < T > :: operator T () const
{
T tmp;
AlignedWireGet ( _ref, tmp );
return tmp;
}
template < class T >
inline AlignedWireRef < T > & AlignedWireRef < T > :: operator = ( const T & src )
{
AlignedWireSet ( src, _ref );
return *this;
}
template < class T >
inline AlignedWireRef < const T > :: AlignedWireRef ( const T & ref ) :
_ref ( ref )
{
}
template < class T >
inline AlignedWireRef < const T > :: operator T () const
{
T tmp;
AlignedWireGet ( _ref, tmp );
return tmp;
}
// may be useful when creating support for little endian
inline epicsUInt16 byteSwap ( const epicsUInt16 & src )
{
return static_cast < epicsUInt16 >
( ( src << 8u ) | ( src >> 8u ) );
}
// may be useful when creating support for little endian
inline epicsUInt32 byteSwap ( const epicsUInt32 & src )
{
epicsUInt32 tmp0 = byteSwap (
static_cast < epicsUInt16 > ( src >> 16u ) );
epicsUInt32 tmp1 = byteSwap (
static_cast < epicsUInt16 > ( src ) );
return static_cast < epicsUInt32 >
( ( tmp1 << 16u ) | tmp0 );
}
template < class T > union WireAlias;
template <>
union WireAlias < epicsInt8 > {
epicsUInt8 _u;
epicsInt8 _o;
};
template <>
union WireAlias < epicsInt16 > {
epicsUInt16 _u;
epicsInt16 _o;
};
template <>
union WireAlias < epicsInt32 > {
epicsUInt32 _u;
epicsInt32 _o;
};
template <>
union WireAlias < epicsFloat32 > {
epicsUInt32 _u;
epicsFloat32 _o;
};
//
// Missaligned unsigned wire format get/set can be implemented generically
// w/o performance penalty. Attempts to improve this on architectures that
// don't have alignment requirements will probably get into trouble with
// over-aggressive optimization under strict aliasing rules.
//
template < class T >
inline void WireGet ( const epicsUInt8 * pWireSrc, T & dst )
{
// copy through union here
// a) prevents over-aggressive optimization under strict aliasing rules
// b) doesnt preclude extra copy operation being optimized away
WireAlias < T > tmp;
WireGet ( pWireSrc, tmp._u );
dst = tmp._o;
}
template <>
inline void WireGet < epicsUInt8 > (
const epicsUInt8 * pWireSrc, epicsUInt8 & dst )
{
dst = pWireSrc[0];
}
template <>
inline void WireGet < epicsUInt16 > (
const epicsUInt8 * pWireSrc, epicsUInt16 & dst )
{
dst = static_cast < epicsUInt16 > (
( pWireSrc[0] << 8u ) | pWireSrc[1] );
}
template <>
inline void WireGet < epicsUInt32 > (
const epicsUInt8 * pWireSrc, epicsUInt32 & dst )
{
dst = static_cast < epicsUInt32 > (
( pWireSrc[0] << 24u ) |
( pWireSrc[1] << 16u ) |
( pWireSrc[2] << 8u ) |
pWireSrc[3] );
}
template < class T >
inline void WireSet ( const T & src, epicsUInt8 * pWireDst )
{
// copy through union here
// a) prevents over-aggressive optimization under strict aliasing rules
// b) doesnt preclude extra copy operation being optimized away
WireAlias < T > tmp;
tmp._o = src;
WireSet ( tmp._u, pWireDst );
}
template <>
inline void WireSet < epicsUInt8 > (
const epicsUInt8 & src, epicsUInt8 * pWireDst )
{
pWireDst[0] = src;
}
template <>
inline void WireSet < epicsUInt16 > (
const epicsUInt16 & src, epicsUInt8 * pWireDst )
{
pWireDst[0] = static_cast < epicsUInt8 > ( src >> 8u );
pWireDst[1] = static_cast < epicsUInt8 > ( src );
}
template <>
inline void WireSet < epicsUInt32 > (
const epicsUInt32 & src, epicsUInt8 * pWireDst )
{
pWireDst[0] = static_cast < epicsUInt8 > ( src >> 24u );
pWireDst[1] = static_cast < epicsUInt8 > ( src >> 16u );
pWireDst[2] = static_cast < epicsUInt8 > ( src >> 8u );
pWireDst[3] = static_cast < epicsUInt8 > ( src );
}
template < class T >
inline void AlignedWireGet ( const T & src, T & dst )
{
// copy through union here
// a) prevents over-aggressive optimization under strict aliasing rules
// b) doesnt preclude extra copy operation being optimized away
WireAlias < T > srcu, dstu;
srcu._o = src;
AlignedWireGet ( srcu._u, dstu._u );
dst = dstu._o;
}
template < class T >
inline void AlignedWireSet ( const T & src, T & dst )
{
// copy through union here
// a) prevents over-aggressive optimization under strict aliasing rules
// b) doesnt preclude extra copy operation being optimized away
WireAlias < T > srcu, dstu;
srcu._o = src;
AlignedWireSet ( srcu._u, dstu._u );
dst = dstu._o;
}
#include "osdWireFormat.h"
#endif // osiWireFormat