/* * types1516.h - IEEE 1516.2 compliant datatypes * http://virtualair.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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. * * Copyright (C) 2008 Petr Gotthard * * $Id: types1516.h 13 2008-05-23 15:43:11Z $ */ #include #include /* These templates implement efficient access functions that provide direct * access to IEEE 1516.2 compliant data buffers. * The data are manipulated "in situ", no temporary variables are created. * * The extensive use of template metaprogramming allows many operations to * be pre-calculated during compile-time. * See http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s09.html */ #ifdef _MSC_VER typedef unsigned __int64 uint64_t; typedef __int64 int64_t; typedef unsigned __int32 uint32_t; typedef __int32 int32_t; typedef unsigned __int16 uint16_t; typedef __int16 int16_t; typedef unsigned __int8 uint8_t; typedef __int8 int8_t; #endif // #define TYPES1516_DISPLAYPRINTABLE //! Print the physical data buffer (for debugging purposes only) inline std::ostream& __print_buffer(std::ostream& stream, const void *buffer, size_t length) { static const size_t cBytesPerLine = 16; size_t offset = 0; while (length != 0) { stream << std::hex << std::setfill('0') << std::setw(4) << (unsigned)offset << ": "; size_t i = std::min(cBytesPerLine, length); const unsigned char* p = (const unsigned char*)buffer; for(size_t j = i; j > 0; j--) stream << " " << std::hex << std::setfill('0') << std::setw(2) << (unsigned)*p++; #ifdef TYPES1516_DISPLAYPRINTABLE for(size_t j = cBytesPerLine - i; j > 0; j--) stream << " "; stream << " "; p = (const unsigned char*)buffer; for(size_t j = i; j > 0; j--) { char ch = *p++; stream << (isprint(ch) ? ch : ' '); } #endif stream << std::endl; buffer = (const unsigned char*)buffer + i; length -= i; offset += i; } return stream; } //! Swap bytes of the type /*! Template specializations are defined for each possible . */ template struct __swap; //! Conversion to the Little Endian encoding template struct LittleEndian { inline const T operator()(const T& x) const { #if __BYTE_ORDER == __LITTLE_ENDIAN return x; #elif __BYTE_ORDER == __BIG_ENDIAN return __swap()( x ); #else #error Undefined __BYTE_ORDER #endif } }; //! Conversion to the Big Endian encoding template struct BigEndian { inline const T operator()(const T& x) const { #if __BYTE_ORDER == __LITTLE_ENDIAN return __swap()( x ); #elif __BYTE_ORDER == __BIG_ENDIAN return x; #endif } }; template struct __swap { inline const T operator()(const T& x) const { return x; } }; template struct __swap { inline const T operator()(const T& x) const { return (T) ((uint16_t)x<<8 | (uint16_t)x>>8); } }; template struct __swap { inline const T operator()(const T& x) const { return (T) ((uint32_t)x<<24 | (uint32_t)x>>24 | ((uint32_t)x & (uint32_t)0x0000ff00UL)<<8 | ((uint32_t)x & (uint32_t)0x00ff0000UL)>>8); } }; template struct __swap { inline const T operator()(const T& x) const { return (T) ((uint64_t)x<<56 | (uint64_t)x>>56 | ((uint64_t)x & (uint64_t)0x000000000000ff00ULL)<<40 | ((uint64_t)x & (uint64_t)0x0000000000ff0000ULL)<<24 | ((uint64_t)x & (uint64_t)0x00000000ff000000ULL)<< 8 | ((uint64_t)x & (uint64_t)0x000000ff00000000ULL)>> 8 | ((uint64_t)x & (uint64_t)0x0000ff0000000000ULL)>>24 | ((uint64_t)x & (uint64_t)0x00ff000000000000ULL)>>40); } }; //! HLA basic type, represented by type of size , encoded in /*! * HLAbasicType * defines a DATATYPE of BYTES size, encoded using ENCODING. * * The buffer is casted to a structure that provide data access operators. The * data can be accessed in an usual way. * * For example: * typedef HLAbasicType HLAinteger32BE; * HLAinteger32BE& value = (HLAinteger32BE&)*buffer; * * value = 42; */ templateclass E> struct HLAbasicType { HLAbasicType& operator = (const T& data) { *(T*)this = E()(data); return *this; } operator T() const { return E()(*(T*)this); } static const size_t __sizeof() { return S; } static const size_t m_octetBoundary = S; static const bool m_isVariable = false; std::ostream& operator << (std::ostream& stream) const { return __print_buffer(stream, (void*)this, __sizeof()); } }; templateclass E> std::ostream& operator << (std::ostream& stream, HLAbasicType& buffer) { return __print_buffer(stream, (void*)&buffer, buffer.__sizeof()); } /* IEEE 1516.2, Table 23: * Basic data representation table */ typedef HLAbasicType HLAinteger16BE; typedef HLAbasicType HLAinteger32BE; typedef HLAbasicType HLAinteger64BE; typedef HLAbasicType HLAfloat32BE; typedef HLAbasicType HLAfloat64BE; typedef HLAbasicType HLAoctetPairBE; typedef HLAbasicType HLAinteger16LE; typedef HLAbasicType HLAinteger32LE; typedef HLAbasicType HLAinteger64LE; typedef HLAbasicType HLAfloat32LE; typedef HLAbasicType HLAfloat64LE; typedef HLAbasicType HLAoctetPairLE; typedef HLAbasicType HLAoctet; enum __HLAboolean { HLAfalse = 0, HLAtrue = 1 }; typedef HLAbasicType<__HLAboolean, 4, BigEndian> HLAboolean; #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif /* Calculate the smallest nonnegative value of P that satisfies the following * formula: (offset+size+P) mod boundary = 0 */ inline size_t __padding(size_t size, size_t boundary) { return boundary - ((size-1)%boundary + 1); } //! Fixed array of elements of type /*! * HLAfixedArray * defines a fixed array of NUMBER elements of type DATATYPE. * * The data can be accessed in an usual way. * * For example: * typedef HLAfixedArray Coordinates; * Coordinates& value = (Coordinates&)*buffer; * * value[0] = 100; * value[1] = 200; */ template struct HLAfixedArray; template std::ostream& operator << (std::ostream& stream, HLAfixedArray& buffer) { return __print_buffer(stream, (void*)&buffer, buffer.__sizeof()); } // Fixed array optimized for fixed-size elements // note: this is the most efficient data type template struct HLAfixedArray { static const size_t size() { return N; } static const size_t offset(int i) { return i*(M::__sizeof() + __padding(M::__sizeof(), M::m_octetBoundary)); } M& operator[](int i) const { return *(M*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. static const size_t __sizeof() { return offset(N-1) + M::__sizeof(); } static const size_t m_octetBoundary = M::m_octetBoundary; static const bool m_isVariable = false; // fixed-size array of fixed-size elements }; // Generic fixed array, supports variable-size elements template struct HLAfixedArray { static const size_t size() { return N; } const size_t offset(int i) const { size_t offs = 0; // count every member, the elements may be variable-sized for(int j=0; j__sizeof(); offs += __padding(offs, M::m_octetBoundary); } return offs; } M& operator[](int i) const { return *(M*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. const size_t __sizeof() const { size_t offs = offset(N-1); return offs + ((M*)((char*)this + offs))->__sizeof(); } static const size_t m_octetBoundary = M::m_octetBoundary; static const bool m_isVariable = true; // variable-sized elements }; //! Variable array of type /*! * HLAvariableArray * defines an array of a variable number of DATATYPE elements. * * The size() member must be set before accessing the data. No data are moved * when the size() is changed. * * For example: * typedef HLAvariableArray List; * List& value = (List&)*buffer; * * value.size() = 2; * value[0] = 100; * value[1] = 200; */ template struct HLAvariableArray; template std::ostream& operator << (std::ostream& stream, HLAvariableArray& buffer) { return __print_buffer(stream, (void*)&buffer, buffer.__sizeof()); } // Variable array optimized for fixed-size elements template struct HLAvariableArray { HLAinteger32BE& size() const { return (HLAinteger32BE&)*this; } static const size_t offset(int i) { return HLAinteger32BE::__sizeof() + __padding(HLAinteger32BE::__sizeof(), M::m_octetBoundary) + i*(M::__sizeof() + __padding(M::__sizeof(), M::m_octetBoundary)); } M& operator[](int i) const { return *(M*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. const size_t __sizeof() const { if(size() > 0) return offset(size()-1) + M::__sizeof(); else return size().__sizeof() + __padding(size().__sizeof(), M::m_octetBoundary); } static const size_t m_octetBoundary = MAX(HLAinteger32BE::m_octetBoundary, M::m_octetBoundary); static const bool m_isVariable = true; // variable-sized array }; // Generic variable array, supports variable-size elements // note: this is the less efficient data type template struct HLAvariableArray { HLAinteger32BE& size() const { return (HLAinteger32BE&)*this; } const size_t offset(int i) const { size_t offs = HLAinteger32BE::__sizeof() + __padding(HLAinteger32BE::__sizeof(), M::m_octetBoundary); // count every member, the elements may be variable-sized for(int j=0; j__sizeof(); offs += __padding(offs, M::m_octetBoundary); } return offs; } M& operator[](int i) const { return *(M*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. const size_t __sizeof() const { if(size() > 0) { size_t offs = offset(size()-1); return offs + ((M*)((char*)this + offs))->__sizeof(); } else return size().__sizeof() + __padding(size().__sizeof(), M::m_octetBoundary); } static const size_t m_octetBoundary = MAX(HLAinteger32BE::m_octetBoundary, M::m_octetBoundary); static const bool m_isVariable = true; // variable-size array of variable-size elements }; //! Fixed record field of type , followed by HLAfixedRecord /*! * HLAfixedRecord ... > TYPENAME; * defines an ordered sequence of DATATYPE entries. * * The data can be accessed using the field() function, where the INDEX * is a zero-based order of the field being accessed. * * For example: * typedef * #define FIELD_X 0 * HLAfixedRecord > > Coordinates; * Coordinates& value = (Coordinates&)*buffer; * * value.field() = 3.14; * value.field() = 6.28; * value.field() = 9.42; */ template struct HLAfixedRecord; template std::ostream& operator << (std::ostream& stream, HLAfixedRecord& buffer) { return __print_buffer(stream, (void*)&buffer, buffer.__sizeof()); } //! Returns th field of the HLAfixedRecord template struct __FieldAt; // Fixed record optimized for fixed-size fields template struct HLAfixedRecord { static const size_t offset(int i, size_t offs = 0) { if(i > 0) { size_t size = M::__sizeof(); size += __padding(offs+size, N::memberBoundary); return N::offset(i-1, offs+size); } else return offs; } static const size_t memberBoundary = M::m_octetBoundary; template typename __FieldAt,i>::Type& field() const { return *(typename __FieldAt,i>::Type*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. static const size_t __sizeof(size_t offs = 0) { size_t size = M::__sizeof(); // if not reached HLAfixedRecordEnd if(N::memberBoundary) { size += __padding(offs+size, N::memberBoundary); return N::__sizeof(offs+size); } else return offs+size; } static const size_t m_octetBoundary = MAX(M::m_octetBoundary, N::m_octetBoundary); static const bool m_isVariable = true; // variable-sized fields }; // Generic fixed record, supports variable-size fields template struct HLAfixedRecord { const size_t offset(int i, size_t offs = 0) const { if(i > 0) { size_t size = ((M*)this)->__sizeof(); size += __padding(offs+size, N::memberBoundary); return ((N*)((char*)this + size))->offset(i-1, offs+size); } else return offs; } static const size_t memberBoundary = M::m_octetBoundary; template typename __FieldAt,i>::Type& field() const { return *(typename __FieldAt,i>::Type*)((char*)this + offset(i)); } // Padding shall not be added after the last element of the array. const size_t __sizeof(size_t offs = 0) const { size_t size = ((M*)this)->__sizeof(); // if not reached HLAfixedRecordEnd if(N::memberBoundary) { size += __padding(offs+size, N::memberBoundary); return ((N*)((char*)this + size))->__sizeof(offs+size); } else return offs+size; } static const size_t m_octetBoundary = MAX(M::m_octetBoundary, N::m_octetBoundary); static const bool m_isVariable = true; // variable-sized fields }; //! Defines a last field in the fixed record struct HLAfixedRecordEnd { static const size_t offset(int i, size_t offs = 0) { return offs; } static const size_t memberBoundary = 0; static const size_t __sizeof(size_t offs = 0) { return offs; } static const size_t m_octetBoundary = 0; static const bool m_isVariable = false; }; template struct __FieldAt,i> { typedef typename __FieldAt::Type Type; }; template struct __FieldAt,0> { typedef M Type; }; // end of file