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 

Generated on Thu Apr 30 15:53:49 2009 for CERTIDeveloperDocumentation by doxygen 1.5.5