# HLAvariantRecord.hh

Go to the documentation of this file.

    00001 // ----------------------------------------------------------------------------
    00002 // HLAvariantRecord.hh - IEEE 1516.2 compliant datatypes
    00003 // Copyright (C) 2008  Petr Gotthard <petr.gotthard@centrum.cz>
    00004 //
    00005 // This library is free software; you can redistribute it and/or
    00006 // modify it under the terms of the GNU Lesser General Public
    00007 // License version 2.1, as published by the Free Software Foundation.
    00008 //
    00009 // This library is distributed in the hope that it will be useful,
    00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012 // Lesser General Public License for more details.
    00013 //
    00014 // $Id: HLAvariantRecord.hh,v 1.1 2008/08/02 14:03:15 gotthardp Exp $
    00015 // ----------------------------------------------------------------------------
    00016
    00017 #ifndef _HLATYPES_VARIANTRECORD_HH
    00018 #define _HLATYPES_VARIANTRECORD_HH
    00019
    00020 #include <HLAbuffer.hh>
    00021
    00022 namespace libhla {
    00023
    00024 /* HLAvariantRecord<
    00025  *   INDEX, DATATYPE,
    00026  *   HLAvariantField<ENUMERATORS1, INDEX1, DATATYPE1,
    00027  *   HLAvariantField<ENUMERATORS2, INDEX2, DATATYPE2,
    00028  *   ...
    00029  *   > ... > TYPENAME;
    00030  * defines an ordered sequence of DATATYPE entries.
    00031  *
    00032  * The data can be accessed using the field<INDEX>() function. The INDEX is a logical
    00033  * identifier only.
    00034  * The first field is a discriminant. It is followed by an alternative whose
    00035  * ENUMERATORS match the discriminant value.
    00036  *
    00037  * For example:
    00038  * +-------------+-------------------------------+------------------------------------+------------------+-----------+
    00039  * |             | Discriminant                  | Alternative                        |                  |           |
    00040  * | Record name +------+-----------+------------+---------+--------------+-----------+ Encoding         | Semantics |
    00041  * |             | Name | Type      | Enumerator | Name    | Type         | Semantics |                  |           |
    00042  * +-------------+------+-----------+------------+---------+--------------+-----------+------------------+-----------+
    00043  * |             |      |           | AXIS_X     | FIELD_X | HLAfloat32LE |           |                  |           |
    00044  * | Coordinates | TYPE | TypesEnum +------------+---------+--------------+-----------+ HLAvariantRecord |           |
    00045  * |             |      |           | AXIS_Y     | FIELD_Y | HLAfloat32LE |           |                  |           |
    00046  * +-------------+------+-----------+------------+---------+--------------+-----------+------------------+-----------+
    00047  *
    00048  * namespace __Fields {
    00049  * enum __enum {
    00050  *   TYPE = 0,
    00051  *   FIELD_X = 101,
    00052  *   FIELD_Y = 102
    00053  * };
    00054  * }
    00055  * typedef HLAenumeratedType<__Fields::__enum, HLAinteger32BE> Fields;
    00056  * typedef HLAvariantRecord<
    00057  *   __Fields::TYPE, TypesEnum,
    00058  *   HLAvariantField<HLAsetValue<AXIS_X>, __Fields::FIELD_X, HLAfloat32LE,
    00059  *   HLAvariantField<HLAsetValue<AXIS_Y>, __Fields::FIELD_Y, HLAfloat32LE
    00060  *   > > > Coordinates;
    00061  * HLAdata<Coordinates> value;
    00062  *
    00063  * value->set_discriminant(AXIS_X);
    00064  * value->field<__Fields::FIELD_X>() = 3.14;
    00065  */
    00066
    00068 template<int DE, class DM, class R, bool hasVariable = R::m_isVariable>
    00069 struct HLAvariantRecord;
    00070
    00071 template<int DE, class DM, class R, bool V>
    00072 std::ostream& PrintBuffer(std::ostream& stream, HLAvariantRecord<DE,DM,R,V>& buffer)
    00073 { return __print_buffer(stream, (void*)&buffer, buffer.__sizeof()); }
    00074
    00076 template<class R, int i> struct __FieldAt;
    00077
    00079 template<int DE, class DM, class R, int e>
    00080 struct __DiscriminantOrFieldAt;
    00081
    00082 // Variant record optimized for fixed-size fields
    00083 template<int DE, class DM, class R>
    00084 struct HLAvariantRecord<DE, DM, R, false>
    00085 {
    00087     /* This function assumes no data are stored in the buffer after this array.
    00088      * You may want to use set_discriminant() instead.
    00089      */
    00090     DM& discriminant() const
    00091     { return *(DM*)this; }
    00092
    00094     void set_discriminant(int d)
    00095     {
    00096         if (d == (int)discriminant())
    00097             return; // no change
    00098
    00099         // as changing the discriminant may impact padding, the whole buffer needs to be reorganized
    00100         __HLAbuffer::shake(this, d, (long)R::field_emptysizeof(d));
    00101     }
    00102
    00103     template <int e>
    00104     typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type& field() const
    00105     {
    00106         // return the discriminant
    00107         if (e == DE)
    00108             return *(typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type*)this;
    00109
    00110         if (e != R::get_field(discriminant()))
    00111             throw std::out_of_range("HLAvariantRecord: wrong discriminant");
    00112         // return one of the alternatives
    00113         return *(typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type*)((char*)this + emptysizeof());
    00114     }
    00115
    00116     static const size_t emptysizeof()
    00117     { return DM::__sizeof() + __padding(DM::__sizeof(), R::m_octetBoundary); }
    00118
    00119     const size_t __sizeof() const
    00120     {
    00121         if (R::has_field(discriminant()))
    00122             return emptysizeof() + R::field_sizeof(discriminant());
    00123         else
    00124             return emptysizeof();
    00125     }
    00126
    00127     void copy(void* source)
    00128     {
    00129         __HLAbuffer& buffer = __HLAbuffer::__buffer(this);
    00130         if(source == buffer.mShakeThat) {
    00131             *(DM*)this = buffer.mShakeValue;
    00132             // switching variant: content is removed
    00133         }
    00134         else {
    00135             int d = *(DM*)source;
    00136             // not switching variant: copy the content
    00137             *(DM*)this = d;
    00138             ((R*)this)->copy(d, (char*)source + emptysizeof());
    00139         }
    00140     }
    00141
    00142     static const size_t m_octetBoundary = MAX(DM::m_octetBoundary, R::m_octetBoundary);
    00143     static const bool m_isVariable = true; // variant record of fixed-size fields
    00144 };
    00145
    00146 // Generic variant record, supports variable-size fields
    00147 template<int DE, class DM, class R>
    00148 struct HLAvariantRecord<DE, DM, R, true>
    00149 {
    00151     /* This function assumes no data are stored in the buffer after this array.
    00152      * You may want to use set_discriminant() instead.
    00153      */
    00154     DM& discriminant() const
    00155     { return *(DM*)this; }
    00156
    00158     void set_discriminant(int d)
    00159     {
    00160         if (d == (int)discriminant())
    00161             return; // no change
    00162
    00163         // as changing the discriminant may impact padding, the whole buffer needs to be reorganized
    00164         __HLAbuffer::shake(this, d, (long)R::field_emptysizeof(d));
    00165     }
    00166
    00167     template <int e>
    00168     typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type& field() const
    00169     {
    00170         // return the discriminant
    00171         if (e == DE)
    00172             return *(typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type*)this;
    00173
    00174         if (e != R::get_field(discriminant()))
    00175             throw std::out_of_range("HLAvariantRecord: wrong discriminant");
    00176         // return one of the alternatives
    00177         return *(typename __DiscriminantOrFieldAt<DE,DM,R,e>::Type*)((char*)this + emptysizeof());
    00178     }
    00179
    00180     static const size_t emptysizeof()
    00181     { return DM::__sizeof() + __padding(DM::__sizeof(), R::m_octetBoundary); }
    00182
    00183     const size_t __sizeof() const
    00184     {
    00185         if (R::has_field(discriminant()))
    00186             return emptysizeof() + ((R*)((char*)this + emptysizeof()))->field_sizeof(discriminant());
    00187         else
    00188             return emptysizeof();
    00189     }
    00190
    00191     void copy(void* source)
    00192     {
    00193         __HLAbuffer& buffer = __HLAbuffer::__buffer(this);
    00194         if(source == buffer.mShakeThat) {
    00195             *(DM*)this = buffer.mShakeValue;
    00196             // switching variant: content is removed
    00197         }
    00198         else {
    00199             int d = *(DM*)source;
    00200             // not switching variant: copy the content
    00201             *(DM*)this = d;
    00202             ((R*)this)->copy(d, (char*)source + emptysizeof());
    00203         }
    00204     }
    00205
    00206     static const size_t m_octetBoundary = MAX(DM::m_octetBoundary, R::m_octetBoundary);
    00207     static const bool m_isVariable = true; // variant record of variable-sized fields
    00208 };
    00209
    00210 struct HLAsetEnd;
    00211
    00213 template<int e, class N = HLAsetEnd>
    00214 struct HLAsetValue
    00215 {
    00216     static int includes(int i)
    00217     {
    00218         if (i == e)
    00219             return 1;
    00220         else
    00221             return N::includes(i);
    00222     }
    00223 };
    00224
    00226 template<int e1, int e2, class N = HLAsetEnd>
    00227 struct HLAsetRange
    00228 {
    00229     static int includes(int i)
    00230     {
    00231         if (e1 <= i && i <= e2)
    00232             return 1;
    00233         else
    00234             return N::includes(i);
    00235     }
    00236 };
    00237
    00239 template<class N = HLAsetEnd>
    00240 struct HLAsetOther
    00241 {
    00242     static int includes(int i)
    00243     { return 1; }
    00244 };
    00245
    00247 struct HLAsetEnd
    00248 {
    00249     static int includes(int i)
    00250     { return 0; }
    00251 };
    00252
    00253 struct HLAvariantEnd;
    00254
    00256 // note: <E> must be "int" to enable implicit conversion from/to enum types
    00257 template<class D, int E, class M, class N = HLAvariantEnd, bool hasVariable = M::m_isVariable || N::m_isVariable>
    00258 struct HLAvariantField;
    00259
    00260 // List of fixed-size fields
    00261 template<class D, int E, class M, class N>
    00262 struct HLAvariantField<D, E, M, N, false>
    00263 {
    00264     static bool has_field(int d)
    00265     {
    00266         if (D::includes(d))
    00267           return true; // found
    00268         else
    00269           return N::has_field(d); // continue searching
    00270     }
    00271
    00272     static int get_field(int d)
    00273     {
    00274         if (D::includes(d))
    00275             return E;
    00276         else
    00277             return N::get_field(d);
    00278     }
    00279
    00280     static const size_t field_emptysizeof(int e)
    00281     {
    00282         if (e == E)
    00283             return M::emptysizeof();
    00284         else
    00285             return N::field_emptysizeof(e);
    00286     }
    00287
    00288     static const size_t field_sizeof(int e)
    00289     {
    00290         if (e == E)
    00291             return M::__sizeof();
    00292         else
    00293             return N::field_sizeof(e);
    00294     }
    00295
    00296     void copy(int e, void* source)
    00297     {
    00298         if (e == E)
    00299             return ((M*)this)->copy(source);
    00300         else
    00301             return ((N*)this)->copy(e, source);
    00302     }
    00303
    00304     static const size_t m_octetBoundary = MAX(M::m_octetBoundary, N::m_octetBoundary);
    00305     static const bool m_isVariable = false; // fixed-sized fields
    00306 };
    00307
    00308 // List containg variable-size fields
    00309 template<class D, int E, class M, class N>
    00310 struct HLAvariantField<D, E, M, N, true>
    00311 {
    00312     static bool has_field(int d)
    00313     {
    00314         if (D::includes(d))
    00315           return true; // found
    00316         else
    00317           return N::has_field(d); // continue searching
    00318     }
    00319
    00320     static int get_field(int d)
    00321     {
    00322         if (D::includes(d))
    00323             return E;
    00324         else
    00325             return N::get_field(d);
    00326     }
    00327
    00328     static const size_t field_emptysizeof(int e)
    00329     {
    00330         if (e == E)
    00331             return M::emptysizeof();
    00332         else
    00333             return N::field_emptysizeof(e);
    00334     }
    00335
    00336     const size_t field_sizeof(int e) const
    00337     {
    00338         if (e == E)
    00339             return ((M*)this)->__sizeof();
    00340         else
    00341             return ((N*)this)->field_sizeof(e);
    00342     }
    00343
    00344     void copy(int e, void* source)
    00345     {
    00346         if (e == E)
    00347             return ((M*)this)->copy(source);
    00348         else
    00349             return ((N*)this)->copy(e, source);
    00350     }
    00351
    00352     static const size_t m_octetBoundary = MAX(M::m_octetBoundary, N::m_octetBoundary);
    00353     static const bool m_isVariable = true; // variable-sized fields
    00354 };
    00355
    00357 struct HLAvariantEnd
    00358 {
    00359     static bool has_field(int d)
    00360     { return false; }
    00361     static int get_field(int d)
    00362     { throw std::out_of_range("HLAvariantRecord: unknown discriminant"); }
    00363     static const size_t field_emptysizeof(int e)
    00364     { return 0; }
    00365     static const size_t field_sizeof(int e)
    00366     { return 0; }
    00367     void copy(int e, void* source)
    00368     { /* nop */ }
    00369
    00370     static const size_t m_octetBoundary = 0;
    00371     static const bool m_isVariable = false;
    00372 };
    00373
    00374 template<bool C, class Then, class Else>
    00375 struct __variantRecord_if
    00376 { typedef Then X; };
    00377
    00378 template<class Then, class Else>
    00379 struct __variantRecord_if<false, Then, Else>
    00380 { typedef Else X; };
    00381
    00382 template<int DE, class DM, class R, int e>
    00383 struct __DiscriminantOrFieldAt
    00384 { typedef typename __variantRecord_if<e==DE, DM, typename __FieldAt<R,e>::Type>::X Type; };
    00385
    00386 template<class D, int E, class M, class N, bool V, int e>
    00387 struct __FieldAt<HLAvariantField<D,E,M,N,V>, e>
    00388 { typedef typename __variantRecord_if<e==E, M, typename __FieldAt<N,e>::Type>::X Type; };
    00389
    00390 // returned when no HLAvariantField has a given index(i)
    00391 template<int e>
    00392 struct __FieldAt<HLAvariantEnd, e>
    00393 { typedef HLAvariantEnd Type; };
    00394
    00395 } // namespace libhla
    00396
    00397 #endif // _HLATYPES_VARIANTRECORD_HH
    00398
    00399 // $Id: HLAvariantRecord.hh,v 1.1 2008/08/02 14:03:15 gotthardp Exp $
    00400