Modules | |
Policy Implementation classes | |
Macros | |
#define | SENF_SOCKET_POLICIES |
List all policy axis. More... | |
Typedefs | |
typedef AddressingPolicyBase | senf::UnspecifiedAddressingPolicy |
Alias of AddressingPolicyBase for better readability. More... | |
The policy framework conceptually implements a list of parallel inheritance hierarchies each covering a specific interface aspect of the socket handle. The socket handle itself only provides minimal functionality. All further functionality is relayed to a policy class, or more precisely, to a group of policy classes, one for each policy axis. The policy axis are <dl><dt><em>addressingPolicy</em></dt><dd>configures, whether a socket is addressable and if so, configures the address type</dd> <dt><em>framingPolicy</em></dt> <dd>configures the type of framing the socket provides: either no framing providing a simple i/o stream or packet framing</dd> <dt><em>communicationPolicy</em></dt><dd>configures,if and how the communication partner is selected</dd> <dt><em>readPolicy</em></dt><dd>configures the readability of the socket</dd> <dt><em>writePolicy</em></dt><dd>configures the writability of the socket</dd></dl> The template senf::SocketPolicy combines these policy axis to form a concrete socket policy. In a concrete policy, each of these policy axis is assigned a value, the policy value. This value is identified by a class type, a policy class. E.g. possible values for <em>framingPolicy</em> are <tt>DatagramFramingPolicy</tt> or <tt>StreamFramingPolicy</tt> which are classes derived from the axis base class <tt>FramingPolicyBase</tt>. This base class also doubles as <tt>UnspecifiedFramingPolicy</tt> (which is just a typedef alias). If a policy axis is assigned this Unspecified type, the axis is left unspecified, the concrete policy will be incomplete. The senf::SocketPolicy template defines the behavior of a socket handle. The socket handle instances do not implement any socket functionality themselves instead deferring the implementation to the policy classes. The SocketHandle interface is therefore \e not implemented using virtual members, all important socket functions can be inlined by the compiler to create highly efficient code. A senf::SocketPolicy instance can be incomplete. In this case it does \e not completely specify the socket interface, it leaves some aspects open by assigning the Unspecified value to one or more of the policy axis. A senf::SocketHandle based on such a policy will have a reduced interface: It will only support those members for which the corresponding policies are defined. To build a senf::SocketPolicy instance the senf::MakeSocketPolicy helper is provided. This helper template takes any number (it is really limited to 6 Arguments but more arguments don't make sense) of policy classes as it's argument. The MakeSocketPolicy helper will take the arguments in the order they are specified and for each argument will check to which axis the policy class belongs (by checking the base classes of that class) and assign it to the correct policy axis in the senf::SocketPolicy template. If any policy axis are not specified, they are defaulted to their corresponding Unspecified value. This helper frees you to specify the policy classes in any order. An additional feature is, that you may specify a complete policy as a first argument. This policy will then be used to provide default values for unspecified axis. Two senf::SocketHandle's with different policies can be \e compatible. If they are, the more specific SocketHandle can be converted (assigned to) the more basic SocketHandle. A SocketHandle is more specific then another SocketHandle if the policy of the former is more specific then that of the latter which means, that for each policy axis separately, the value of that axis of the more specific policy is derived from or the same as the value of that axis in the more basic policy. This is like converting a derived class pointer to a base class pointer, only it happens separately but at the same time for each policy axis:
In the following discussion, deeper insight into C++ and especially the concepts of template meta-programming are needed. However, this information is only needed if you want to write new policy classes or want to use the policy framework explicitly for your own involved optimizations ... or if you are just plain curious :-) In the following discussion we will use the following conventions: \li \e Axis is one or \c AddressingPolicy, \c FramingPolicy, \c CommunicationPolicy, \c ReadPolicy or \c WritePolicy \li \e socketPolicy is any socket policy (that is, an instantiation of the SocketPolicy template) \li \e trait is an any policy class (that is, any class derived from one of the axis base classes) Each axis is comprised of a number of classes and templates (all in namespace senf of course): <dl><dt>\e Axis \c Base (ex: AddressingPolicyBase)</dt><dd>Baseclass of all policies in this axis</dd> <dt>\c Unspecified \e Axis (ex: \ref UnspecifiedAddressingPolicy)</dt> <dd>An alias (typedef) for \e Axis \c Base</dd> <dt>\e Axis \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)</dt> <dd>A template metafunction returning \c boost::true_type, if \e trait (any class derived from \e Axis \c Base) is a compatible policy value of the given \e socketPolicy</dd> <dt>\c If \e Axis \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)</dt> <dd>This is a combination of \e Axis \c Is and \c boost::enable_if</dd> <dt>\c If \e Axis \c IsNot < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIsNot)</dt> <dd>The inverse of above</dd> </dl> These classes form the basis of the policy framework. To bind the policy axis together, there are some more classes and templates. <dl><dt>\c class \c SocketPolicyBase</dt> <dd>This class is the base class of the SocketPolicy template. It is used to validate, that a class is really a SocketPolicy (by checking, that it derives from SocketPolicyBase. This is simpler than checking the template directly).</dd> <dt>\c template \c SocketPolicy < \e addressingPolicy, \e framingPolicy, \e communicationPolicy, \e readPolicy, \e writePolicy ></dt> <dd>This is the central SocketPolicy template. It combines a complete set of policy classes, one for each axis.</dd> <dt>\c template \c MakeSocketPolicy < \e args ></dt> <dd>\c MakeSocketPolicy is a template metafunction which simplifies building SocketPolicy instantiations. It takes any number (ok, up to a maximum of 6) of policy classes as an argument (in any order). It will sort these arguments into the SocketPolicy template arguments. If for some axis no class is specified, it's slot will be filled with \c Unspecified \e Axis. Additionally, the first Argument may optionally be an arbitrary SocketPolicy. It will provide default values for unspecified axis</dd> <dt>\c template \c SocketPolicyIsBaseOf < \e base, \e derived ></dt> <dd>This template metafunction will check, whether the socket policy \e derived is convertible to \e base. This means, that for each axis, the corresponding policy class in \e derived must be derived or be the same as the one on \e base.</dd> </dl> \par "Implementation note:" All these classes are created automatically. The \c SENF_SOCKET_POLICIES macro is a Boost.Preprocessor style sequence listing all policy axis. The Boost.Preprocessor library is then used to generate the respective classes.
To define a new policy class, derive from the corresponding base class for your policy axes. The only policy axis which might possibly need to be extended is the addressing policy (AddressingPolicyBase). See the Documentation of these classes for more information on which members can be implemented. All members you define must be static. For any of the policy classes, you must only define those members which are supported by your implementation. If you leave out a member you automatically disable the corresponding functionality in the ClientSocketHandle/ServerSocketHandle interface. The member prototypes given in the base class documentation only specify the call signature not the way, the member must be defined (FileHandle really is not a FileHandle but an arbitrary SocketHandle). If the existence of a member depends on other policies, you should use the <code>If</code><i>SomePolicy</i><code>Is</code> and <code>If</code><i>SomePolicy</i><code>IsNot</code> templates to dynamically enable/disable the member depending on some other policy:
The \c connect member in this example will only be enabled, it the communication policy of the socket handle is ConnectedCommunicationPolicy (or a derived type). See <a href="http://www.boost.org/doc/libs/release/libs/utility/enable_if.html">Boost.Enable_If</a> for a discussion of the third argument (\c senf::ConnectedCommunicationPolicyIs is based on the \c boost::enable_if template). \see \ref extend_policy \n <a href="http://www.boost.org/doc/libs/release/libs/utility/enable_if.html">The Boost enable_if utility</a> \n <a href="http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html">The Boost.MPL library</a> \n <a href="http://www.boost.org/doc/libs/release/libs/preprocessor/doc/index.html">The Boost.Preprocessor library</a>
Is
templates into a single template. Since the trait argument will automatically specify the axis to be used, it is not necessary to specify that axis in the template functor's name. We could even combine this with SocketPolicyIsBaseOf
. #define SENF_SOCKET_POLICIES |
List all policy axis.
This define symbol is used to configure the policy axis. The base class for each of these axis must be defined explicitly (e.g. AddressingPolicyBase). The implementation files will then automatically generate all the other classes from this list.
Definition at line 247 of file SocketPolicy.hh.
Alias of AddressingPolicyBase for better readability.
Definition at line 403 of file SocketPolicy.hh.