From: g0dil Date: Mon, 22 Oct 2007 23:26:11 +0000 (+0000) Subject: Packets: Add container helper macros X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=9f6bb706cb491d4da38f6472746b3076a66202e0;p=senf.git Packets: Add container helper macros Packets: Move example policies into .dox files Packets: Implement variant parser git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@473 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/MPEGDVBBundle/SConscript b/Packets/MPEGDVBBundle/SConscript index 8155acd..8529e7b 100644 --- a/Packets/MPEGDVBBundle/SConscript +++ b/Packets/MPEGDVBBundle/SConscript @@ -15,5 +15,5 @@ SENFSCons.Lib(env, library = 'Packets_MPEGDVBBundle', sources = sources[0], LIBS = ['Packets', 'Socket', 'Utils'], no_includes = 1) SENFSCons.Doxygen(env, extra_sources = [ - env.Dia2Png("TLV.dia", DIA2PNGMAXWIDTH = 600) + env.Dia2Png("TLV.dia") ]) diff --git a/Packets/MPEGDVBBundle/TLV.dia b/Packets/MPEGDVBBundle/TLV.dia index d3bdc7c..77dc6eb 100644 Binary files a/Packets/MPEGDVBBundle/TLV.dia and b/Packets/MPEGDVBBundle/TLV.dia differ diff --git a/Packets/ParseArray.hh b/Packets/ParseArray.hh index a42f406..b7e40bd 100644 --- a/Packets/ParseArray.hh +++ b/Packets/ParseArray.hh @@ -95,6 +95,21 @@ namespace senf { value_type operator[](difference_type i) const; }; + /** \brief Define array field + + This macro is a special helper to define a senf::Parse_Array type field, a fixed size + collection of fixed size elements. + + \param[in] name field name + \param[in] elt_type array element type + \param[in] size constant number of elements + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_ARRAY(name, elt_type, size) \ + typedef senf::Parse_Array BOOST_PP_CAT(name, _array_t); \ + SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _array_t) ) + } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Packets/ParseHelpers.hh b/Packets/ParseHelpers.hh index bc22591..6561dbf 100644 --- a/Packets/ParseHelpers.hh +++ b/Packets/ParseHelpers.hh @@ -214,6 +214,9 @@ See the documentation of each of these macros for a detailed description of the macro arguments and usage. Bit-fields are handled in the following section. + There also some supplementary macros for defining fields of more complex composite types + (e.g. vectors). See the list of 'Defines' further down this page. + \subsection parsermacrosbitfields Bit-fields \par "" @@ -580,6 +583,8 @@ This command will skip the given number of bits within a bitfield group. This command does \e only affect bitfield commands. Therefore, a SENF_PARSER_SKIP_BITS command which is not followed by a bitfield command will be ignored. + + \hideinitializer */ #define SENF_PARSER_SKIP_BITS(bits) @@ -595,6 +600,7 @@ group covers multiple bytes before the bit field \a name. \param[in] name field or label to jump to + \hideinitializer */ #define SENF_PARSER_GOTO(name) @@ -612,6 +618,7 @@ \param[in] offset Depending on the parser type, either single \a bytes value or two arguments \a bytes and \a init_size. + \hideinitializer */ #define SENF_PARSER_GOTO_OFFSET(offset) @@ -626,6 +633,7 @@ labeled with \ref SENF_PARSER_LABEL() \param[in] name label name + \hideinitializer */ #define SENF_PARSER_LABEL(name) @@ -635,9 +643,29 @@ while defining the parser, normally while defining inline functions. This macro will return the correct value when defining fixed or dynamically sized parsers. + + \param[in] name field or label name + \returns offset of the field from parsers start + \hideinitializer */ #define SENF_PARSER_OFFSET(name) +/** \brief Get fixed field offset, if possible + + This macro will return the fixed offset to the field \a name, a compile-time constant + expression. This is identical to \ref SENF_PARSER_OFFSET() when defining a fixed size parser. + + Even in dynamically sized parsers this macro will work, if the field \a name is preceded by + fixed size fields only. This macro does \e not validate this condition, it will return an + arbitrary incorrect value otherwise. + + \pre Field \a name preceded by fixed size fields only + \param[in] field or label name + \returns compile-time constant offset of the field from parsers start + \hideinitializer + */ +#define SENF_PARSER_FIXED_OFFSET(name) + ///@} #else @@ -662,6 +690,8 @@ #define SENF_PARSER_LABEL BOOST_PP_CAT(SENF_PARSER_LABEL_, SENF_PARSER_TYPE) #define SENF_PARSER_OFFSET BOOST_PP_CAT(SENF_PARSER_OFFSET_, SENF_PARSER_TYPE) +#define SENF_PARSER_FIXED_OFFSET BOOST_PP_CAT(SENF_PARSER_FIXED_OFFSET_,SENF_PARSER_TYPE) +#define SENF_PARSER_CURRENT_FIXED_OFFSET BOOST_PP_CAT(SENF_PARSER_CURRENT_FIXED_OFFSET_, SENF_PARSER_TYPE) #define SENF_PARSER_FINALIZE BOOST_PP_CAT(SENF_PARSER_FINALIZE_, SENF_PARSER_TYPE) diff --git a/Packets/ParseHelpers.ih b/Packets/ParseHelpers.ih index aca1f14..b55c9a4 100644 --- a/Packets/ParseHelpers.ih +++ b/Packets/ParseHelpers.ih @@ -368,6 +368,18 @@ # define SENF_PARSER_OFFSET_var(name) BOOST_PP_CAT(name, _offset)() # # /////////////////////////////////////////////////////////////////////////// +# // SENF_PARSER_FIXED_OFFSET_* +# +# define SENF_PARSER_FIXED_OFFSET_fix(name) BOOST_PP_CAT(name, _offset) +# define SENF_PARSER_FIXED_OFFSET_var(name) BOOST_PP_CAT(name, _init_bytes) +# +# /////////////////////////////////////////////////////////////////////////// +# // SENF_PARSER_FIXED_OFFSET_* +# +# define SENF_PARSER_CURRENT_FIXED_OFFSET_fix() SENF_MPL_SLOT_GET(offset) +# define SENF_PARSER_CURRENT_FIXED_OFFSET_var() SENF_MPL_SLOT_GET(init_bytes) +# +# /////////////////////////////////////////////////////////////////////////// # // SENF_PARSER_FINALIZE_* # # define SENF_PARSER_FINALIZE_var(name) \ diff --git a/Packets/ParseList.dox b/Packets/ParseList.dox new file mode 100644 index 0000000..3cad044 --- /dev/null +++ b/Packets/ParseList.dox @@ -0,0 +1,192 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +namespace senf { + + /** \brief Example of a list policy. ONLY FOR EXPOSITION. + + This class shows the interface which must be implemented by a list policy. It is not a list + policy only a declaration of the interface: + \code + struct ExampleListPolicy + { + // optional typedefs used to simplify all other declarations + typedef PacketParserBase::data_iterator data_iterator; + typedef PacketParserBase::state_type state_type; + typedef PacketParserBase::size_type size_type; + + // mandatory typedefs in the parser and container policy + typedef ElementParser element_type; + typedef Parse_List< ExampleListPolicy > parser_type; + typedef Parse_List_Container< ExampleListPolicy > container_type; + + // mandatory constant in parser and container policy + static const size_type init_bytes = 0; + + // Members needed in the parser and the container policy + size_type bytes (data_iterator i, state_type s) const; + size_type size (data_iterator i, state_type s) const; + void init (data_iterator i, state_type s) const; + + // Members needed only in the container policy + void erase (data_iterator i, state_type s, iterator p) const; + void insert (data_iterator i, state_type s, iterator p) const; + + struct iterator_policy + { + iterator setBegin (data_iterator i, state_type s); + iterator setEnd (data_iterator i, state_type s); + void setFromPosition (data_iterator i, state_type s, iterator p); + iterator next (data_iterator i, state_type s); + iterator raw (data_iterator i, state_type s) const; + }; + }; + \endcode + + The list policy must be either default constructible or copy constructible. The policy may + contain arbitrary additional data members. However, their number and size should be kept at + an absolute minimum, since they will increase the size of the list parser. + + If necessary, you may use a different policy in the container_type. The ListPolicy must + define the elements bytes(), size() and init(), the container policy needs all these and + additionally needs erase() and insert(). The container policy will also need the + element_type, parser_type and container_type typedefs. + + \see \ref Parse_List + */ + struct ExampleListPolicy + { + typedef PacketParserBase::data_iterator iterator; + typedef PacketParserBase::state_type state_type; + typedef PacketParserBase::size_type size_type; + + typedef void element_type; ///< Type of list elements + /**< This is the parser used to parse the list elements. */ + typedef void parser_type; ///< List parser type + /**< parser_type is the list parser used to parse a list of + this type, + e.g. senf::Parse_List. */ + typedef void container_type; ///< Type of container wrapper + /**< This is the container wrapper of the list, e.g. + Parse_List_Container. The + container may however use a \e different policy, as + long as that policy is constructible from the parser + policy. */ + + static const size_type init_bytes = 0; ///< Size of a new list of this type + /**< Initial size which needs to be allocated to this type + of list */ + + size_type bytes(iterator i, state_type s) const; ///< Size of list in bytes + /**< Return the complete size of the list in + bytes. Depending on the type of list, this call may + need to completely traverse the list ... */ + + size_type size(iterator i, state_type s) const; ///< Number of elements in list + /**< Return the number of elements in the list. This + operation may be quite inefficient for some lists (the + list must be traversed to find that number. */ + + void init(iterator i, state_type s) const; ///< Initialize new list + /**< Called after init_size bytes have been allocated to + initialize the list. After init() is called, the list + is traversed to initialize any members (probably + none) */ + + void erase(iterator i, state_type s, iterator p) const; ///< Erase element from list + /**< Delete the list element at p from the List (i,s). When + this operation is called, the element is still part of + the list. This call must update the meta-data as + needed. The data will be removed after this call + returns. */ + + void insert(iterator i, state_type s, iterator p) const; ///< Insert element into list + /**< This is called after an element has been inserted at p + into the List (i,s) to update the meta-data. */ + + /** \brief Example of a list iterator policy. ONLY FOR EXPOSITION. + + \see \ref ExampleListPolicy \n + \ref Parse_List + */ + struct iterator_policy + { + iterator setBegin(iterator i, state_type s); ///< Initialize iterator to begin() + /**< Initialize the policy from the given List (i,s). Set + the iterator to the beginning iterator. Return + data_iterator to the first element. + + \warning if the list is empty, the returned iterator + \e must be the same as the one returned by setEnd. */ + + iterator setEnd(iterator i, state_type s); ///< Initialize iterator to end() + /**< Initialize the policy from the given List (i,s). Set + the iterator to the end iterator. Return data_iterator + used to mark the end of the range. This may be a + special sentinel value (e.g. data().end()) if + needed. */ + + void setFromPosition(iterator i, state_type s, iterator p); + ///< Initialize iterator from the given raw position + /**< Set the iterator to the Element at raw position p. This + operation can potentially be very inefficient if the + list needs to be traversed from the beginning until the + iterator is found. */ + + iterator next(iterator i, state_type s); ///< Advance to next element + /**< given an iterator to an element, go to the next + element. */ + + iterator raw(iterator i, state_type s); ///< Return raw position of element + /**< Given the iterator state (i,s), return the raw iterator + to the datum. This will be i in almost all cases EXCEPT + if a special sentinel value is used as end() value. In + this case, this member must return the real position + after the last element. */ + }; + + /** \brief Example of a list container policy. ONLY FOR EXPOSITION + + \see \ref ExampleListPolicy \n + \ref Parse_List + */ + struct container_policy + { + void init(iterator i, state_type s); ///< Initialize new container + void update(iterator i, state_type s); ///< Called before every container access + }; + }; + +} + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// mode: flyspell +// mode: auto-fill +// End: diff --git a/Packets/ParseList.hh b/Packets/ParseList.hh index dc757bf..8eb9592 100644 --- a/Packets/ParseList.hh +++ b/Packets/ParseList.hh @@ -103,156 +103,6 @@ namespace senf { template friend class Parse_List_Container; }; - /** \brief Example of a list policy. ONLY FOR EXPOSITION. - - This class shows the interface which must be implemented by a list policy. It is not a list - policy only a declaration of the interface: - \code - struct ExampleListPolicy - { - // optional typedefs used to simplify all other declarations - typedef PacketParserBase::data_iterator data_iterator; - typedef PacketParserBase::state_type state_type; - typedef PacketParserBase::size_type size_type; - - // mandatory typedefs in the parser and container policy - typedef ElementParser element_type; - typedef Parse_List< ExampleListPolicy > parser_type; - typedef Parse_List_Container< ExampleListPolicy > container_type; - - // mandatory constant in parser and container policy - static const size_type init_bytes = 0; - - // Members needed in the parser and the container policy - size_type bytes (data_iterator i, state_type s) const; - size_type size (data_iterator i, state_type s) const; - void init (data_iterator i, state_type s) const; - - // Members needed only in the container policy - void erase (data_iterator i, state_type s, iterator p) const; - void insert (data_iterator i, state_type s, iterator p) const; - - struct iterator_policy - { - iterator setBegin (data_iterator i, state_type s); - iterator setEnd (data_iterator i, state_type s); - void setFromPosition (data_iterator i, state_type s, iterator p); - iterator next (data_iterator i, state_type s); - iterator raw (data_iterator i, state_type s) const; - }; - }; - \endcode - - If necessary, you may use a different policy in the container_type. The ListPolicy must - define the elements bytes(), size() and init(), the container policy needs all these and - additionally needs erase() and insert(). The container policy will also need the - element_type, parser_type and container_type typedefs. - - \see \ref Parse_List - */ - struct ExampleListPolicy - { - typedef PacketParserBase::data_iterator iterator; - typedef PacketParserBase::state_type state_type; - typedef PacketParserBase::size_type size_type; - - typedef void element_type; ///< Type of list elements - /**< This is the parser used to parse the list elements. */ - typedef void parser_type; ///< List parser type - /**< parser_type is the list parser used to parse a list of - this type, - e.g. senf::Parse_List. */ - typedef void container_type; ///< Type of container wrapper - /**< This is the container wrapper of the list, e.g. - Parse_List_Container. The - container may however use a \e different policy, as - long as that policy is constructible from the parser - policy. */ - - static const size_type init_bytes = 0; ///< Size of a new list of this type - /**< Initial size which needs to be allocated to this type - of list */ - - size_type bytes(iterator i, state_type s) const; ///< Size of list in bytes - /**< Return the complete size of the list in - bytes. Depending on the type of list, this call may - need to completely traverse the list ... */ - - size_type size(iterator i, state_type s) const; ///< Number of elements in list - /**< Return the number of elements in the list. This - operation may be quite inefficient for some lists (the - list must be traversed to find that number. */ - - void init(iterator i, state_type s) const; ///< Initialize new list - /**< Called after init_size bytes have been allocated to - initialize the list. After init() is called, the list - is traversed to initialize any members (probably - none) */ - - void erase(iterator i, state_type s, iterator p) const; ///< Erase element from list - /**< Delete the list element at p from the List (i,s). When - this operation is called, the element is still part of - the list. This call must update the meta-data as - needed. The data will be removed after this call - returns. */ - - void insert(iterator i, state_type s, iterator p) const; ///< Insert element into list - /**< This is called after an element has been inserted at p - into the List (i,s) to update the meta-data. */ - - /** \brief Example of a list iterator policy. ONLY FOR EXPOSITION. - - \see \ref ExampleListPolicy \n - \ref Parse_List - */ - struct iterator_policy - { - iterator setBegin(iterator i, state_type s); ///< Initialize iterator to begin() - /**< Initialize the policy from the given List (i,s). Set - the iterator to the beginning iterator. Return - data_iterator to the first element. - - \warning if the list is empty, the returned iterator - \e must be the same as the one returned by setEnd. */ - - iterator setEnd(iterator i, state_type s); ///< Initialize iterator to end() - /**< Initialize the policy from the given List (i,s). Set - the iterator to the end iterator. Return data_iterator - used to mark the end of the range. This may be a - special sentinel value (e.g. data().end()) if - needed. */ - - void setFromPosition(iterator i, state_type s, iterator p); - ///< Initialize iterator from the given raw position - /**< Set the iterator to the Element at raw position p. This - operation can potentially be very inefficient if the - list needs to be traversed from the beginning until the - iterator is found. */ - - iterator next(iterator i, state_type s); ///< Advance to next element - /**< given an iterator to an element, go to the next - element. */ - - iterator raw(iterator i, state_type s); ///< Return raw position of element - /**< Given the iterator state (i,s), return the raw iterator - to the datum. This will be i in almost all cases EXCEPT - if a special sentinel value is used as end() value. In - this case, this member must return the real position - after the last element. */ - }; - - /** \brief Example of a list container policy. ONLY FOR EXPOSITION - - \see \ref ExampleListPolicy \n - \ref Parse_List - */ - struct container_policy - { - void init(iterator i, state_type s); ///< Initialize new container - void update(iterator i, state_type s); ///< Called before every container access - }; - }; - /** \brief Parse_List container wrapper This is the container wrapper used for list parsers. The container wrapper will stay valid diff --git a/Packets/ParseListB.hh b/Packets/ParseListB.hh index 5fa118c..c8ee210 100644 --- a/Packets/ParseListB.hh +++ b/Packets/ParseListB.hh @@ -65,6 +65,23 @@ namespace senf { typedef Parse_List< detail::Parse_ListB_Policy > parser; }; + /** \brief Define Parse_ListB field + + This macro is a special helper to define a senf::Parse_ListB type field, a list of elements + of type \a elt_type (a parser type) directly preceded by a numeric size field of type \a + size_type (another parser type) giving the total number of bytes of the list (not the + element count). + + \param[in] name field name + \param[in] elt_type list element type + \param[in] size_type size type + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_LIST_B(name, elt_type, size_type) \ + typedef senf::Parse_ListB::parser BOOST_PP_CAT(name, _list_t); \ + SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _list_t) ) + } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Packets/ParseListN.hh b/Packets/ParseListN.hh index 28524bc..18c5f4b 100644 --- a/Packets/ParseListN.hh +++ b/Packets/ParseListN.hh @@ -55,6 +55,22 @@ namespace senf { typedef Parse_List< detail::Parse_ListN_Policy > parser; }; + /** \brief Define Parse_ListN field + + This macro is a special helper to define a senf::Parse_ListN type field, a list of elements + of type \a elt_type (a parser type) directly preceded by a numeric size field of type \a + size_type (another parser type). + + \param[in] name field name + \param[in] elt_type list element type + \param[in] size_type size type + \hideinitializer + \ingroup packetparsermacros + */ +# define SENF_PARSER_LIST_N(name, elt_type, size_type) \ + typedef senf::Parse_ListN::parser BOOST_PP_CAT(name, _list_t); \ + SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _list_t) ) + } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Packets/ParseVariant.ct b/Packets/ParseVariant.ct new file mode 100644 index 0000000..d147776 --- /dev/null +++ b/Packets/ParseVariant.ct @@ -0,0 +1,71 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ParseVariant non-inline template implementation */ + +#include "ParseVariant.ih" + +// Custom includes +#include + +#define prefix_ +///////////////////////////////ct.p//////////////////////////////////////// + +template +template +prefix_ void senf::Parse_Variant::init() +{ + unsigned oldSize( bytes() ); + typedef typename boost::mpl::at >::type NewParser; + + if (oldSize < senf::init_bytes::value) { + data_iterator j (i()); + std::advance(j, oldSize); + std::fill(i(), j, 0u); + safe_data_iterator safe_i (*this); + data().insert(j, senf::init_bytes::value - oldSize, 0u); + VariantPolicy::variant(N, safe_i, state()); + NewParser( VariantPolicy::begin(safe_i, state()), state() ).init(); + } else { + data_iterator j (i()); + std::advance(j, senf::init_bytes::value); + data().erase(j, boost::next(i(), oldSize)); + std::fill(i(), j, 0u); + VariantPolicy::variant(N, i(), state()); + NewParser(VariantPolicy::begin(i(), state()), state()).init(); + } +} + +///////////////////////////////ct.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Packets/ParseVariant.cti b/Packets/ParseVariant.cti new file mode 100644 index 0000000..f3ca98e --- /dev/null +++ b/Packets/ParseVariant.cti @@ -0,0 +1,118 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ParseVariant inline template implementation */ + +#include "ParseVariant.ih" + +// Custom includes +#include + +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::Parse_Variant + +template +prefix_ senf::Parse_Variant:: +Parse_Variant(data_iterator i, state_type s) + : PacketParserBase(i,s) +{} + +template +prefix_ senf::Parse_Variant:: +Parse_Variant(VariantPolicy policy, data_iterator i, state_type s) + : PacketParserBase(i,s), VariantPolicy(policy) +{} + +template +prefix_ senf::PacketParserBase::size_type +senf::Parse_Variant::bytes() + const +{ + return detail::VariantBytes< Parse_Variant, boost::mpl::size::value - 1 > + ::bytes(*this, variant()) + VariantPolicy::bytes(i(),state()); +} + +template +prefix_ void +senf::Parse_Variant::init() +{ + VariantPolicy::variant(0,i(),state()); + get<0>().init(); +} + +template +prefix_ unsigned senf::Parse_Variant::variant() + const +{ + return VariantPolicy::variant(i(),state()); +} + +template +template +prefix_ typename boost::mpl::at< + typename senf::Parse_Variant::parsers, + boost::mpl::int_ >::type +senf::Parse_Variant::get() + const +{ + BOOST_ASSERT( variant() == N ); + return typename boost::mpl::at >::type( + VariantPolicy::begin(i(), state()), state() ); +} + +///////////////////////////////////////////////////////////////////////// +// senf::detail::VariantBytes + +template +prefix_ senf::PacketParserBase::size_type +senf::detail::VariantBytes::bytes(Variant const & v, unsigned n) +{ + if (n == N) + return senf::bytes(v.template get()); + else + return VariantBytes::bytes(v, n); +} + +template +prefix_ senf::PacketParserBase::size_type +senf::detail::VariantBytes::bytes(Variant const & v, unsigned n) +{ + return senf::bytes(v.template get<0>()); +} + +///////////////////////////////cti.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Packets/ParseVariant.dox b/Packets/ParseVariant.dox new file mode 100644 index 0000000..d9153e5 --- /dev/null +++ b/Packets/ParseVariant.dox @@ -0,0 +1,53 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +namespace senf { + + struct ExampleVariantPolicy + { + // optional typedefs used to simplify all other declarations + typedef PacketParserBase::data_iterator data_iterator; + typedef PacketParserBase::state_type state_type; + typedef PacketParserBase::size_type size_type; + + static size_type const init_bytes = 0; + size_type bytes (data_iterator i, state_type s) const; + data_iterator begin(data_iterator i, state_type s) const; + + unsigned variant (data_iterator i, state_type s) const; + void variant (unsigned v, data_iterator i, state_type s); + }; + +} + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// mode: flyspell +// mode: auto-fill +// End: diff --git a/Packets/ParseVariant.hh b/Packets/ParseVariant.hh new file mode 100644 index 0000000..84564a4 --- /dev/null +++ b/Packets/ParseVariant.hh @@ -0,0 +1,132 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ParseVariant public header */ + +#ifndef HH_ParseVariant_ +#define HH_ParseVariant_ 1 + +#ifndef HH_Packets_ +#error "Don't include 'ParseVariant.hh' directly, include 'Packets.hh'" +#endif + +// Custom includes +#include +#include +#include +#include +#include +#include "PacketParser.hh" + +//#include "ParseVariant.mpp" +#include "ParseVariant.ih" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { + +# ifndef SENF_LIMIT_PARSER_VARIANT +# define SENF_LIMIT_PARSE_VARIANT 10 +# endif + +# define SENF_PARSE_VARIANT_TPL_ARGS_DFL(n) \ + BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( SENF_LIMIT_PARSE_VARIANT, \ + n, \ + boost::mpl::na ) + +# define SENF_PARSE_VARIANT_TPL_ARGS(n) BOOST_PP_ENUM_PARAMS( SENF_LIMIT_PARSE_VARIANT, n ) + + template + class Parse_Variant + : public PacketParserBase, private VariantPolicy + { + typedef boost::mpl::vector< SENF_PARSE_VARIANT_TPL_ARGS(P) > parsers; + + public: + Parse_Variant(data_iterator i, state_type s); + Parse_Variant(VariantPolicy policy, data_iterator i, state_type s); + + size_type bytes() const; + void init(); + + static const size_type init_bytes = + senf::init_bytes::value + VariantPolicy::init_bytes; + + /////////////////////////////////////////////////////////////////////////// + + unsigned variant() const; + + template + typename boost::mpl::at< parsers, boost::mpl::int_ >::type get() const; + + template + void init(); + + private: + }; + + template + struct Parse_Variant_Direct + { + typedef Parse_Variant< detail::Parse_Variant_Direct, + SENF_PARSE_VARIANT_TPL_ARGS(P) > parser; + }; + +# define SENF_PARSER_VARIANT_(r, data, elem) ,elem + +# define SENF_PARSER_VARIANT(name, chooser, types) \ + typedef senf::Parse_Variant_Direct< \ + BOOST_PP_CAT(chooser, _t), \ + SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser) \ + BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types ) \ + >::parser BOOST_PP_CAT(name, _variant_t); \ + SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _variant_t) ) + +# define SENF_PARSER_PRIVATE_VARIANT(name, chooser, types) \ + typedef senf::Parse_Variant_Direct< \ + BOOST_PP_CAT(chooser, _t), \ + SENF_PARSER_CURRENT_FIXED_OFFSET() - SENF_PARSER_FIXED_OFFSET(chooser) \ + BOOST_PP_SEQ_FOR_EACH( SENF_PARSER_VARIANT_, _, types ) \ + >::parser BOOST_PP_CAT(name, _variant_t); \ + SENF_PARSER_PRIVATE_FIELD( name, BOOST_PP_CAT(name, _variant_t) ) + +} + +///////////////////////////////hh.e//////////////////////////////////////// +#endif +#if !defined(HH_Packets__decls_) && !defined(HH_ParseVariant_i_) +#define HH_ParseVariant_i_ +//#include "ParseVariant.cci" +#include "ParseVariant.ct" +#include "ParseVariant.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Packets/ParseVariant.ih b/Packets/ParseVariant.ih new file mode 100644 index 0000000..c022af5 --- /dev/null +++ b/Packets/ParseVariant.ih @@ -0,0 +1,85 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ParseVariant internal header */ + +#ifndef IH_ParseVariant_ +#define IH_ParseVariant_ 1 + +// Custom includes +#include "PacketParser.hh" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { +namespace detail { + + template + struct VariantBytes { + static PacketParserBase::size_type bytes(Variant const & v, unsigned n); + }; + + template + struct VariantBytes { + static PacketParserBase::size_type bytes(Variant const & v, unsigned n); + }; + + template + struct Parse_Variant_Direct + { + typedef PacketParserBase::data_iterator data_iterator; + typedef PacketParserBase::state_type state_type; + typedef PacketParserBase::size_type size_type; + + static size_type const init_bytes = 0; + size_type bytes(data_iterator i, state_type s) const { return 0; } + data_iterator begin(data_iterator i, state_type s) const { return i; } + + ChooserType chooser(data_iterator i, state_type s) const { + return ChooserType(boost::prior(i, Distance),s); + } + + unsigned variant(data_iterator i, state_type s) const { + return chooser(i,s).value(); + } + + void variant(unsigned v, data_iterator i, state_type s) { + chooser(i,s).value(v); + } + }; + +}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Packets/ParseVariant.test.cc b/Packets/ParseVariant.test.cc new file mode 100644 index 0000000..feac293 --- /dev/null +++ b/Packets/ParseVariant.test.cc @@ -0,0 +1,144 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ParseVariant.test unit tests */ + +//#include "ParseVariant.test.hh" +//#include "ParseVariant.test.ih" + +// Custom includes +#include "Packets.hh" + +#include +#include + +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +BOOST_AUTO_UNIT_TEST(parseVariant) +{ + typedef senf::Parse_Array<10, senf::Parse_UInt8> Array10; + typedef senf::Parse_Variant_Direct< senf::Parse_UInt8, 1, + senf::VoidPacketParser, + Array10, + senf:: Parse_UInt32 + >::parser Variant; + + unsigned char data[] = { 0x01, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B }; + senf::DataPacket p (senf::DataPacket::create(data)); + { + Variant v ( boost::next(p.data().begin()), & p.data() ); + BOOST_REQUIRE_EQUAL( v.variant(), 1u ); + BOOST_CHECK_EQUAL( senf::bytes(v), 10u ); + BOOST_CHECK_EQUAL_COLLECTIONS( v.get<1>().begin(), v.get<1>().end(), + data+1, data+11 ); + v.init(); + // The container size should not change in this case but now variant should be 0 ... + BOOST_REQUIRE_EQUAL( p.data().size(), 11u ); + BOOST_REQUIRE_EQUAL( v.variant(), 0u ); + BOOST_CHECK_EQUAL( senf::bytes(v), 0u ); + + v.init<2>(); + // v invalidated + } + { + Variant v ( boost::next(p.data().begin()), & p.data() ); + + BOOST_CHECK_EQUAL( p.data()[0], 2u ); + BOOST_REQUIRE_EQUAL( v.variant(), 2u ); + BOOST_CHECK_EQUAL( senf::bytes(v), 4u ); + + unsigned char data2[] = { 0x02, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B }; + BOOST_CHECK_EQUAL_COLLECTIONS( p.data().begin(), p.data().end(), + data2, data2+sizeof(data2) ); + BOOST_CHECK_EQUAL( v.get<2>().value(), 0u ); + BOOST_CHECK_EQUAL( p.data().size(), 15u ); + p.data()[4] = 0x01u; + BOOST_CHECK_EQUAL( v.get<2>().value(), 1u ); + }; +} + +namespace { + + struct SubParser : public senf::PacketParserBase + { +# include SENF_FIXED_PARSER() + + SENF_PARSER_FIELD( foo, senf::Parse_UInt32 ); + SENF_PARSER_FIELD( bar, senf::Parse_Int16 ); + + SENF_PARSER_FINALIZE(SubParser); + }; + + struct TestParser : public senf::PacketParserBase + { +# include SENF_PARSER() + + SENF_PARSER_SKIP_BITS( 4 ); + SENF_PARSER_PRIVATE_BITFIELD( type_, 4, unsigned ); + SENF_PARSER_PRIVATE_VARIANT( content_, type_, (senf::VoidPacketParser)(SubParser) ); + + bool hasContent() const { return content_().variant() == 1; } + void hasContent(bool v) const { if (v) content_().init<1>(); else content_().init<0>(); } + SubParser content() const { return content_().get<1>(); } + + SENF_PARSER_FINALIZE(TestParser); + }; + +} + +BOOST_AUTO_UNIT_TEST(parseVariantMacro) +{ + senf::DataPacket p (senf::DataPacket::create(senf::init_bytes::value)); + + { + TestParser v (p.data().begin(), & p.data()); + + BOOST_CHECK( ! v.hasContent() ); + BOOST_CHECK_EQUAL( senf::bytes(v), 1u ); + v.hasContent(true); + } + { + TestParser v (p.data().begin(), & p.data()); + BOOST_CHECK( v.hasContent() ); + BOOST_CHECK_EQUAL( senf::bytes(v), 7u ); + BOOST_CHECK_EQUAL( v.content().foo(), 0u ); + } +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Packets/ParseVec.dox b/Packets/ParseVec.dox new file mode 100644 index 0000000..f496f36 --- /dev/null +++ b/Packets/ParseVec.dox @@ -0,0 +1,94 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +namespace senf { + + /** \brief Example vector sizer. ONLY FOR EXPOSITION + + This class shows the interface which must be implemented by a vector sizer policy. It is not + a vector sizer, it is only a declaration of the interface: + \code + struct ExampleVectorPolicy + { + // optional typedefs used to simplify all other declarations + typedef PacketParserBase::size_type size_type; + typedef PacketParserBase::data_iterator iterator; + typedef PacketParserBase::state_type state_type; + + // mandatory members + static const size_type init_bytes = 0; + size_type size (iterator i, state_type s) const; + void size (iterator i, state_type s, size_type v) const; + iterator begin (iterator i, state_type s) const; + size_type bytes (iterator i, state_type s) const; + void init (iterator i, state_type s) const; + }; + \endcode + + A sizer may if needed define additional data members. + */ + struct ExampleVectorPolicy + { + typedef PacketParserBase::size_type size_type; + typedef PacketParserBase::data_iterator iterator; + typedef PacketParserBase::state_type state_type; + + static const size_type init_bytes = 0; ///< Size of a new vector of this size + /**< Initial size which needs to be allocated to this type + of list */ + + size_type size (iterator i, state_type s) const; ///< Get current vector size + /**< Return the current number of elements in the + vector. */ + void size (iterator i, state_type s, size_type v) const; ///< Change vector size + /**< Set the size of the vector to \a v. */ + iterator begin (iterator i, state_type s) const; + ///< Return data_iterator to first element + /**< The returned data_iterator must point to the beginning + of the first vector element. The last iterator can than + automatically be calculated from the fixed element size + and the number of vector elements. */ + size_type bytes (iterator i, state_type s) const; ///< Bytes taken by the vector size + /**< Return the additional size which needs to be added to + the size of the vector data (calculated form \c size() + * ElementType::fixed_bytes) to get the size of + the complete vector. This may be zero if the size is + not considered part of the vector. */ + void init (iterator i, state_type s) const; ///< Initialize new vector + /** Called to initialize a new vector after allocating + init_bytes number of bytes for the vector. */ + }; + +} + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// mode: flyspell +// mode: auto-fill +// End: diff --git a/Packets/ParseVec.hh b/Packets/ParseVec.hh index ded220a..beb953f 100644 --- a/Packets/ParseVec.hh +++ b/Packets/ParseVec.hh @@ -137,59 +137,21 @@ namespace senf { detail::Parse_VectorN_Sizer > parser; }; - /** \brief Example vector sizer. ONLY FOR EXPOSITION - - This class shows the interface which must be implemented by a vector sizer policy. It is not - a vector sizer, it is only a declaration of the interface: - \code - struct ExampleVectorPolicy - { - // optional typedefs used to simplify all other declarations - typedef PacketParserBase::size_type size_type; - typedef PacketParserBase::data_iterator iterator; - typedef PacketParserBase::state_type state_type; - - // mandatory members - static const size_type init_bytes = 0; - size_type size (iterator i, state_type s) const; - void size (iterator i, state_type s, size_type v) const; - iterator begin (iterator i, state_type s) const; - size_type bytes (iterator i, state_type s) const; - void init (iterator i, state_type s) const; - }; - \endcode - - A sizer may if needed define additional data members. + /** \brief Define Parse_VectorN field + + This macro is a special helper to define a senf::Parse_VectorN type field, a vector of + elements of type \a elt_type (a parser) directly preceded by a numeric size field of type \a + size_type (another parser). + + \param[in] name field name + \param[in] elt_type vector element type + \param[in] size_type size type + \hideinitializer + \ingroup packetparsermacros */ - struct ExampleVectorPolicy - { - typedef PacketParserBase::size_type size_type; - typedef PacketParserBase::data_iterator iterator; - typedef PacketParserBase::state_type state_type; - - static const size_type init_bytes = 0; ///< Size of a new vector of this size - /**< Initial size which needs to be allocated to this type - of list */ - - size_type size (iterator i, state_type s) const; ///< Get current vector size - /**< Return the current number of elements in the - vector. */ - void size (iterator i, state_type s, size_type v) const; ///< Change vector size - /**< Set the size of the vector to \a v. */ - iterator begin (iterator i, state_type s) const; - ///< Return data_iterator to first element - /**< The returned data_iterator must point to the beginning - of the first vector element. The last iterator can than - automatically be calculated from the fixed element size - and the number of vector elements. */ - size_type bytes (iterator i, state_type s) const; ///< Size of vector parser - /**< Return the size of the complete vector in bytes. This - is not necessarily the same as \c size() * \e - fixed_element_bytes. */ - void init (iterator i, state_type s) const; ///< Initialize new vector - /** Called to initialize a new vector after allocating - init_bytes number of bytes for the vector. */ - }; +# define SENF_PARSER_VEC_N(name, elt_type, size_type) \ + typedef senf::Parse_VectorN::parser BOOST_PP_CAT(name, _vec_t); \ + SENF_PARSER_FIELD( name, BOOST_PP_CAT(name, _vec_t) ) /** \brief Parse_Vector container wrapper