EPICS Base  7.0.6.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
osiWireFormat.h
1 /*************************************************************************\
2 * Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * SPDX-License-Identifier: EPICS
7 * EPICS BASE is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /*
12  * Author Jeffrey O. Hill
14  */
15 
16 #ifndef osiWireFormat
17 #define osiWireFormat
18 
19 #include "epicsTypes.h"
20 
21 //
22 // With future CA protocols user defined payload composition will be
23 // supported and we will need to move away from a naturally aligned
24 // protocol (because pad byte overhead will probably be excessive when
25 // maintaining 8 byte natural alignment if the user isn't thinking about
26 // placing like sized elements together).
27 //
28 // Nevertheless, the R3.14 protocol continues to be naturally aligned,
29 // and all of the fields within the DBR_XXXX types are naturally aligned.
30 // Therefore we support here two wire transfer interfaces (naturally
31 // aligned and otherwise) because there are important optimizations
32 // specific to each of them.
33 //
34 // At some point in the future the naturally aligned interfaces might
35 // be eliminated (or unbundled from base) should they be no-longer needed.
36 //
37 
38 template < class T >
39 void WireGet ( const epicsUInt8 * pWireSrc, T & );
40 
41 template < class T >
42 void WireSet ( const T &, epicsUInt8 * pWireDst );
43 
44 template < class T >
45 void AlignedWireGet ( const T &, T & );
46 
47 template < class T >
48 void AlignedWireSet ( const T &, T & );
49 
50 template < class T >
52 public:
53  AlignedWireRef ( T & ref );
54  operator T () const;
55  AlignedWireRef < T > & operator = ( const T & );
56 private:
57  T & _ref;
58  AlignedWireRef ( const AlignedWireRef & );
59  AlignedWireRef & operator = ( const AlignedWireRef & );
60 };
61 
62 template < class T >
63 class AlignedWireRef < const T > {
64 public:
65  AlignedWireRef ( const T & ref );
66  operator T () const;
67 private:
68  const T & _ref;
69  AlignedWireRef ( const AlignedWireRef & );
70  AlignedWireRef & operator = ( const AlignedWireRef & );
71 };
72 
73 template < class T >
74 inline AlignedWireRef < T > :: AlignedWireRef ( T & ref ) :
75  _ref ( ref )
76 {
77 }
78 
79 template < class T >
80 inline AlignedWireRef < T > :: operator T () const
81 {
82  T tmp;
83  AlignedWireGet ( _ref, tmp );
84  return tmp;
85 }
86 
87 template < class T >
88 inline AlignedWireRef < T > & AlignedWireRef < T > :: operator = ( const T & src )
89 {
90  AlignedWireSet ( src, _ref );
91  return *this;
92 }
93 
94 template < class T >
95 inline AlignedWireRef < const T > :: AlignedWireRef ( const T & ref ) :
96  _ref ( ref )
97 {
98 }
99 
100 template < class T >
101 inline AlignedWireRef < const T > :: operator T () const
102 {
103  T tmp;
104  AlignedWireGet ( _ref, tmp );
105  return tmp;
106 }
107 
108 // may be useful when creating support for little endian
109 inline epicsUInt16 byteSwap ( const epicsUInt16 & src )
110 {
111  return static_cast < epicsUInt16 >
112  ( ( src << 8u ) | ( src >> 8u ) );
113 }
114 
115 // may be useful when creating support for little endian
116 inline epicsUInt32 byteSwap ( const epicsUInt32 & src )
117 {
118  epicsUInt32 tmp0 = byteSwap (
119  static_cast < epicsUInt16 > ( src >> 16u ) );
120  epicsUInt32 tmp1 = byteSwap (
121  static_cast < epicsUInt16 > ( src ) );
122  return static_cast < epicsUInt32 >
123  ( ( tmp1 << 16u ) | tmp0 );
124 }
125 
126 template < class T > union WireAlias;
127 
128 template <>
129 union WireAlias < epicsInt8 > {
130  epicsUInt8 _u;
131  epicsInt8 _o;
132 };
133 
134 template <>
135 union WireAlias < epicsInt16 > {
136  epicsUInt16 _u;
137  epicsInt16 _o;
138 };
139 
140 template <>
141 union WireAlias < epicsInt32 > {
142  epicsUInt32 _u;
143  epicsInt32 _o;
144 };
145 
146 template <>
147 union WireAlias < epicsFloat32 > {
148  epicsUInt32 _u;
149  epicsFloat32 _o;
150 };
151 
152 //
153 // Missaligned unsigned wire format get/set can be implemented generically
154 // w/o performance penalty. Attempts to improve this on architectures that
155 // don't have alignment requirements will probably get into trouble with
156 // over-aggressive optimization under strict aliasing rules.
157 //
158 
159 template < class T >
160 inline void WireGet ( const epicsUInt8 * pWireSrc, T & dst )
161 {
162  // copy through union here
163  // a) prevents over-aggressive optimization under strict aliasing rules
164  // b) doesnt preclude extra copy operation being optimized away
165  WireAlias < T > tmp;
166  WireGet ( pWireSrc, tmp._u );
167  dst = tmp._o;
168 }
169 
170 template <>
171 inline void WireGet < epicsUInt8 > (
172  const epicsUInt8 * pWireSrc, epicsUInt8 & dst )
173 {
174  dst = pWireSrc[0];
175 }
176 
177 template <>
178 inline void WireGet < epicsUInt16 > (
179  const epicsUInt8 * pWireSrc, epicsUInt16 & dst )
180 {
181  dst = static_cast < epicsUInt16 > (
182  ( pWireSrc[0] << 8u ) | pWireSrc[1] );
183 }
184 
185 template <>
186 inline void WireGet < epicsUInt32 > (
187  const epicsUInt8 * pWireSrc, epicsUInt32 & dst )
188 {
189  dst = static_cast < epicsUInt32 > (
190  ( pWireSrc[0] << 24u ) |
191  ( pWireSrc[1] << 16u ) |
192  ( pWireSrc[2] << 8u ) |
193  pWireSrc[3] );
194 }
195 
196 template < class T >
197 inline void WireSet ( const T & src, epicsUInt8 * pWireDst )
198 {
199  // copy through union here
200  // a) prevents over-aggressive optimization under strict aliasing rules
201  // b) doesnt preclude extra copy operation being optimized away
202  WireAlias < T > tmp;
203  tmp._o = src;
204  WireSet ( tmp._u, pWireDst );
205 }
206 
207 template <>
208 inline void WireSet < epicsUInt8 > (
209  const epicsUInt8 & src, epicsUInt8 * pWireDst )
210 {
211  pWireDst[0] = src;
212 }
213 
214 template <>
215 inline void WireSet < epicsUInt16 > (
216  const epicsUInt16 & src, epicsUInt8 * pWireDst )
217 {
218  pWireDst[0] = static_cast < epicsUInt8 > ( src >> 8u );
219  pWireDst[1] = static_cast < epicsUInt8 > ( src );
220 }
221 
222 template <>
223 inline void WireSet < epicsUInt32 > (
224  const epicsUInt32 & src, epicsUInt8 * pWireDst )
225 {
226  pWireDst[0] = static_cast < epicsUInt8 > ( src >> 24u );
227  pWireDst[1] = static_cast < epicsUInt8 > ( src >> 16u );
228  pWireDst[2] = static_cast < epicsUInt8 > ( src >> 8u );
229  pWireDst[3] = static_cast < epicsUInt8 > ( src );
230 }
231 
232 template < class T >
233 inline void AlignedWireGet ( const T & src, T & dst )
234 {
235  // copy through union here
236  // a) prevents over-aggressive optimization under strict aliasing rules
237  // b) doesnt preclude extra copy operation being optimized away
238  WireAlias < T > srcu, dstu;
239  srcu._o = src;
240  AlignedWireGet ( srcu._u, dstu._u );
241  dst = dstu._o;
242 }
243 
244 template < class T >
245 inline void AlignedWireSet ( const T & src, T & dst )
246 {
247  // copy through union here
248  // a) prevents over-aggressive optimization under strict aliasing rules
249  // b) doesnt preclude extra copy operation being optimized away
250  WireAlias < T > srcu, dstu;
251  srcu._o = src;
252  AlignedWireSet ( srcu._u, dstu._u );
253  dst = dstu._o;
254 }
255 
256 #include "osdWireFormat.h"
257 
258 #endif // osiWireFormat
The core data types used by epics.